aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/ast.h4
-rw-r--r--src/ast.c9
-rw-r--r--src/interpreter.c13
-rw-r--r--src/lexer.l2
-rw-r--r--src/parser.y4
5 files changed, 28 insertions, 4 deletions
diff --git a/include/ast.h b/include/ast.h
index c619c72..8482aab 100644
--- a/include/ast.h
+++ b/include/ast.h
@@ -4,7 +4,7 @@
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_INT, NT_VAR, NT_AOP, NT_BOP, NT_NOT, NT_ROP, NT_LET
} NodeType;
typedef enum { AOP_ADD, AOP_SUB, AOP_MUL } AOp;
@@ -24,6 +24,7 @@ typedef struct ASTNode {
struct { BOp bop; struct ASTNode *bexp1, *bexp2; } d_bop;
struct { struct ASTNode *bexp; } d_not;
struct { ROp rop; struct ASTNode *aexp1, *aexp2; } d_rop;
+ struct { struct ASTNode *var, *aexp, *stm; } d_let;
} u;
} ASTNode;
@@ -39,6 +40,7 @@ ASTNode *ast_aop(AOp aop, ASTNode *aexp1, ASTNode *aexp2);
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);
void ast_free(ASTNode *node);
diff --git a/src/ast.c b/src/ast.c
index 5460c87..83a55c6 100644
--- a/src/ast.c
+++ b/src/ast.c
@@ -88,6 +88,15 @@ ASTNode *ast_rop(ROp rop, ASTNode *aexp1, ASTNode *aexp2) {
return node;
}
+ASTNode *ast_let(ASTNode *var, ASTNode *aexp, ASTNode *stm) {
+ ASTNode *node = new_node(NT_LET);
+ node->u.d_let.var = var;
+ node->u.d_let.aexp = aexp;
+ node->u.d_let.stm = stm;
+ return node;
+}
+
+
void ast_free(ASTNode *node) {
if (!node) return;
switch (node->type) {
diff --git a/src/interpreter.c b/src/interpreter.c
index 93b1bdb..4449847 100644
--- a/src/interpreter.c
+++ b/src/interpreter.c
@@ -76,9 +76,9 @@ void exec_stmt(hashmap_t context, ASTNode *node) {
case NT_SKIP:
return;
case NT_ASSIGN: {
- char *var = node->u.d_assign.var->u.d_var.name;
+ char *name = node->u.d_assign.var->u.d_var.name;
int val = eval_aexpr(context, node->u.d_assign.aexp);
- context_set(context, var, val);
+ context_set(context, name, val);
return;
}
case NT_SEQ:
@@ -96,6 +96,15 @@ void exec_stmt(hashmap_t context, ASTNode *node) {
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;
+ }
default:
fprintf(stderr, "Bad stmt node %d\n", node->type);
exit(EXIT_FAILURE);
diff --git a/src/lexer.l b/src/lexer.l
index c9aaff0..26ac229 100644
--- a/src/lexer.l
+++ b/src/lexer.l
@@ -17,6 +17,8 @@ WHITESPACE [ \t\r\n]+
"end" { return TOKEN_END; }
"while" { return TOKEN_WHILE; }
"do" { return TOKEN_DO; }
+"var" { return TOKEN_VAR; }
+"in" { return TOKEN_IN; }
"(" { return TOKEN_LEFT_PARENTHESIS; }
")" { return TOKEN_RIGHT_PARENTHESIS; }
diff --git a/src/parser.y b/src/parser.y
index 9a94480..cb3544e 100644
--- a/src/parser.y
+++ b/src/parser.y
@@ -29,7 +29,7 @@ void yyerror(const char *s) {
%token TOKEN_LEFT_PARENTHESIS TOKEN_RIGHT_PARENTHESIS
%token TOKEN_SEMICOLON
%token TOKEN_SKIP
-%token TOKEN_IF TOKEN_THEN TOKEN_ELSE TOKEN_END TOKEN_WHILE TOKEN_DO
+%token TOKEN_IF TOKEN_THEN TOKEN_ELSE TOKEN_END TOKEN_WHILE TOKEN_DO TOKEN_VAR TOKEN_IN
%token TOKEN_PLUS TOKEN_MINUS TOKEN_MULTIPLY
%token TOKEN_NOT TOKEN_OR TOKEN_AND
%token TOKEN_EQUALS TOKEN_NOT_EQUALS TOKEN_LESS_THAN TOKEN_LESS_EQUAL TOKEN_GREATER_THAN TOKEN_GREATER_EQUAL
@@ -54,6 +54,8 @@ statement : TOKEN_SKIP
{ $$ = ast_if($2, $4, $6); }
| TOKEN_WHILE boolean_expression TOKEN_DO statement TOKEN_END
{ $$ = ast_while($2, $4); }
+ | TOKEN_VAR variable TOKEN_ASSIGN arithmetic_expression TOKEN_IN statement TOKEN_END
+ { $$ = ast_let($2, $4, $6); }
;
variable : TOKEN_IDENTIFIER