diff --git a/lab-4/README.md b/lab-4/README.md
index e814109..b2d23a0 100644
--- a/lab-4/README.md
+++ b/lab-4/README.md
@@ -21,7 +21,6 @@ bison --defines=token.h --output=parser.c -v parser.bison
THe `-v` flag will create a `parser.output` which represents the grammar in text form.
-
### Running the Parser
Then build the `main.c`, `parcer.c` and `scanner.c` using **gcc**.
@@ -38,7 +37,6 @@ For example here is a command for `samples/program.c`
./parser.out < samples/program.c
```
-
### Testing the Parser
Then build the `main_test.c`, `parcer.c` and `scanner.c` using **gcc**.
@@ -54,43 +52,41 @@ Then execute the test suite using `./parser_test.out`.
./parser_test.out
```
-
### Using Make
Alternatively you can use the supplied make file.
-* Build main program - `make`
-* Build test program - `make test`
-* Clean up build files - `make clean`
-
+- Build main program - `make`
+- Build test program - `make test`
+- Clean up build files - `make clean`
## Tests
-* Write test for various statements in your language
- * assignment
- * print
- * mathmatical expressions
- * boolean expressions
- * branching
- * looping
-* Write a test for each sample test file.
- * Hello World!
- * Quadratic
- * Sorting
-
+- Write test for various statements in your language
+ - assignment - Riley
+ - print - Josh (write test)
+ - mathmatical expressions - Jenessy
+ - boolean expressions - Jenessy
+ - branching - Josh
+ - looping - Riley
+- Write a test for each sample test file.
+ - Hello World! - Josh (already done)
+ - Quadratic - Jenessy
+ - Sorting - Riley
## Grading Rubric
The grading will be over the following categories.
-Points Description
------------ ------------------------------------
-60 points Ability to parse — Six different language statements
-10 points Ability to parse — Hello world
-10 points Ability to parse — Quadratic equation
-10 points Ability to parse — Integer sorting
-10 points Report formatting and readability
+Points Description
+---
+
+60 points Ability to parse — Six different language statements
+10 points Ability to parse — Hello world
+10 points Ability to parse — Quadratic equation
+10 points Ability to parse — Integer sorting
+10 points Report formatting and readability
## Turn In
diff --git a/lab-4/main_test.c b/lab-4/main_test.c
index 0e80882..057bed9 100644
--- a/lab-4/main_test.c
+++ b/lab-4/main_test.c
@@ -43,9 +43,9 @@ UTEST(parser, missing_semi_colon) {
ASSERT_EQ(result, 1);
}
-UTEST(parser, sample) {
+UTEST(parser, hello) {
// Read sample file as input
- yyin = fopen("samples/program.c", "r");
+ yyin = fopen("samples/hello-world.cbl", "r");
yyrestart(yyin);
ASSERT_TRUE(yyin);
@@ -55,3 +55,31 @@ UTEST(parser, sample) {
// Assert the result to test correctness
ASSERT_EQ(result, 0);
}
+
+UTEST(parser, print) {
+ // Must include the null character to terminate input
+ char string[] = "DISPLAY 'Hello World!'\0";
+ YY_BUFFER_STATE buffer = yy_scan_buffer(string, sizeof(string));
+
+ yylineno = 1;
+ int result = yyparse();
+
+ yy_delete_buffer(buffer);
+
+ // Assert the result to test correctness
+ ASSERT_EQ(result, 0);
+}
+
+UTEST(parser, branching) {
+ // Must include the null character to terminate input
+ char string[] = "IF A > B THEN DISPLAY 'A is greater than B' ELSE DISPLAY 'B is greater than A'\0";
+ YY_BUFFER_STATE buffer = yy_scan_buffer(string, sizeof(string));
+
+ yylineno = 1;
+ int result = yyparse();
+
+ yy_delete_buffer(buffer);
+
+ // Assert the result to test correctness
+ ASSERT_EQ(result, 0);
+}
\ No newline at end of file
diff --git a/lab-4/parser.bison b/lab-4/parser.bison
index ddbc8b4..e4c4b6f 100644
--- a/lab-4/parser.bison
+++ b/lab-4/parser.bison
@@ -77,6 +77,7 @@ sect_data : TOKEN_PROGRAM_ID TOKEN_DOT TOKEN_IDENT TOKEN_DOT
type : TOKEN_IDENTIFICATION
| TOKEN_PROCEDURE
| TOKEN_STOP
+ | TOKEN_KEYWORD_DATA
;
simple_stmt : function
;
diff --git a/lab-4/token.h b/lab-4/token.h
new file mode 100644
index 0000000..fc7b161
--- /dev/null
+++ b/lab-4/token.h
@@ -0,0 +1,125 @@
+/* A Bison parser, made by GNU Bison 3.8.2. */
+
+/* Bison interface for Yacc-like parsers in C
+
+ Copyright (C) 1984, 1989-1990, 2000-2015, 2018-2021 Free Software Foundation,
+ Inc.
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see . */
+
+/* As a special exception, you may create a larger work that contains
+ part or all of the Bison parser skeleton and distribute that work
+ under terms of your choice, so long as that work isn't itself a
+ parser generator using the skeleton or a modified version thereof
+ as a parser skeleton. Alternatively, if you modify or redistribute
+ the parser skeleton itself, you may (at your option) remove this
+ special exception, which will cause the skeleton and the resulting
+ Bison output files to be licensed under the GNU General Public
+ License without this special exception.
+
+ This special exception was added by the Free Software Foundation in
+ version 2.2 of Bison. */
+
+/* DO NOT RELY ON FEATURES THAT ARE NOT DOCUMENTED in the manual,
+ especially those whose name start with YY_ or yy_. They are
+ private implementation details that can be changed or removed. */
+
+#ifndef YY_YY_TOKEN_H_INCLUDED
+# define YY_YY_TOKEN_H_INCLUDED
+/* Debug traces. */
+#ifndef YYDEBUG
+# define YYDEBUG 1
+#endif
+#if YYDEBUG
+extern int yydebug;
+#endif
+
+/* Token kinds. */
+#ifndef YYTOKENTYPE
+# define YYTOKENTYPE
+ enum yytokentype
+ {
+ YYEMPTY = -2,
+ YYEOF = 0, /* "end of file" */
+ YYerror = 256, /* error */
+ YYUNDEF = 257, /* "invalid token" */
+ TOKEN_EOF = 258, /* TOKEN_EOF */
+ TOKEN_IDENTIFICATION = 259, /* TOKEN_IDENTIFICATION */
+ TOKEN_KEYWORD_DIVISION = 260, /* TOKEN_KEYWORD_DIVISION */
+ TOKEN_KEYWORD_DATA = 261, /* TOKEN_KEYWORD_DATA */
+ TOKEN_KEYWORD_SECTION = 262, /* TOKEN_KEYWORD_SECTION */
+ TOKEN_PROGRAM_ID = 263, /* TOKEN_PROGRAM_ID */
+ TOKEN_WORKING_STORAGE = 264, /* TOKEN_WORKING_STORAGE */
+ TOKEN_PROCEDURE = 265, /* TOKEN_PROCEDURE */
+ TOKEN_STOP = 266, /* TOKEN_STOP */
+ TOKEN_RUN = 267, /* TOKEN_RUN */
+ TOKEN_MOVE = 268, /* TOKEN_MOVE */
+ TOKEN_KEYWORD_TO = 269, /* TOKEN_KEYWORD_TO */
+ TOKEN_PERFORM = 270, /* TOKEN_PERFORM */
+ TOKEN_VARYING = 271, /* TOKEN_VARYING */
+ TOKEN_KEYWORD_FROM = 272, /* TOKEN_KEYWORD_FROM */
+ TOKEN_KEYWORD_BY = 273, /* TOKEN_KEYWORD_BY */
+ TOKEN_UNTIL = 274, /* TOKEN_UNTIL */
+ TOKEN_END_PERFORM = 275, /* TOKEN_END_PERFORM */
+ TOKEN_IF = 276, /* TOKEN_IF */
+ TOKEN_END_IF = 277, /* TOKEN_END_IF */
+ TOKEN_SPACE = 278, /* TOKEN_SPACE */
+ TOKEN_KEYWORD_OCCURS = 279, /* TOKEN_KEYWORD_OCCURS */
+ TOKEN_KEYWORD_VALUE = 280, /* TOKEN_KEYWORD_VALUE */
+ TOKEN_KEYWORD_COMPUTE = 281, /* TOKEN_KEYWORD_COMPUTE */
+ TOKEN_KEYWORD_FUNCTION = 282, /* TOKEN_KEYWORD_FUNCTION */
+ TOKEN_IDENT = 283, /* TOKEN_IDENT */
+ TOKEN_STRING = 284, /* TOKEN_STRING */
+ TOKEN_INTEGER = 285, /* TOKEN_INTEGER */
+ TOKEN_PICTURE = 286, /* TOKEN_PICTURE */
+ TOKEN_ALPHANUMERIC = 287, /* TOKEN_ALPHANUMERIC */
+ TOKEN_NUMERIC = 288, /* TOKEN_NUMERIC */
+ TOKEN_SIGNED_NUMERIC = 289, /* TOKEN_SIGNED_NUMERIC */
+ TOKEN_IMPLIED_DECIMAL = 290, /* TOKEN_IMPLIED_DECIMAL */
+ TOKEN_COMPUTATION_LEVEL_0 = 291, /* TOKEN_COMPUTATION_LEVEL_0 */
+ TOKEN_COMPUTATION_LEVEL_1 = 292, /* TOKEN_COMPUTATION_LEVEL_1 */
+ TOKEN_COMPUTATION_LEVEL_2 = 293, /* TOKEN_COMPUTATION_LEVEL_2 */
+ TOKEN_COMPUTATION_LEVEL_3 = 294, /* TOKEN_COMPUTATION_LEVEL_3 */
+ TOKEN_LEFT_PARENTHESIS = 295, /* TOKEN_LEFT_PARENTHESIS */
+ TOKEN_RIGHT_PARENTHESIS = 296, /* TOKEN_RIGHT_PARENTHESIS */
+ TOKEN_DOT = 297, /* TOKEN_DOT */
+ TOKEN_COMMENT = 298, /* TOKEN_COMMENT */
+ TOKEN_ADD = 299, /* TOKEN_ADD */
+ TOKEN_SUB = 300, /* TOKEN_SUB */
+ TOKEN_MULTIPLY = 301, /* TOKEN_MULTIPLY */
+ TOKEN_DIVIDE = 302, /* TOKEN_DIVIDE */
+ TOKEN_EQUAL = 303, /* TOKEN_EQUAL */
+ TOKEN_GREATER_THAN = 304, /* TOKEN_GREATER_THAN */
+ TOKEN_LESS_THAN = 305, /* TOKEN_LESS_THAN */
+ TOKEN_EXPONENTIAL = 306, /* TOKEN_EXPONENTIAL */
+ TOKEN_DISPLAY = 307 /* TOKEN_DISPLAY */
+ };
+ typedef enum yytokentype yytoken_kind_t;
+#endif
+
+/* Value type. */
+#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
+typedef int YYSTYPE;
+# define YYSTYPE_IS_TRIVIAL 1
+# define YYSTYPE_IS_DECLARED 1
+#endif
+
+
+extern YYSTYPE yylval;
+
+
+int yyparse (void);
+
+
+#endif /* !YY_YY_TOKEN_H_INCLUDED */
diff --git a/lab-5/Makefile b/lab-5/Makefile
new file mode 100644
index 0000000..fd9e075
--- /dev/null
+++ b/lab-5/Makefile
@@ -0,0 +1,26 @@
+
+# The top level rule indicates how to link everything together into calc
+
+main: main.o symbol_map.o expr.o scanner.o parser.o
+ gcc main.o symbol_map.o expr.o scanner.o parser.o -o interpreter.out -lm
+
+# This pattern indicates that any .o file depends
+# upon the .c file of the same name, and all of the .h files.
+# So, if a .o file is needed, it is built automatically.
+
+%.o: %.c *.h
+ gcc -Wall -c $< -o $@
+
+# Only the files generated by flex and bison need explicit rules.
+
+scanner.c: scanner.flex parser.h
+ flex -oscanner.c scanner.flex
+
+parser.c parser.h: parser.bison
+ bison --defines=parser.h --output=parser.c -v parser.bison -Wconflicts-sr -Wcounterexamples
+
+# clean causes all intermediate files to be deleted.
+
+clean:
+ rm -f parser.c parser.output parser.h scanner.c *.o interpreter.out
+
diff --git a/lab-5/README.md b/lab-5/README.md
new file mode 100644
index 0000000..b9e30d0
--- /dev/null
+++ b/lab-5/README.md
@@ -0,0 +1,107 @@
+# Bison Interpreter
+
+Create an interpreter for your sample programs.
+See the [example lab for Python](https://gitlab.cs.wallawalla.edu/cptr354/language-interpreter-lab-python).
+
+In this lab, you will focus on basic operations that support your sample code.
+
+* Arithmetic operations
+ * add
+ * subtract
+ * multiple
+ * divide
+* Functions (but implemented directly in the language)
+ * Printing
+ * Square root
+* Variable for numbers
+* Variable for lists (or arrays)
+* Branching statements
+* Looping statements
+
+Notice you will find a new file `expr.c`.
+The file is used to implement the parser rule.
+Inside these functions, you will create the runtime code that is the interpreter.
+
+
+## Build Process
+
+The process is similar to prior labs.
+To build the `scanner.c` run the following **flex** command.
+
+```sh
+flex -o scanner.c scanner.flex
+```
+
+The parser is built using **bison**.
+Note this command also builds the `token.h`.
+
+```sh
+bison --defines=token.h --output=parser.c parser.bison
+```
+
+Then build the `main.c`, `expr.c`, `parcer.c` and `scanner.c` using **gcc**.
+Note that you may get a few warnings that can be ignored.
+
+```sh
+gcc *.c -o interpreter.out
+```
+
+Then execute the test suite using `./interpreter.out` and pass in the input from your sample program.
+For example here is a command for `samples/program.c`
+
+```sh
+./interpreter.out < samples/program.c
+```
+
+Single line command:
+
+```sh
+flex -o scanner.c scanner.flex && \
+bison --defines=token.h --output=parser.c parser.bison && \
+gcc *.c -o interpreter.out && ./interpreter.out < samples/program.c
+```
+
+## Building with Make
+
+To simplify the process a Makefile has been supplied.
+
+```sh
+make && ./interpreter.out < samples/program.c
+```
+
+To remove the build files, use make clean.
+
+```sh
+make clean
+```
+
+
+## Assignment Steps
+
+1. Start by confirming these commands work for the sample code provided.
+
+1. Next copy over your `scanner.flex`, `parser.bison` and sample programs from lab 5.
+
+1. Start working on your bison `parser.bison` and `expr.c` files to implement the interpreter part of your parser.
+
+
+## Grading Rubric
+
+The grading will be over the following categories.
+
+Points Description
+----------- ------------------------------------
+30 points Ability to interpret — Hello world
+30 points Ability to interpret — Quadratic equation
+30 points Ability to interpret — Arithmetic operations
+30 points Ability to interpret — Integer Sort example
+20 points Ability to interpret — Looping operations
+20 points Ability to interpret — Branching operations
+20 points Ability to interpret — Array variables
+10 points Report formatting and readability
+
+
+## Turn In
+
+Please submit the URL of your GitLab project to D2L's Brightspace with your report.
+On GitLab update the `lab-5` folder to have your report and code snippets before the due date.
diff --git a/lab-5/expr.c b/lab-5/expr.c
new file mode 100644
index 0000000..6b0e94d
--- /dev/null
+++ b/lab-5/expr.c
@@ -0,0 +1,457 @@
+
+#include "expr.h"
+
+#include
+#include
+#include
+
+static struct SymbolMap *symbol_table = NULL;
+
+/*
+Create one node in an expression tree and return the structure.
+*/
+
+struct type *type_create(type_t kind, struct type *sub) {
+ struct type *t = malloc(sizeof(*t));
+ t->kind = kind;
+ t->subtype = sub;
+ return t;
+}
+
+struct decl *decl_create(struct expr *name, struct type *type,
+ struct expr *value, struct stmt *code,
+ struct decl *next) {
+ struct decl *d = malloc(sizeof(*d));
+ d->name = name;
+ d->type = type;
+ d->value = value;
+ d->code = code;
+ d->next = next;
+ return d;
+}
+
+struct stmt *stmt_create(stmt_t kind, struct decl *decl, struct expr *init_expr,
+ struct expr *expr, struct expr *next_expr,
+ struct stmt *body, struct stmt *else_body,
+ struct stmt *next) {
+ struct stmt *s = malloc(sizeof(*s));
+
+ s->kind = kind;
+ s->decl = decl;
+ s->init_expr = init_expr;
+ s->expr = expr;
+ s->next_expr = next_expr;
+ s->body = body;
+ s->else_body = else_body;
+ s->next = next;
+
+ return s;
+}
+
+struct expr *expr_create(expr_t kind, struct expr *left, struct expr *right) {
+ /* Shortcut: sizeof(*e) means "the size of what e points to" */
+ struct expr *e = malloc(sizeof(*e));
+
+ e->kind = kind;
+ e->left = left;
+ e->right = right;
+ e->name = "";
+ e->integer_value = 0;
+ e->float_value = 0.0;
+ e->string_literal = "";
+
+ return e;
+}
+
+struct expr *expr_create_name(const char *value) {
+ struct expr *e = expr_create(EXPR_NAME, 0, 0);
+ char *dest = malloc(sizeof(*value));
+ strcpy(dest, value); // copy contents of source to dest
+ e->name = dest;
+ return e;
+}
+
+struct expr *expr_create_integer_literal(int value) {
+ struct expr *e = expr_create(EXPR_INTEGER_LITERAL, 0, 0);
+ e->integer_value = value;
+ return e;
+}
+
+struct expr *expr_create_float_literal(float value) {
+ struct expr *e = expr_create(EXPR_FLOAT_LITERAL, 0, 0);
+ e->float_value = value;
+ return e;
+}
+
+struct expr *expr_create_string_literal(const char *value) {
+ struct expr *e = expr_create(EXPR_STRING_LITERAL, 0, 0);
+ e->string_literal = value;
+ return e;
+}
+
+/*
+Recursively delete an expression tree.
+*/
+
+void expr_delete(struct expr *e) {
+ /* Careful: Stop on null pointer. */
+ if (!e)
+ return;
+ expr_delete(e->left);
+ expr_delete(e->right);
+ free(e);
+}
+
+void scope_bind(const char *name, struct expr *value) {
+ if (symbol_table == NULL) {
+ symbol_table = createSymbolMap();
+ }
+ insertSymbol(symbol_table, name, value);
+}
+
+struct expr *scope_lookup(const char *name) {
+ return getSymbol(symbol_table, name);
+}
+
+/*
+Recursively print an expression tree by performing an
+in-order traversal of the tree, printing the current node
+between the left and right nodes.
+*/
+
+void stmt_print(struct stmt *s) {
+ if (!s)
+ return;
+
+ switch (s->kind) {
+ case STMT_DECL:
+ decl_print(s->decl);
+ printf(";\n");
+ break;
+ case STMT_EXPR:
+ expr_print(s->expr);
+ break;
+ case STMT_IF:
+ printf("if ");
+ expr_print(s->expr);
+ printf(" then\n");
+ stmt_print(s->body);
+ printf("endif\n");
+ break;
+ case STMT_PRINT:
+ printf("print ");
+ expr_print(s->expr);
+ printf(";\n");
+ break;
+ case STMT_BLOCK:
+ stmt_print(s->body);
+ break;
+ }
+
+ stmt_print(s->next);
+}
+
+void decl_print(struct decl *d) {
+ expr_print(d->name);
+ printf(" = ");
+ expr_print(d->value);
+}
+
+void expr_print(struct expr *e) {
+ /* Careful: Stop on null pointer. */
+ if (!e)
+ return;
+
+ const char *close = "";
+ if (e->kind == EXPR_ARRAY) {
+ printf("[");
+ close = "]";
+ } else if (e->kind != EXPR_NAME && e->kind != EXPR_SUBSCRIPT &&
+ e->kind != EXPR_INTEGER_LITERAL && e->kind != EXPR_FLOAT_LITERAL &&
+ e->kind != EXPR_STRING_LITERAL) {
+ printf("(");
+ close = ")";
+ }
+
+ expr_print(e->left);
+
+ switch (e->kind) {
+ case EXPR_NAME:
+ printf("%s", e->name);
+ break;
+ case EXPR_ARRAY:
+ if (e->right) {
+ printf(", ");
+ }
+ break;
+ case EXPR_SUBSCRIPT:
+ printf("[");
+ close = "]";
+ break;
+ case EXPR_ADD:
+ printf("+");
+ break;
+ case EXPR_SUBTRACT:
+ printf("-");
+ break;
+ case EXPR_MULTIPLY:
+ printf("*");
+ break;
+ case EXPR_DIVIDE:
+ printf("/");
+ break;
+ case EXPR_EQUAL_EQUAL:
+ printf("==");
+ break;
+ case EXPR_NOT_EQUAL:
+ printf("!=");
+ break;
+ case EXPR_GREATER_THAN:
+ printf(">");
+ break;
+ case EXPR_GREATER_THAN_OR_EQUAL:
+ printf(">=");
+ break;
+ case EXPR_LESS_THAN:
+ printf("<");
+ break;
+ case EXPR_LESS_THAN_OR_EQUAL:
+ printf("<=");
+ break;
+ case EXPR_INTEGER_LITERAL:
+ printf("%d", e->integer_value);
+ break;
+ case EXPR_FLOAT_LITERAL:
+ printf("%f", e->float_value);
+ break;
+ case EXPR_STRING_LITERAL:
+ printf("%s", e->string_literal);
+ break;
+ }
+
+ expr_print(e->right);
+
+ // Options for closing
+ printf("%s", close);
+}
+
+/*
+Recursively evaluate an expression by performing
+the desired operation and returning it up the tree.
+*/
+
+void stmt_evaluate(struct stmt *s) {
+ if (!s)
+ return;
+
+ switch (s->kind) {
+ case STMT_DECL:
+ decl_evaluate(s->decl);
+ break;
+ case STMT_EXPR:
+ expr_evaluate(s->expr);
+ break;
+ case STMT_IF:
+ if (expr_evaluate(s->expr)) {
+ stmt_evaluate(s->body);
+ }
+ break;
+ case STMT_PRINT:
+ if (s->expr->kind == EXPR_STRING_LITERAL) {
+ printf("%s", expr_string_evaluate(s->expr));
+ } else if (s->expr->kind == EXPR_FLOAT_LITERAL) {
+ printf("%f", expr_evaluate(s->expr));
+ } else if (s->expr->kind == EXPR_INTEGER_LITERAL ||
+ s->expr->kind == EXPR_NAME || s->expr->kind == EXPR_SUBSCRIPT) {
+ printf("%.0f", expr_evaluate(s->expr));
+ } else {
+ printf("runtime error: print expression is not literal\n");
+ }
+ break;
+ case STMT_BLOCK:
+ stmt_evaluate(s->body);
+ break;
+ }
+
+ stmt_evaluate(s->next);
+}
+
+void decl_evaluate(struct decl *d) {
+ if (!d)
+ return;
+
+ if (d->name->kind == EXPR_NAME && d->value->kind == EXPR_ARRAY) {
+ struct expr *e = expr_sub_evaluate(d->value);
+ scope_bind(d->name->name, e);
+ } else if (d->name->kind == EXPR_NAME) {
+ float value = expr_evaluate(d->value);
+ struct expr *e = expr_create_float_literal(value);
+ scope_bind(d->name->name, e);
+ } else if (d->name->kind == EXPR_SUBSCRIPT) {
+ float value = expr_evaluate(d->value);
+ decl_subscript_evaluate(d->name, value);
+ } else {
+ printf("Error: expression type unknown for name");
+ exit(1);
+ }
+}
+
+void decl_subscript_evaluate(struct expr *e, float value) {
+ /* Careful: Return zero on null pointer. */
+ if (!e)
+ return;
+
+ if (e->kind != EXPR_SUBSCRIPT) {
+ printf("runtime error: not a subscript expression\n");
+ exit(1);
+ }
+
+ if (e->left->kind != EXPR_NAME) {
+ printf("runtime error: subscript has no name\n");
+ exit(1);
+ }
+
+ // Get array expresion
+ struct expr *a = scope_lookup(e->left->name);
+ float index = expr_evaluate(e->right);
+
+ // Find the right offset
+ while (index > 0) {
+ a = a->right;
+ index--;
+ }
+ expr_delete(a->left);
+ a->left = expr_create_float_literal(value);
+}
+
+const char *expr_string_evaluate(struct expr *e) {
+ /* Careful: Return zero on null pointer. */
+ if (!e)
+ return 0;
+
+ switch (e->kind) {
+ case EXPR_NAME:
+ case EXPR_ARRAY:
+ case EXPR_SUBSCRIPT:
+ case EXPR_ADD:
+ case EXPR_SUBTRACT:
+ case EXPR_MULTIPLY:
+ case EXPR_DIVIDE:
+ case EXPR_EQUAL_EQUAL:
+ case EXPR_NOT_EQUAL:
+ case EXPR_GREATER_THAN:
+ case EXPR_GREATER_THAN_OR_EQUAL:
+ case EXPR_LESS_THAN:
+ case EXPR_LESS_THAN_OR_EQUAL:
+ case EXPR_INTEGER_LITERAL:
+ case EXPR_FLOAT_LITERAL:
+ printf("runtime error: not a string expression\n");
+ exit(1);
+ case EXPR_STRING_LITERAL:
+ return e->string_literal;
+ }
+
+ return "";
+}
+
+struct expr *expr_sub_evaluate(struct expr *e) {
+ /* Careful: Return zero on null pointer. */
+ if (!e)
+ return 0;
+
+ // TODO evaluate each item in the array and save the result
+
+ return e;
+}
+
+/*
+Recursively evaluate an expression by performing
+the desired operation and returning it up the tree.
+*/
+
+float expr_subscript_evaluate(struct expr *e) {
+ /* Careful: Return zero on null pointer. */
+ if (!e)
+ return 0;
+
+ if (e->kind != EXPR_SUBSCRIPT) {
+ printf("runtime error: not a subscript expression\n");
+ exit(1);
+ }
+
+ if (e->left->kind != EXPR_NAME) {
+ printf("runtime error: subscript has no name\n");
+ exit(1);
+ }
+
+ // Get array expresion
+ struct expr *a = scope_lookup(e->left->name);
+ float index = expr_evaluate(e->right);
+
+ // Find the right offset
+ while (index > 0) {
+ a = a->right;
+ index--;
+ }
+ return expr_evaluate(a->left);
+}
+
+float expr_evaluate(struct expr *e) {
+ /* Careful: Return zero on null pointer. */
+ if (!e)
+ return 0;
+
+ if (e->kind == EXPR_SUBSCRIPT)
+ return expr_subscript_evaluate(e);
+
+ float l = expr_evaluate(e->left);
+ float r = expr_evaluate(e->right);
+
+ switch (e->kind) {
+ case EXPR_NAME:
+ // Get the variable expression and then evaluate it.
+ return expr_evaluate(scope_lookup(e->name));
+ case EXPR_ARRAY:
+ printf("runtime error: array in expression\n");
+ exit(1);
+ case EXPR_SUBSCRIPT:
+ printf(
+ "runtime error: subscript should be processed earlier in expression\n");
+ exit(1);
+ case EXPR_ADD:
+ return l + r;
+ case EXPR_SUBTRACT:
+ return l - r;
+ case EXPR_MULTIPLY:
+ return l * r;
+ case EXPR_DIVIDE:
+ if (r == 0) {
+ printf("runtime error: divide by zero\n");
+ exit(1);
+ }
+ return l / r;
+ case EXPR_EQUAL_EQUAL:
+ return l == r;
+ case EXPR_NOT_EQUAL:
+ return l != r;
+ case EXPR_GREATER_THAN:
+ return l > r;
+ case EXPR_GREATER_THAN_OR_EQUAL:
+ return l >= r;
+ case EXPR_LESS_THAN:
+ return l < r;
+ case EXPR_LESS_THAN_OR_EQUAL:
+ return l <= r;
+ case EXPR_INTEGER_LITERAL:
+ return e->integer_value;
+ case EXPR_FLOAT_LITERAL:
+ return e->float_value;
+ case EXPR_STRING_LITERAL:
+ printf("runtime error: string in expression\n");
+ exit(1);
+ }
+
+ return 0;
+}
+
+void close_parser() { destroySymbolMap(symbol_table); }
diff --git a/lab-5/expr.h b/lab-5/expr.h
new file mode 100644
index 0000000..99d8461
--- /dev/null
+++ b/lab-5/expr.h
@@ -0,0 +1,108 @@
+/*
+expr.h defines the structure of an expression node,
+and the operations that can be performed upon it.
+Note some things about this file that you should emulate:
+- Every symbol in expr.[ch] begins with expr_.
+- Use enumerations to define variant types.
+- Build complex trees one node at a time.
+- Define methods with recurse over those trees.
+*/
+
+#ifndef EXPR_H
+#define EXPR_H
+
+#include "symbol_map.h"
+#include
+#include
+
+// Expressions
+typedef enum {
+ EXPR_ADD,
+ EXPR_ARRAY,
+ EXPR_DIVIDE,
+ EXPR_EQUAL_EQUAL,
+ EXPR_FLOAT_LITERAL,
+ EXPR_GREATER_THAN,
+ EXPR_GREATER_THAN_OR_EQUAL,
+ EXPR_INTEGER_LITERAL,
+ EXPR_LESS_THAN,
+ EXPR_LESS_THAN_OR_EQUAL,
+ EXPR_MULTIPLY,
+ EXPR_NAME,
+ EXPR_NOT_EQUAL,
+ EXPR_STRING_LITERAL,
+ EXPR_SUBSCRIPT,
+ EXPR_SUBTRACT,
+} expr_t;
+
+struct expr {
+ expr_t kind;
+ struct expr *left;
+ struct expr *right;
+ const char *name;
+ int integer_value;
+ float float_value;
+ const char *string_literal;
+};
+
+typedef enum { TYPE_ARRAY, TYPE_FLOAT, TYPE_INTEGER, TYPE_STRING } type_t;
+
+struct type {
+ type_t kind;
+ struct type *subtype;
+};
+
+struct decl {
+ struct expr *name;
+ struct type *type;
+ struct expr *value;
+ struct stmt *code;
+ struct decl *next;
+};
+
+typedef enum { STMT_BLOCK, STMT_DECL, STMT_EXPR, STMT_IF, STMT_PRINT } stmt_t;
+
+struct stmt {
+ stmt_t kind;
+ struct decl *decl;
+ struct expr *init_expr;
+ struct expr *expr;
+ struct expr *next_expr;
+ struct stmt *body;
+ struct stmt *else_body;
+ struct stmt *next;
+};
+
+struct stmt *stmt_create(stmt_t kind, struct decl *decl, struct expr *init_expr,
+ struct expr *expr, struct expr *next_expr,
+ struct stmt *body, struct stmt *else_body,
+ struct stmt *next);
+struct decl *decl_create(struct expr *name, struct type *type,
+ struct expr *value, struct stmt *code,
+ struct decl *next);
+struct expr *expr_create_name(const char *name);
+struct expr *expr_create_integer_literal(int i);
+struct expr *expr_create_float_literal(float f);
+struct expr *expr_create_string_literal(const char *str);
+struct expr *expr_create(expr_t kind, struct expr *left, struct expr *right);
+struct type *type_create(type_t kind, struct type *sub);
+
+void scope_bind(const char *name, struct expr *sym);
+struct expr *scope_lookup(const char *name);
+
+void stmt_print(struct stmt *e);
+void decl_print(struct decl *d);
+void expr_print(struct expr *e);
+
+void stmt_evaluate(struct stmt *e);
+void decl_evaluate(struct decl *e);
+void decl_subscript_evaluate(struct expr *e, float value);
+float expr_evaluate(struct expr *e);
+struct expr *expr_sub_evaluate(struct expr *e);
+float expr_subscript_evaluate(struct expr *e);
+const char *expr_string_evaluate(struct expr *e);
+
+void expr_delete(struct expr *e);
+void close_parser();
+
+#endif
diff --git a/lab-5/main.c b/lab-5/main.c
new file mode 100644
index 0000000..63208e9
--- /dev/null
+++ b/lab-5/main.c
@@ -0,0 +1,32 @@
+/*
+Main program of calculator example.
+Simply invoke the parser generated by bison, and then display the output.
+*/
+
+#include "expr.h"
+#include
+
+/* Clunky: Declare the parse function generated from parser.bison */
+extern int yyparse();
+
+/* Clunky: Declare the result of the parser from parser.bison */
+extern struct stmt *parser_result;
+
+int main(int argc, char *argv[]) {
+ printf("Lab 6 Example Interpreter Compiler\n");
+ printf(
+ "Enter an infix expression using the operators +-*/() ending with ;\n\n");
+
+ if (yyparse() == 0) {
+ printf("Parse successful: ");
+ stmt_print(parser_result);
+ printf("\n");
+ printf("Running the program, results in: ");
+ stmt_evaluate(parser_result);
+ printf("\n");
+ return 0;
+ } else {
+ printf("Parse failed!\n");
+ return 1;
+ }
+}
diff --git a/lab-5/parser.bison b/lab-5/parser.bison
new file mode 100644
index 0000000..0f901ba
--- /dev/null
+++ b/lab-5/parser.bison
@@ -0,0 +1,189 @@
+
+/*
+Declare token types at the top of the bison file,
+causing them to be automatically generated in parser.tab.h
+for use by scanner.c.
+*/
+
+%debug
+%define parse.error detailed
+
+%token TOKEN_ASSIGNMENT
+%token TOKEN_COMMA
+%token TOKEN_DIV
+%token TOKEN_EQUAL_EQUAL
+%token TOKEN_GREATER_THAN
+%token TOKEN_GREATER_THAN_OR_EQUAL
+%token TOKEN_ID
+%token TOKEN_INT
+%token TOKEN_INTEGER
+%token TOKEN_KEYWORD_ENDIF
+%token TOKEN_KEYWORD_IF
+%token TOKEN_KEYWORD_PRINT
+%token TOKEN_KEYWORD_THEN
+%token TOKEN_LBRACKET
+%token TOKEN_LESS_THAN
+%token TOKEN_LESS_THAN_OR_EQUAL
+%token TOKEN_LPAREN
+%token TOKEN_MINUS
+%token TOKEN_MUL
+%token TOKEN_NOT_EQUAL
+%token TOKEN_PLUS
+%token TOKEN_RBRACKET
+%token TOKEN_RPAREN
+%token TOKEN_SEMI
+
+%union {
+ struct stmt *stmt;
+ struct expr *expr;
+ struct decl *decl;
+};
+
+%type program statement_list statement print_statement assignment_statement if_statement block
+%type expr term factor name sum array_subscript star_expr
+%type declaration
+
+%{
+#define YYDEBUG 1
+
+#include
+#include
+#include
+#include "expr.h"
+
+
+/*
+Clunky: Manually declare the interface to the scanner generated by flex.
+*/
+
+extern int yylineno;
+extern char *yytext;
+extern int yylex();
+extern void yyerror(const char*);
+
+/*
+Clunky: Keep the final result of the parse in a global variable,
+so that it can be retrieved by main().
+*/
+
+struct stmt * parser_result = 0;
+
+%}
+
+%%
+
+/* Here is the grammar: program is the start symbol. */
+
+program : statement_list
+ { parser_result = $1; return 0; }
+ ;
+
+statement_list : statement
+ { $$ = $1; }
+ | statement statement_list
+ { $$ = $1; $1->next = $2; }
+ ;
+
+block : statement
+ { $$ = $1; }
+ | statement block
+ { $$ = $1; $1->next = $2; }
+ ;
+
+statement : assignment_statement TOKEN_SEMI
+ { $$ = $1; }
+ | print_statement TOKEN_SEMI
+ { $$ = $1; }
+ | if_statement
+ { $$ = $1; }
+ ;
+
+assignment_statement : declaration
+ { $$ = stmt_create(STMT_DECL,$1,0,0,0,0,0,0); }
+ ;
+
+print_statement : TOKEN_KEYWORD_PRINT expr
+ { $$ = stmt_create(STMT_PRINT,0,0,$2,0,0,0,0); }
+ ;
+
+if_statement : TOKEN_KEYWORD_IF expr TOKEN_KEYWORD_THEN block TOKEN_KEYWORD_ENDIF
+ { $$ = stmt_create(STMT_IF,0,0,$2,0,$4,0,0); }
+ ;
+
+declaration : name TOKEN_ASSIGNMENT expr
+ { $$ = decl_create($1,0,$3,0,0); }
+ | array_subscript TOKEN_ASSIGNMENT expr
+ { $$ = decl_create($1,0,$3,0,0); }
+ ;
+
+name : TOKEN_ID
+ { $$ = expr_create_name(yytext); }
+ ;
+
+array_subscript : name TOKEN_LBRACKET expr TOKEN_RBRACKET
+ { $$ = expr_create(EXPR_SUBSCRIPT,$1,$3); }
+ ;
+
+star_expr : expr
+ { $$ = expr_create(EXPR_ARRAY,$1,0); }
+ | expr TOKEN_COMMA star_expr
+ { $$ = expr_create(EXPR_ARRAY,$1,$3); }
+ ;
+
+expr : sum TOKEN_LESS_THAN sum
+ { $$ = expr_create(EXPR_LESS_THAN,$1,$3); }
+ | sum TOKEN_LESS_THAN_OR_EQUAL sum
+ { $$ = expr_create(EXPR_LESS_THAN_OR_EQUAL,$1,$3); }
+ | sum TOKEN_GREATER_THAN sum
+ { $$ = expr_create(EXPR_GREATER_THAN,$1,$3); }
+ | sum TOKEN_GREATER_THAN_OR_EQUAL sum
+ { $$ = expr_create(EXPR_GREATER_THAN_OR_EQUAL,$1,$3); }
+ | sum TOKEN_EQUAL_EQUAL sum
+ { $$ = expr_create(EXPR_EQUAL_EQUAL,$1,$3); }
+ | sum TOKEN_NOT_EQUAL sum
+ { $$ = expr_create(EXPR_NOT_EQUAL,$1,$3); }
+ | sum
+ { $$ = $1; }
+ ;
+
+sum : sum TOKEN_PLUS term
+ { $$ = expr_create(EXPR_ADD,$1,$3); }
+ | sum TOKEN_MINUS term
+ { $$ = expr_create(EXPR_SUBTRACT,$1,$3); }
+ | term
+ { $$ = $1; }
+ ;
+
+term : term TOKEN_MUL factor
+ { $$ = expr_create(EXPR_MULTIPLY,$1,$3); }
+ | term TOKEN_DIV factor
+ { $$ = expr_create(EXPR_DIVIDE,$1,$3); }
+ | factor
+ { $$ = $1; }
+ ;
+
+factor : TOKEN_LPAREN expr TOKEN_RPAREN
+ { $$ = $2; }
+ | TOKEN_MINUS factor
+ { $$ = expr_create(EXPR_SUBTRACT,expr_create_integer_literal(0),$2); }
+ | TOKEN_INT
+ { $$ = expr_create_integer_literal(atoi(yytext)); }
+ | TOKEN_LBRACKET star_expr TOKEN_RBRACKET
+ { $$ = $2; }
+ | array_subscript
+ { $$ = $1; }
+ | name
+ { $$ = $1; }
+ ;
+
+%%
+
+/*
+This function will be called by bison if the parse should
+encounter an error. In principle, "str" will contain something
+useful. In practice, it often does not.
+*/
+
+void yyerror(const char* msg) {
+ fprintf(stderr, "Error | Line: %d\n%s\n", yylineno, msg);
+}
diff --git a/lab-5/samples/array_assignment.c b/lab-5/samples/array_assignment.c
new file mode 100644
index 0000000..cce2d38
--- /dev/null
+++ b/lab-5/samples/array_assignment.c
@@ -0,0 +1 @@
+a = [ 4, 8, 12 ];
diff --git a/lab-5/samples/array_read.c b/lab-5/samples/array_read.c
new file mode 100644
index 0000000..db30710
--- /dev/null
+++ b/lab-5/samples/array_read.c
@@ -0,0 +1,2 @@
+a = [ 3, 5 ];
+print a[0];
\ No newline at end of file
diff --git a/lab-5/samples/array_write.c b/lab-5/samples/array_write.c
new file mode 100644
index 0000000..4f81214
--- /dev/null
+++ b/lab-5/samples/array_write.c
@@ -0,0 +1,4 @@
+a = [ 3, 5, 7, 9, 11];
+print a[1];
+a[1] = 6;
+print a[1];
diff --git a/lab-5/samples/assignment_statement.c b/lab-5/samples/assignment_statement.c
new file mode 100644
index 0000000..a5a2277
--- /dev/null
+++ b/lab-5/samples/assignment_statement.c
@@ -0,0 +1 @@
+a = 5;
\ No newline at end of file
diff --git a/lab-5/samples/multiple_statements.c b/lab-5/samples/multiple_statements.c
new file mode 100644
index 0000000..b31de4e
--- /dev/null
+++ b/lab-5/samples/multiple_statements.c
@@ -0,0 +1,2 @@
+print 5;
+print 6;
diff --git a/lab-5/samples/print_if_equal.c b/lab-5/samples/print_if_equal.c
new file mode 100644
index 0000000..e4a42e4
--- /dev/null
+++ b/lab-5/samples/print_if_equal.c
@@ -0,0 +1,6 @@
+if 3==3 then
+ print 3;
+endif
+if 3==4 then
+ print 4;
+endif
diff --git a/lab-5/samples/print_if_false.c b/lab-5/samples/print_if_false.c
new file mode 100644
index 0000000..5340a03
--- /dev/null
+++ b/lab-5/samples/print_if_false.c
@@ -0,0 +1,5 @@
+if 0 then
+ print 5;
+ print 3;
+ print 1;
+endif
diff --git a/lab-5/samples/print_if_true.c b/lab-5/samples/print_if_true.c
new file mode 100644
index 0000000..7848347
--- /dev/null
+++ b/lab-5/samples/print_if_true.c
@@ -0,0 +1,5 @@
+if 1 then
+ print 5;
+ print 3;
+ print 1;
+endif
diff --git a/lab-5/samples/print_statement.c b/lab-5/samples/print_statement.c
new file mode 100644
index 0000000..1748ba7
--- /dev/null
+++ b/lab-5/samples/print_statement.c
@@ -0,0 +1 @@
+print 5;
diff --git a/lab-5/samples/print_variable.c b/lab-5/samples/print_variable.c
new file mode 100644
index 0000000..28aae29
--- /dev/null
+++ b/lab-5/samples/print_variable.c
@@ -0,0 +1,2 @@
+a = 4 + 4;
+print a;
diff --git a/lab-5/samples/program.c b/lab-5/samples/program.c
new file mode 100644
index 0000000..f1f084a
--- /dev/null
+++ b/lab-5/samples/program.c
@@ -0,0 +1,2 @@
+a=(101*20)+4;
+print(a);
diff --git a/lab-5/scanner.flex b/lab-5/scanner.flex
new file mode 100644
index 0000000..69284c9
--- /dev/null
+++ b/lab-5/scanner.flex
@@ -0,0 +1,47 @@
+%{
+#include "parser.h"
+%}
+
+%option nounput
+%option noinput
+%option noyywrap
+%option yylineno
+
+DIGIT [0-9]
+LETTER [a-zA-Z_]
+
+%%
+
+[ \n\r\t]* /* skip whitespace */;
+"print" return TOKEN_KEYWORD_PRINT;
+"if" return TOKEN_KEYWORD_IF;
+"then" return TOKEN_KEYWORD_THEN;
+"endif" return TOKEN_KEYWORD_ENDIF;
+{DIGIT}+ return TOKEN_INT;
+{LETTER}+ return TOKEN_ID;
+"," return TOKEN_COMMA;
+"]" return TOKEN_RBRACKET;
+"[" return TOKEN_LBRACKET;
+"==" return TOKEN_EQUAL_EQUAL;
+"!=" return TOKEN_NOT_EQUAL;
+"<=" return TOKEN_LESS_THAN_OR_EQUAL;
+">=" return TOKEN_GREATER_THAN_OR_EQUAL;
+"<" return TOKEN_LESS_THAN;
+">" return TOKEN_GREATER_THAN;
+\= return TOKEN_ASSIGNMENT;
+\* return TOKEN_MUL;
+\+ return TOKEN_PLUS;
+\- return TOKEN_MINUS;
+\/ return TOKEN_DIV;
+\( return TOKEN_LPAREN;
+\) return TOKEN_RPAREN;
+\; return TOKEN_SEMI;
+. { printf("scan error: bad token: %c\n", yytext[0]); }
+%%
+
+/*
+flex calls yywrap() whenever it reaches the end of the current file.
+If yywrap returns false to indicate the end of the program.
+It could alternatively open up another file and return true,
+so that flex would keep going.
+*/
diff --git a/lab-5/symbol_map.c b/lab-5/symbol_map.c
new file mode 100644
index 0000000..f15b8a7
--- /dev/null
+++ b/lab-5/symbol_map.c
@@ -0,0 +1,74 @@
+#include
+#include
+#include
+#include "symbol_map.h"
+
+// Function to create a new symbol map
+struct SymbolMap *createSymbolMap(struct SymbolMap *map) {
+ map = (struct SymbolMap *)malloc(sizeof(struct SymbolMap));
+ if (map == NULL) {
+ // Handle memory allocation failure
+ exit(EXIT_FAILURE);
+ }
+ map->head = NULL;
+ return map;
+}
+
+// Function to insert a symbol into the map
+void insertSymbol(struct SymbolMap *map, const char *key, struct expr *value) {
+ struct Node *newNode = (struct Node *)malloc(sizeof(struct Node));
+ if (newNode == NULL) {
+ // Handle memory allocation failure
+ exit(EXIT_FAILURE);
+ }
+ newNode->key = key;
+ newNode->value = value;
+ newNode->next = map->head;
+ map->head = newNode;
+}
+
+// Function to get a symbol from the map
+struct expr *getSymbol(struct SymbolMap *map, const char *key) {
+ struct Node *current = map->head;
+ while (current != NULL) {
+ if (strcmp(current->key, key) == 0) {
+ return current->value;
+ }
+ current = current->next;
+ }
+ return NULL; // Key not found
+}
+
+// Function to delete a symbol from the map
+void deleteSymbol(struct SymbolMap *map, const char *key) {
+ struct Node *current = map->head;
+ struct Node *prev = NULL;
+
+ while (current != NULL) {
+ if (strcmp(current->key, key) == 0) {
+ if (prev == NULL) {
+ map->head = current->next;
+ } else {
+ prev->next = current->next;
+ }
+ free(current);
+ return;
+ }
+ prev = current;
+ current = current->next;
+ }
+}
+
+// Function to destroy the symbol map and free memory
+void destroySymbolMap(struct SymbolMap *map) {
+ struct Node *current = map->head;
+ struct Node *next;
+
+ while (current != NULL) {
+ next = current->next;
+ free(current);
+ current = next;
+ }
+
+ free(map);
+}
diff --git a/lab-5/symbol_map.h b/lab-5/symbol_map.h
new file mode 100644
index 0000000..7704fda
--- /dev/null
+++ b/lab-5/symbol_map.h
@@ -0,0 +1,56 @@
+/*
+ * symbol_map.h
+ *
+ * Header file for a simple symbol map implementation in C.
+ * This file defines structures and functions to create, manipulate,
+ * and destroy a map with keys of type 'const char *' and values of type 'struct expr *'.
+ *
+ * Author: ChatGPT
+ * Date: November 16, 2023
+ *
+ * Structures:
+ * - struct expr: Represents a symbol with fields for its value and other relevant information.
+ * - struct Node: Represents a node in the linked list used for the symbol map implementation.
+ * - struct SymbolMap: Represents the symbol map itself.
+ *
+ * Functions:
+ * - createSymbolMap: Creates a new symbol map and initializes it.
+ * - insertSymbol: Inserts a key-value pair into the symbol map.
+ * - getSymbol: Retrieves the value associated with a given key from the symbol map.
+ * - deleteSymbol: Removes a key-value pair from the symbol map.
+ * - destroySymbolMap: Frees memory allocated for the symbol map and its nodes.
+ *
+ * Usage:
+ * 1. Include this header file in your C program: #include "symbol_map.h"
+ * 2. Implement the functions in a corresponding C file.
+ * 3. Use the functions to manage symbols in your program.
+ *
+ * Note: This implementation assumes each key in the map is unique.
+ * If needed, explore other data structures for more complex use cases.
+ */
+#ifndef SYMBOL_MAP_H
+#define SYMBOL_MAP_H
+
+// Define the symbol structure
+#include "expr.h"
+
+// Define the node structure for the linked list
+struct Node {
+ const char *key;
+ struct expr *value;
+ struct Node *next;
+};
+
+// Define the symbol map structure
+struct SymbolMap {
+ struct Node *head;
+};
+
+// Function declarations
+struct SymbolMap *createSymbolMap();
+void insertSymbol(struct SymbolMap *map, const char *key, struct expr *value);
+struct expr *getSymbol(struct SymbolMap *map, const char *key);
+void deleteSymbol(struct SymbolMap *map, const char *key);
+void destroySymbolMap(struct SymbolMap *map);
+
+#endif // SYMBOL_MAP_H