Flex (Fast Lexical Analyzer Generator) and Bison (parser generator) are being used to parse C+- toy language source file .cpm
and create abstract syntax tree (AST). Then corresponding C++ file .cpp
is generated and compiled into executable.
- C+- consists only of
- Variables
var a;
and constantsval b;
- Numeric and string literals (
43
,12.3
,"my string"
, etc) - Addition, subtraction and assignment operators
+
,-
,=
- Output function
print()
- Input function
input()
- Single line and multi-line comments (wasn't specified in the task)
- Variables
- There are only 3 types of values
- Int - 8 byte
- String - sequence of characters
- Float - 8 byte
- C+- is an implicit dynamic typization language
- Same variable can store numbers and strings, the following is correct
var a = 5.5; a = "Hello"; a = 34.5;
- Operators follow rules (order of arguments doesn't matter)
- String + Int/Float: Numeric is converted to string
- String - Int/Float: String is converted to Int/Float, if it's not possible String value considered to be
0
- Int/Float + Int/Float: Integer is converted to Float if necessary
- Same variable can store numbers and strings, the following is correct
- Code example
Output
var str = "Hello"; // variable declared using var str = str + "1"; // variables can be changed print(str); // print function takes only one argument str = 21 + 2 + 18; // same variable can store numbers print(str); // -> 41 val worldString = "World"; // constant declared using val val answerNumber = 42; print(worldString + answerNumber); // -> World42 print(worldString - answerNumber); // -> -42 val pi = 3.14; print(pi + answerNumber); // -> 45.14 val numberString = "134"; print(numberString + answerNumber); // -> 92 print(numberString - answerNumber); // -> 13442 val name = input("Name: "); // prints "Name: " and waits for input print("Your name is " + name);
Hello1 41 World42 -42 45.14 92 13442 Name: Vladimir Your name is Vladimir
Ubuntu
>= 18g++
>= 9.3.0
Download cpm_compiler.zip
archive. Files inside:
c+-
- compiler from .cpm source to .out executablemixed.h
- mixed type declaration headerlibmixed.a
- mixed methods definition static library
To use the compiler specify the path to source .cpm file and (optionally) destination directory. Note that header and library files are required to be in the same location as compiler. Created directory contains both transpiled a.cpp
and compiled a.out
files.
$ cpm_compiler/c+- --help
Usage: cpm_compiler/c+- FILE [DIRECTORY]
Options:
-h, --help Show this help message
Specify the path to .cpm source FILE to create DIRECTORY with a.cpp and a.out files. Directory is "./out" by default.
$ pwd
/home/vladimir/projects/cpm_compiler
$ cpm_compiler/c+- examples/perimeter.cpm
cpm_compiler/out/a.out successfully compiled
cpm_compiler/out successfully moved to .
$ out/a.out
Calculating perimeter of rectangle
Enter length of one side: 5.5
Enter length of another side: 123.4
Perimeter: 5.55.5123.4123.4
Oops... strings concatenated
Let's try another time!
Perimeter: 257.8
print("Calculating perimeter of rectangle");
val a = input("Enter length of one side: ");
val b = input("Enter length of another side: ");
var answer = a + a + b + b;
print("Perimeter: " + answer);
print("Oops... strings concatenated");
val a_numeric = a - 0;
val b_numeric = b - 0;
answer = a_numeric + a_numeric + b_numeric + b_numeric;
print("Let's try another time!");
print("Perimeter: " + answer);
#include "../mixed.h"
int main() {
print(Mixed("Calculating perimeter of rectangle"));
const Mixed a = input(Mixed("Enter length of one side: "));
const Mixed b = input(Mixed("Enter length of another side: "));
Mixed answer = a + a + b + b;
print(Mixed("Perimeter: ") + answer);
print(Mixed("Oops... strings concatenated"));
const Mixed a_numeric = a - Mixed(0);
const Mixed b_numeric = b - Mixed(0);
answer = a_numeric + a_numeric + b_numeric + b_numeric;
print(Mixed("Let's try another time!"));
print(Mixed("Perimeter: ") + answer);
return 0;
}
$ pwd
/home/vladimir/projects/cpm_compiler
$ cpm_compiler/c+- examples/errors.cpm
Compilation failed
Command(s) with errors: 4
Redeclaration(s) of constant: 1
Redeclaration(s) of variable: 0
Usage(s) of undefined identifier: 2
Redifinition(s) of constant: 1
Makefile can be used to do the following:
$ make
create cpm_compiler directory and its files$ make run
compile example and run produced executable, change$(example)
variale inMakefile
to try another example$ make rerun
deleteout
directory and then executemake run
$ make pack
makecpm_compiler.zip
archive with compiler files$ make clean
delete all files except sources. Note that you'll need to generate parser files again usingflex
>= 2.6.4 andbison
>= 3.5.1