aboutsummaryrefslogtreecommitdiff
path: root/src/interpreter.c
blob: 27626a8c20c2720ab26ff2e5d8fae1f3a9d73a74 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
#include "interpreter.h"
#include <stdlib.h>
#include <stdio.h>
#include <string.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 yy_delete_buffer(YY_BUFFER_STATE);


void context_set(hashmap_t context, const char *name, int val) {
  hashmap_insert(context, name, val);
}

int context_get(hashmap_t context, const char *name) {
  int *val = hashmap_get(context, name);
  if (val) return *val;
  return 0;
}

static void print_var(const char *name, int val) {
  printf("%s = %d\n", name, val);
}

void context_print(hashmap_t context) {
  hashmap_iterate(context, print_var);
}

static int eval_aexpr(hashmap_t 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_AOP: {
      int aexp1 = eval_aexpr(context, node->u.d_aop.aexp1);
      int aexp2 = 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;
      }
    }
    default:
      fprintf(stderr, "Bad aexpr node %d\n", node->type);
      exit(EXIT_FAILURE);
  }
}

static int eval_bexpr(hashmap_t 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);
      switch (node->u.d_bop.bop) {
        case BOP_AND: return bexp1 && bexp2;
        case BOP_OR:  return bexp1 || bexp2;
      }
    }
    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);
      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;
      }
    }
    default:
      fprintf(stderr, "Bad bexpr node %d\n", node->type);
      exit(EXIT_FAILURE);
  }
}

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;
      }
      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;
      }
      default:
        fprintf(stderr, "Bad stmt node %d\n", node->type);
        exit(EXIT_FAILURE);
    }
  }
}

int exec_file (hashmap_t context, const char *path) {
  yyin = fopen(path, "r");
  if (!yyin) {
    perror(path);
    return -1;
  }
  yyrestart(yyin);
  if (!yyparse()) {
    exec_stmt(context, ast_root);
    ast_free(ast_root);
  } else {
    fprintf(stderr, "Parse error in %s\n", path);
    fclose(yyin);
    return -1;
  }
  fclose(yyin);
  return 0;
}

int exec_str (hashmap_t context, const char *str) {
  YY_BUFFER_STATE buf = yy_scan_string(str);
  if (!yyparse()) {
    exec_stmt(context, ast_root);
    ast_free(ast_root);
  } else {
    fprintf(stderr, "Parse error\n");
    yy_delete_buffer(buf);
    return -1;
  }
  yy_delete_buffer(buf);
  return 0;
}