aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--example/example.imp19
-rw-r--r--include/ast.h18
-rw-r--r--include/hash_map.h13
-rw-r--r--include/hashmap.h23
-rw-r--r--include/interpreter.h19
-rw-r--r--include/repl.h2
-rw-r--r--src/ast.c97
-rw-r--r--src/driver.c13
-rw-r--r--src/hashmap.c (renamed from src/hash_map.c)61
-rw-r--r--src/interpreter.c235
-rw-r--r--src/lexer.l3
-rw-r--r--src/parser.y33
-rw-r--r--src/repl.c28
13 files changed, 411 insertions, 153 deletions
diff --git a/example/example.imp b/example/example.imp
index b52d2da..a5bc5dd 100644
--- a/example/example.imp
+++ b/example/example.imp
@@ -1,13 +1,12 @@
-y := 0;
-
-var x := 5 in
-
- while x < 10 and true do
- x := (x + 1);
+procedure factorial(n;r) begin
+ if n <= 0 then
+ r := 1;
+ else
+ m := n - 1;
+ factorial(m;r);
+ r := r * n;
end;
-
- y := x;
-
end;
-z := 5; \ No newline at end of file
+n := 5;
+factorial(n;r); \ No newline at end of file
diff --git a/include/ast.h b/include/ast.h
index 8482aab..2d25057 100644
--- a/include/ast.h
+++ b/include/ast.h
@@ -4,7 +4,8 @@
typedef enum {
NT_SKIP, NT_ASSIGN, NT_SEQ, NT_IF, NT_WHILE,
- NT_INT, NT_VAR, NT_AOP, NT_BOP, NT_NOT, NT_ROP, NT_LET
+ NT_INT, NT_VAR, NT_AOP, NT_BOP, NT_NOT, NT_ROP, NT_LET,
+ NT_PROCDECL, NT_PROCCALL
} NodeType;
typedef enum { AOP_ADD, AOP_SUB, AOP_MUL } AOp;
@@ -25,9 +26,16 @@ typedef struct ASTNode {
struct { struct ASTNode *bexp; } d_not;
struct { ROp rop; struct ASTNode *aexp1, *aexp2; } d_rop;
struct { struct ASTNode *var, *aexp, *stm; } d_let;
+ struct { char *name; struct ASTNodeList *args, *vargs; struct ASTNode *stm; } d_procdecl;
+ struct { char *name; struct ASTNodeList *args, *vargs; } d_proccall;
} u;
} ASTNode;
+typedef struct ASTNodeList {
+ ASTNode *node;
+ struct ASTNodeList *next;
+} ASTNodeList;
+
ASTNode *ast_skip(void);
ASTNode *ast_assign(ASTNode *var, ASTNode *aexp);
@@ -41,8 +49,14 @@ ASTNode *ast_bop(BOp bop, ASTNode *bexp1, ASTNode *bexp2);
ASTNode *ast_not(ASTNode *bexp);
ASTNode *ast_rop(ROp rop, ASTNode *aexp1, ASTNode *aexp2);
ASTNode *ast_let(ASTNode *var, ASTNode *aexp, ASTNode *stm);
+ASTNode *ast_procdecl(const char *name, ASTNodeList *args, ASTNodeList *vargs, ASTNode *stm);
+ASTNode *ast_proccall(const char *name, ASTNodeList *args, ASTNodeList *vargs);
+
+
+ASTNodeList *ast_node_list(ASTNode *node, ASTNodeList *list);
+ASTNode *ast_clone(ASTNode *node);
void ast_free(ASTNode *node);
-#endif
+#endif \ No newline at end of file
diff --git a/include/hash_map.h b/include/hash_map.h
deleted file mode 100644
index 6bc733f..0000000
--- a/include/hash_map.h
+++ /dev/null
@@ -1,13 +0,0 @@
-#ifndef HASH_MAP_H
-#define HASH_MAP_H
-
-typedef struct HashMap *hashmap_t;
-
-hashmap_t hashmap_create(void);
-void hashmap_insert(hashmap_t map, const char *key, int value);
-int *hashmap_get(hashmap_t map, const char *key);
-void hashmap_delete(hashmap_t map, const char *key);
-void hashmap_free(hashmap_t map);
-void hashmap_iterate(hashmap_t map, void (*callback)(const char *key, int value));
-
-#endif \ No newline at end of file
diff --git a/include/hashmap.h b/include/hashmap.h
new file mode 100644
index 0000000..c62a319
--- /dev/null
+++ b/include/hashmap.h
@@ -0,0 +1,23 @@
+#ifndef HASHMAP_H
+#define HASHMAP_H
+
+
+typedef struct HashMap *hashmap_t;
+typedef struct HashMapKeys *hashmap_keys_t;
+
+
+hashmap_t hashmap_create(void);
+void hashmap_free(hashmap_t map);
+
+void **hashmap_get(hashmap_t map, const char *key);
+void hashmap_insert(hashmap_t map, const char *key, void *value);
+int hashmap_delete(hashmap_t map, const char *key);
+
+void hashmap_iterate(hashmap_t map, void (*callback)(const char *key, void *value));
+hashmap_keys_t hashmap_keys_create(hashmap_t map);
+const char *hashmap_keys_next(hashmap_keys_t iter);
+void hashmap_keys_free(hashmap_keys_t iter);
+
+
+
+#endif \ No newline at end of file
diff --git a/include/interpreter.h b/include/interpreter.h
index 6e60113..cb3ba75 100644
--- a/include/interpreter.h
+++ b/include/interpreter.h
@@ -3,17 +3,22 @@
#include "ast.h"
-#include "hash_map.h"
-void exec_stmt(hashmap_t context, ASTNode *node);
-void context_print(hashmap_t context);
+typedef struct Context *context_t;
-void context_set(hashmap_t context, const char *name, int value);
-int context_get(hashmap_t context, const char *name);
-int exec_file (hashmap_t context, const char *path);
-int exec_str (hashmap_t context, const char *str);
+context_t context_create(void);
+void context_free(context_t context);
+
+int context_get_var(context_t context, const char *name);
+void context_set_var(context_t context, const char *name, int value);
+void context_print_var_table(context_t context);
+void context_print_proc_table(context_t context);
+
+void interp_ast(context_t context, ASTNode *node);
+int interp_file (context_t context, const char *path);
+int interp_str (context_t context, const char *str);
#endif \ No newline at end of file
diff --git a/include/repl.h b/include/repl.h
index 804b702..4b833ad 100644
--- a/include/repl.h
+++ b/include/repl.h
@@ -1,6 +1,8 @@
#ifndef REPL_H
#define REPL_H
+
void repl(void);
+
#endif \ No newline at end of file
diff --git a/src/ast.c b/src/ast.c
index 66e76ea..ba8dc9f 100644
--- a/src/ast.c
+++ b/src/ast.c
@@ -1,5 +1,5 @@
#include "ast.h"
-#include <stdio.h>
+
#include <stdlib.h>
#include <string.h>
#include <assert.h>
@@ -96,6 +96,39 @@ ASTNode *ast_let(ASTNode *var, ASTNode *aexp, ASTNode *stm) {
return node;
}
+ASTNode *ast_procdecl(const char *name, ASTNodeList *args, ASTNodeList *vargs, ASTNode *stm) {
+ ASTNode *node = new_node(NT_PROCDECL);
+ node->u.d_procdecl.name = strdup(name);
+ assert(node->u.d_procdecl.name);
+ node->u.d_procdecl.args = args;
+ node->u.d_procdecl.vargs = vargs;
+ node->u.d_procdecl.stm = stm;
+ return node;
+}
+
+ASTNode *ast_proccall(const char *name, ASTNodeList *args, ASTNodeList *vargs) {
+ ASTNode *node = new_node(NT_PROCCALL);
+ node->u.d_proccall.name = strdup(name);
+ assert(node->u.d_proccall.name);
+ node->u.d_proccall.args = args;
+ node->u.d_proccall.vargs = vargs;
+ return node;
+}
+
+ASTNodeList *ast_node_list(ASTNode *node, ASTNodeList *list) {
+ ASTNodeList *new_list = malloc(sizeof(ASTNodeList));
+ assert(new_list);
+ new_list->node = node;
+ new_list->next = list;
+ return new_list;
+}
+
+static void ast_free_node_list(ASTNodeList *list) {
+ if (!list) return;
+ ast_free(list->node);
+ ast_free_node_list(list->next);
+ free(list);
+}
void ast_free(ASTNode *node) {
if (!node) return;
@@ -144,6 +177,68 @@ void ast_free(ASTNode *node) {
ast_free(node->u.d_let.aexp);
ast_free(node->u.d_let.stm);
break;
+ case NT_PROCDECL:
+ free(node->u.d_procdecl.name);
+ ast_free_node_list(node->u.d_procdecl.args);
+ ast_free_node_list(node->u.d_procdecl.vargs);
+ ast_free(node->u.d_procdecl.stm);
+ break;
+ case NT_PROCCALL:
+ free(node->u.d_proccall.name);
+ ast_free_node_list(node->u.d_proccall.args);
+ ast_free_node_list(node->u.d_proccall.vargs);
+ break;
+ default: assert(0);
}
free(node);
+}
+
+static ASTNodeList *ast_node_list_clone(ASTNodeList *list) {
+ if (!list) return NULL;
+ return ast_node_list(ast_clone(list->node), ast_node_list_clone(list->next));
+}
+
+ASTNode *ast_clone(ASTNode *node) {
+ if (!node) return NULL;
+ switch (node->type) {
+ case NT_SKIP: return ast_skip();
+ case NT_ASSIGN: return ast_assign(ast_clone(node->u.d_assign.var), ast_clone(node->u.d_assign.aexp));
+ case NT_SEQ: return ast_seq(ast_clone(node->u.d_seq.stm1), ast_clone(node->u.d_seq.stm2));
+ case NT_IF: return ast_if(
+ ast_clone(node->u.d_if.bexp),
+ ast_clone(node->u.d_if.stm1),
+ ast_clone(node->u.d_if.stm2));
+ case NT_WHILE: return ast_while(
+ ast_clone(node->u.d_while.bexp),
+ ast_clone(node->u.d_while.stm));
+ case NT_INT: return ast_int(node->u.d_int.val);
+ case NT_VAR: return ast_var(node->u.d_var.name);
+ case NT_AOP: return ast_aop(
+ node->u.d_aop.aop,
+ ast_clone(node->u.d_aop.aexp1),
+ ast_clone(node->u.d_aop.aexp2));
+ case NT_BOP: return ast_bop(
+ node->u.d_bop.bop,
+ ast_clone(node->u.d_bop.bexp1),
+ ast_clone(node->u.d_bop.bexp2));
+ case NT_NOT: return ast_not(ast_clone(node->u.d_not.bexp));
+ case NT_ROP: return ast_rop(
+ node->u.d_rop.rop,
+ ast_clone(node->u.d_rop.aexp1),
+ ast_clone(node->u.d_rop.aexp2));
+ case NT_LET: return ast_let(
+ ast_clone(node->u.d_let.var),
+ ast_clone(node->u.d_let.aexp),
+ ast_clone(node->u.d_let.stm));
+ case NT_PROCDECL: return ast_procdecl(
+ node->u.d_procdecl.name,
+ ast_node_list_clone(node->u.d_procdecl.args),
+ ast_node_list_clone(node->u.d_procdecl.vargs),
+ ast_clone(node->u.d_procdecl.stm));
+ case NT_PROCCALL: return ast_proccall(
+ node->u.d_proccall.name,
+ ast_node_list_clone(node->u.d_proccall.args),
+ ast_node_list_clone(node->u.d_proccall.vargs));
+ default: assert(0);
+ }
} \ No newline at end of file
diff --git a/src/driver.c b/src/driver.c
index fc2a3ae..e3938a6 100644
--- a/src/driver.c
+++ b/src/driver.c
@@ -2,22 +2,23 @@
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
+
#include "interpreter.h"
#include "repl.h"
+
static void interpret_file(const char *path) {
- hashmap_t context = hashmap_create();
- exec_file(context, path);
- context_print(context);
- hashmap_free(context);
+ context_t context = context_create();
+ interp_file(context, path);
+ context_print_var_table(context);
+ context_free(context);
}
int main(int argc, char **argv) {
int opt;
- const char *script = NULL;
while ((opt = getopt(argc, argv, "i:h")) != -1) {
switch (opt){
- case 'i':
+ case 'i':
interpret_file(optarg);
return EXIT_SUCCESS;
case 'h':
diff --git a/src/hash_map.c b/src/hashmap.c
index 5f80205..a712134 100644
--- a/src/hash_map.c
+++ b/src/hashmap.c
@@ -1,15 +1,17 @@
-#include "hash_map.h"
-#include <stdio.h>
+#include "hashmap.h"
+
#include <stdlib.h>
#include <string.h>
#include <assert.h>
+
#define INITIAL_SIZE (16)
#define LOAD_FACTOR_THRESHOLD (0.75)
+
typedef struct Pair {
char *key;
- int value;
+ void *value;
struct Pair *next;
} Pair;
@@ -19,6 +21,13 @@ typedef struct HashMap {
size_t count;
} HashMap;
+typedef struct HashMapKeys {
+ char **keys;
+ size_t count;
+ size_t index;
+} HashMapKeys;
+
+
static unsigned int hash(const char *key, size_t size) {
unsigned int hash_value = 0;
while (*key) hash_value = (hash_value * 31) + *key++;
@@ -55,8 +64,8 @@ HashMap *hashmap_create(void) {
return map;
}
-void hashmap_insert(HashMap *map, const char *key, int value) {
- int *old_value = hashmap_get(map, key);
+void hashmap_insert(HashMap *map, const char *key, void *value) {
+ void **old_value = hashmap_get(map, key);
if (old_value) {
*old_value = value;
return;
@@ -73,7 +82,7 @@ void hashmap_insert(HashMap *map, const char *key, int value) {
map->count++;
}
-int *hashmap_get(HashMap *map, const char *key) {
+void **hashmap_get(HashMap *map, const char *key) {
unsigned int index = hash(key, map->size);
Pair *pair = map->table[index];
while (pair) {
@@ -83,7 +92,7 @@ int *hashmap_get(HashMap *map, const char *key) {
return NULL;
}
-void hashmap_delete(HashMap *map, const char *key) {
+int hashmap_delete(HashMap *map, const char *key) {
unsigned int index = hash(key, map->size);
Pair *pair = map->table[index];
Pair *prev = NULL;
@@ -94,11 +103,12 @@ void hashmap_delete(HashMap *map, const char *key) {
free(pair->key);
free(pair);
map->count--;
- return;
+ return 0;
}
prev = pair;
pair = pair->next;
}
+ return -1;
}
void hashmap_free(HashMap *map) {
@@ -115,7 +125,7 @@ void hashmap_free(HashMap *map) {
free(map);
}
-void hashmap_iterate(HashMap *map, void (*callback)(const char *key, int value)) {
+void hashmap_iterate(HashMap *map, void (*callback)(const char *key, void *value)) {
for (size_t i = 0; i < map->size; ++i) {
Pair *pair = map->table[i];
while (pair) {
@@ -123,4 +133,37 @@ void hashmap_iterate(HashMap *map, void (*callback)(const char *key, int value))
pair = pair->next;
}
}
+}
+
+HashMapKeys *hashmap_keys_create(HashMap *map) {
+ HashMapKeys *iter = malloc(sizeof(HashMapKeys));
+ assert(iter);
+ iter->keys = malloc(map->count * sizeof(char*));
+ assert(iter->keys);
+ iter->count = 0;
+ iter->index = 0;
+ for (size_t i = 0; i < map->size; ++i) {
+ Pair *pair = map->table[i];
+ while (pair) {
+ iter->keys[iter->count++] = strdup(pair->key);
+ pair = pair->next;
+ }
+ }
+ return iter;
+}
+
+const char *hashmap_keys_next(HashMapKeys *iter) {
+ if (iter->index < iter->count) {
+ return iter->keys[iter->index++];
+ }
+ return NULL;
+}
+
+void hashmap_keys_free(HashMapKeys *iter) {
+ if (!iter) return;
+ for (size_t i = 0; i < iter->count; ++i) {
+ free(iter->keys[i]);
+ }
+ free(iter->keys);
+ free(iter);
} \ No newline at end of file
diff --git a/src/interpreter.c b/src/interpreter.c
index 27626a8..af487c6 100644
--- a/src/interpreter.c
+++ b/src/interpreter.c
@@ -1,138 +1,204 @@
#include "interpreter.h"
+
#include <stdlib.h>
#include <stdio.h>
-#include <string.h>
+#include <assert.h>
+
+#include "hashmap.h"
+
typedef void *YY_BUFFER_STATE;
extern FILE *yyin;
extern ASTNode *ast_root;
extern int yyparse(void);
-extern void yyrestart (FILE *);
-extern YY_BUFFER_STATE yy_scan_string(const char *);
+extern void yyrestart (FILE*);
+extern YY_BUFFER_STATE yy_scan_string(const char*);
extern void yy_delete_buffer(YY_BUFFER_STATE);
+typedef struct Context{
+ hashmap_t var_table;
+ hashmap_t proc_table;
+} Context;
+
+
+Context *context_create(void) {
+ Context *context = malloc(sizeof(Context));
+ assert(context);
+ context->var_table = hashmap_create();
+ context->proc_table = hashmap_create();
+ return context;
+}
-void context_set(hashmap_t context, const char *name, int val) {
- hashmap_insert(context, name, val);
+static void free_procdecl(const char *name, void *procdecl) {
+ ast_free((ASTNode*)procdecl);
}
-int context_get(hashmap_t context, const char *name) {
- int *val = hashmap_get(context, name);
+void context_free(Context *context) {
+ hashmap_free(context->var_table);
+ hashmap_iterate(context->proc_table, free_procdecl);
+ hashmap_free(context->proc_table);
+ free(context);
+}
+
+int context_get_var(Context *context, const char *name) {
+ int *val = (int*)hashmap_get(context->var_table, name);
if (val) return *val;
return 0;
}
-static void print_var(const char *name, int val) {
- printf("%s = %d\n", name, val);
+void context_set_var(Context *context, const char *name, int val) {
+ hashmap_insert(context->var_table, name, (void*)val);
}
-void context_print(hashmap_t context) {
- hashmap_iterate(context, print_var);
+static void print_var(const char *name, void *val) {
+ printf("%s = %d\n", name, (int)val);
}
-static int eval_aexpr(hashmap_t context, ASTNode *node) {
+void context_print_var_table(Context *context) {
+ hashmap_iterate(context->var_table, print_var);
+}
+
+static ASTNode *context_get_proc(Context *context, const char *name) {
+ ASTNode **procdecl = (ASTNode**)hashmap_get(context->proc_table, name);
+ if (procdecl) return *procdecl;
+ return NULL;
+}
+
+static void context_set_proc(Context *context, const char *name, ASTNode *procdecl) {
+ hashmap_insert(context->proc_table, name, (void*)procdecl);
+}
+
+static int eval_aexpr(Context *context, ASTNode *node) {
switch (node->type) {
case NT_INT: return node->u.d_int.val;
- case NT_VAR: return context_get(context, node->u.d_var.name);
+ case NT_VAR: return context_get_var(context, node->u.d_var.name);
case NT_AOP: {
- int aexp1 = eval_aexpr(context, node->u.d_aop.aexp1);
- int aexp2 = eval_aexpr(context, node->u.d_aop.aexp2);
+ int aexp1_val = eval_aexpr(context, node->u.d_aop.aexp1);
+ int aexp2_val = eval_aexpr(context, node->u.d_aop.aexp2);
switch (node->u.d_aop.aop) {
- case AOP_ADD: return aexp1 + aexp2;
- case AOP_SUB: return aexp1 - aexp2;
- case AOP_MUL: return aexp1 * aexp2;
+ case AOP_ADD: return aexp1_val + aexp2_val;
+ case AOP_SUB: return aexp1_val - aexp2_val;
+ case AOP_MUL: return aexp1_val * aexp2_val;
+ default: assert(0);
}
}
- default:
- fprintf(stderr, "Bad aexpr node %d\n", node->type);
- exit(EXIT_FAILURE);
+ default: assert(0);
}
}
-static int eval_bexpr(hashmap_t context, ASTNode *node) {
+static int eval_bexpr(Context *context, ASTNode *node) {
switch (node->type) {
case NT_BOP: {
- int bexp1 = eval_bexpr(context, node->u.d_bop.bexp1);
- int bexp2 = eval_bexpr(context, node->u.d_bop.bexp2);
+ int bexp1_val = eval_bexpr(context, node->u.d_bop.bexp1);
+ int bexp2_val = eval_bexpr(context, node->u.d_bop.bexp2);
switch (node->u.d_bop.bop) {
- case BOP_AND: return bexp1 && bexp2;
- case BOP_OR: return bexp1 || bexp2;
+ case BOP_AND: return bexp1_val && bexp2_val;
+ case BOP_OR: return bexp1_val || bexp2_val;
+ default: assert(0);
}
}
- case NT_NOT:
- return !eval_bexpr(context, node->u.d_not.bexp);
+ case NT_NOT: return !eval_bexpr(context, node->u.d_not.bexp);
case NT_ROP: {
- int aexp1 = eval_aexpr(context, node->u.d_rop.aexp1);
- int aexp2 = eval_aexpr(context, node->u.d_rop.aexp2);
+ int aexp1_val = eval_aexpr(context, node->u.d_rop.aexp1);
+ int aexp2_val = eval_aexpr(context, node->u.d_rop.aexp2);
switch (node->u.d_rop.rop) {
- case ROP_EQ: return aexp1 == aexp2;
- case ROP_NE: return aexp1 != aexp2;
- case ROP_LT: return aexp1 < aexp2;
- case ROP_LE: return aexp1 <= aexp2;
- case ROP_GT: return aexp1 > aexp2;
- case ROP_GE: return aexp1 >= aexp2;
+ case ROP_EQ: return aexp1_val == aexp2_val;
+ case ROP_NE: return aexp1_val != aexp2_val;
+ case ROP_LT: return aexp1_val < aexp2_val;
+ case ROP_LE: return aexp1_val <= aexp2_val;
+ case ROP_GT: return aexp1_val > aexp2_val;
+ case ROP_GE: return aexp1_val >= aexp2_val;
+ default: assert(0);
}
}
- default:
- fprintf(stderr, "Bad bexpr node %d\n", node->type);
- exit(EXIT_FAILURE);
+ default: assert(0);
}
}
-void exec_stmt(hashmap_t context, ASTNode *node) {
- while (node) {
- switch (node->type) {
- case NT_SKIP:
- return;
- case NT_ASSIGN: {
- char *name = node->u.d_assign.var->u.d_var.name;
- int val = eval_aexpr(context, node->u.d_assign.aexp);
- context_set(context, name, val);
- return;
+void interp_ast(Context *context, ASTNode *node) {
+ switch (node->type) {
+ case NT_SKIP: return;
+ case NT_ASSIGN: {
+ char *name = node->u.d_assign.var->u.d_var.name;
+ int val = eval_aexpr(context, node->u.d_assign.aexp);
+ context_set_var(context, name, val);
+ return;
+ }
+ case NT_SEQ:
+ interp_ast(context, node->u.d_seq.stm1);
+ interp_ast(context, node->u.d_seq.stm2);
+ return;
+ case NT_IF:
+ if (eval_bexpr(context, node->u.d_if.bexp)) interp_ast(context, node->u.d_if.stm1);
+ else interp_ast(context, node->u.d_if.stm2);
+ return;
+ case NT_WHILE:
+ while (eval_bexpr(context, node->u.d_while.bexp)) interp_ast(context, node->u.d_while.stm);
+ return;
+ case NT_LET: {
+ char *name = node->u.d_let.var->u.d_var.name;
+ int old_val = context_get_var(context, name);
+ int new_val = eval_aexpr(context, node->u.d_let.aexp);
+ context_set_var(context, name, new_val);
+ interp_ast(context, node->u.d_let.stm);
+ context_set_var(context, name, old_val);
+ return;
+ }
+ case NT_PROCDECL: {
+ char *name = node->u.d_procdecl.name;
+ ASTNode *procdecl = ast_clone(node);
+ ASTNode *procdecl_old = context_get_proc(context, name);
+ if (procdecl_old) ast_free(procdecl_old);
+ context_set_proc(context, name, procdecl);
+ return;
+ }
+ case NT_PROCCALL: {
+ char *name = node->u.d_proccall.name;
+ ASTNode *procdecl = context_get_proc(context, name);
+ if (!procdecl) return;
+ ASTNodeList *caller_args = node->u.d_proccall.args;
+ ASTNodeList *callee_args = procdecl->u.d_procdecl.args;
+ Context *proc_context = context_create();
+ hashmap_keys_t keys = hashmap_keys_create(context->proc_table);
+ const char *key;
+ while ((key = hashmap_keys_next(keys)) != NULL) {
+ ASTNode *proc = context_get_proc(context, key);
+ assert(proc);
+ context_set_proc(proc_context, key, ast_clone(proc));
+ }
+ hashmap_keys_free(keys);
+ while (caller_args && callee_args) {
+ char *caller_arg_name = caller_args->node->u.d_var.name;
+ char *callee_arg_name = callee_args->node->u.d_var.name;
+ context_set_var(proc_context, callee_arg_name, context_get_var(context, caller_arg_name));
+ caller_args = caller_args->next;
+ callee_args = callee_args->next;
}
- case NT_SEQ:
- exec_stmt(context, node->u.d_seq.stm1);
- exec_stmt(context, node->u.d_seq.stm2);
- return;
- case NT_IF:
- if (eval_bexpr(context, node->u.d_if.bexp))
- exec_stmt(context, node->u.d_if.stm1);
- else
- exec_stmt(context, node->u.d_if.stm2);
- return;
- case NT_WHILE:
- while (eval_bexpr(context, node->u.d_while.bexp)) {
- exec_stmt(context, node->u.d_while.stm);
- }
- return;
- case NT_LET: {
- char *name = node->u.d_let.var->u.d_var.name;
- int old_val = context_get(context, name);
- int new_val = eval_aexpr(context, node->u.d_let.aexp);
- context_set(context, name, new_val);
- exec_stmt(context, node->u.d_let.stm);
- context_set(context, name, old_val);
- return;
+ interp_ast(proc_context, procdecl->u.d_procdecl.stm);
+ ASTNodeList *caller_vargs = node->u.d_proccall.vargs;
+ ASTNodeList *callee_vargs = procdecl->u.d_procdecl.vargs;
+ while (caller_vargs && callee_vargs) {
+ char *caller_varg_name = caller_vargs->node->u.d_var.name;
+ char *callee_varg_name = callee_vargs->node->u.d_var.name;
+ context_set_var(context, caller_varg_name, context_get_var(proc_context, callee_varg_name));
+ caller_vargs = caller_vargs->next;
+ callee_vargs = callee_vargs->next;
}
- default:
- fprintf(stderr, "Bad stmt node %d\n", node->type);
- exit(EXIT_FAILURE);
+ context_free(proc_context);
+ return;
}
+ default: assert(0);
}
}
-int exec_file (hashmap_t context, const char *path) {
+int interp_file (Context *context, const char *path) {
yyin = fopen(path, "r");
- if (!yyin) {
- perror(path);
- return -1;
- }
+ if (!yyin) return -1;
yyrestart(yyin);
if (!yyparse()) {
- exec_stmt(context, ast_root);
+ interp_ast(context, ast_root);
ast_free(ast_root);
} else {
- fprintf(stderr, "Parse error in %s\n", path);
fclose(yyin);
return -1;
}
@@ -140,13 +206,12 @@ int exec_file (hashmap_t context, const char *path) {
return 0;
}
-int exec_str (hashmap_t context, const char *str) {
+int interp_str (Context *context, const char *str) {
YY_BUFFER_STATE buf = yy_scan_string(str);
if (!yyparse()) {
- exec_stmt(context, ast_root);
+ interp_ast(context, ast_root);
ast_free(ast_root);
} else {
- fprintf(stderr, "Parse error\n");
yy_delete_buffer(buf);
return -1;
}
diff --git a/src/lexer.l b/src/lexer.l
index b2cbaab..285cbf7 100644
--- a/src/lexer.l
+++ b/src/lexer.l
@@ -19,10 +19,13 @@ WHITESPACE [ \t\r\n]+
"do" { return T_DO; }
"var" { return T_VAR; }
"in" { return T_IN; }
+"procedure" { return T_PROC; }
+"begin" { return T_BEGIN; }
"(" { return T_LPAREN; }
")" { return T_RPAREN; }
";" { return T_SEM; }
+"," { return T_COM; }
":=" { return T_ASSIGN; }
"+" { return T_PLUS; }
diff --git a/src/parser.y b/src/parser.y
index f03e54f..164b3cc 100644
--- a/src/parser.y
+++ b/src/parser.y
@@ -15,9 +15,10 @@ void yyerror(const char *s) {
%union {
- int num;
- char *id;
- struct ASTNode *node;
+ int num;
+ char *id;
+ struct ASTNode *node;
+ struct ASTNodeList *node_list;
}
%start prog
@@ -32,13 +33,12 @@ void yyerror(const char *s) {
%left T_PLUS T_MINUS
%left T_STAR
%right T_UMINUS
-%token T_END T_IF T_THEN T_ELSE T_WHILE T_DO T_VAR T_IN
-%token T_SKIP
+%token T_SKIP T_END T_IF T_THEN T_ELSE T_WHILE T_DO T_VAR T_IN T_PROC T_BEGIN
%token T_ASSIGN
-%token T_LPAREN T_RPAREN
-%token T_SEM
+%token T_LPAREN T_RPAREN T_COM T_SEM
-%type <node> prog stm var aexp bexp
+%type <node> prog stm var aexp bexp procd procc
+%type <node_list> args
%%
@@ -64,6 +64,10 @@ stm : T_SKIP
{ $$ = ast_while($2, $4); }
| T_VAR var T_ASSIGN aexp T_IN stm T_END
{ $$ = ast_let($2, $4, $6); }
+ | procd
+ { $$ = $1; }
+ | procc
+ { $$ = $1; }
;
var : T_ID
@@ -112,4 +116,17 @@ bexp : bexp T_OR bexp
{ $$ = ast_rop(ROP_EQ, ast_int(0), ast_int(1)); }
;
+args : var
+ { $$ = ast_node_list($1, NULL); }
+ | args T_COM var
+ { $$ = ast_node_list($3, $1); }
+ ;
+
+procd : T_PROC T_ID T_LPAREN args T_SEM args T_RPAREN T_BEGIN stm T_END
+ { $$ = ast_procdecl($2, $4, $6, $9); }
+ ;
+
+procc : T_ID T_LPAREN args T_SEM args T_RPAREN
+ { $$ = ast_proccall($1, $3, $5); }
+ ;
%%
diff --git a/src/repl.c b/src/repl.c
index 5ea9792..f6387a2 100644
--- a/src/repl.c
+++ b/src/repl.c
@@ -1,11 +1,15 @@
#include "repl.h"
-#include "interpreter.h"
-#include <readline/readline.h>
-#include <readline/history.h>
+
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <readline/readline.h>
+#include <readline/history.h>
+
+#include "interpreter.h"
+
+
static void print_help(void) {
printf(
"IMP REPL (type IMP statements or commands starting with '%%')\n"
@@ -17,7 +21,7 @@ static void print_help(void) {
" %%help show this message\n");
}
-static void repl_exec_command(hashmap_t context, const char *command) {
+static void repl_exec_command(context_t context, char *command) {
char *cmd = strtok(command, " \t");
if (strcmp(cmd, "%quit") == 0) {
exit(EXIT_SUCCESS);
@@ -26,30 +30,30 @@ static void repl_exec_command(hashmap_t context, const char *command) {
} else if (strcmp(cmd, "%run") == 0) {
char *file = strtok(NULL, " \t");
if (file) {
- if (!exec_file(context, file)) context_print(context);
+ if (!interp_file(context, file)) context_print_var_table(context);
} else {
fprintf(stderr, "Usage: %%run <path/to/file.imp>\n");
}
} else if (strcmp(cmd, "%set") == 0) {
char *var = strtok(NULL, " \t");
char *val = strtok(NULL, " \t");
- if (var && val) context_set(context, var, atoi(val));
+ if (var && val) context_set_var(context, var, atoi(val));
else fprintf(stderr, "Usage: %%set <var> <val>\n");
} else if (strcmp(cmd, "%print") == 0) {
char *var = strtok(NULL, " \t");
- if (var) printf("%s = %d\n", var, context_get(context, var));
- else context_print(context);
+ if (var) printf("%s = %d\n", var, context_get_var(context, var));
+ else context_print_var_table(context);
} else {
fprintf(stderr, "Unknown command: %s\n", cmd);
}
}
-static void repl_exec_statement(hashmap_t context, const char *statement) {
- if (!exec_str(context, statement)) context_print(context);
+static void repl_exec_statement(context_t context, const char *statement) {
+ if (!interp_str(context, statement)) context_print_var_table(context);
}
void repl(void) {
- hashmap_t context = hashmap_create();
+ context_t context = context_create();
char *line;
print_help();
@@ -61,5 +65,5 @@ void repl(void) {
}
printf("\n");
- hashmap_free(context);
+ context_free(context);
} \ No newline at end of file