Logo  

CS456 - Systems Programming

Interpreting part 5

Running the AST:

Break & continue:

In the following code, the function takes a statement pointer to "execute" as well as two pointers cont and brk which are Booleans that pass back to the parent caller that a continue or break was issued. The code assumes that statement may be a block statement and iterates over the linked list of statements executing each one. If a break or continue is encountered the function exits immediately, even if the immediate parent caller wouldn't normally handle the break or continue. At the end of the switch, if cont or brk are still true, keep returning (i.e. poping up the call-stack) until it hits a calling statement that handles them (i.e. the while-loop statement.)

void run(stnode_t *st, int *cont, int *brk)
{
  stnode_t *n;

  for(n = st; n != NULL; n=n->next) {
    switch(n->type) {
      case ST_EXPRESSION:
        eval_expr(n->expr);
        break;
      case ST_PRINT:
        printf("%ld\n", eval_expr(n->expr));
        break;
      case ST_CONTINUE:
        (*cont)++;
        return;
      case ST_BREAK:
        (*brk)++;
        return;
      case ST_WHILE:
        *brk = *cont = 0;
        while(eval_expr(n->w->expr)) {
          run(n->w->body, cont, brk);
          if (*brk) break;
          if (*cont) { *cont = 0; continue; }
        }
        *brk = 0;
        break;
      case ST_IF:
        if (eval_expr(n->i->expr)) {
          run(n->i->body, cont, brk);
        } else if (n->i->elsebody) {
          run(n->i->elsebody, cont, brk);
        }
        break;
    }
    if (*brk || *cont) return;
  }
}

eval_expr() - An expression tree walker

Largely this is the same as the action() function in that we get a left (so long as it is not the left side of an assignment) and right side of the expression (in this case recursively, rather than via a stack,) then perform the operation, returning the result.

int64_t eval_expr(enode_t *e)
{
  int64_t l, r;

  // Don't "evaluate" the lval of an assignment.
  if (e->left && e->op != T_ASSIGN) l = eval_expr(e->left);
  if (e->right) r = eval_expr(e->right);

  switch(e->op) {
    case T_NUMBER:      return e->value;
    case T_IDENTIFIER:  return e->var->value;
    case T_PLUS:        return l + r;
    case T_MINUS:       return l - r;
    case T_MULT:        return l * r;
    case T_DIV:         return l / r;
    case T_MOD:         return l % r;
    case T_OR:          return l || r;
    case T_AND:         return l && r;
    case T_LT:          return l < r;
    case T_GT:          return l > r;
    case T_EQUAL:       return l == r;
    case T_ASSIGN:
      e->left->var->value = r;
      return r;
    default:
      return 0;
  }
  return 0;
}