Example #1
0
// Parse a grouped expression.
//
//    grouped-expr ::= '(' [comma-expr]? ')'s
//
// Note the this is only a grouped expression when the form
// is '(e)' where 'e' is some expression. If the expression
// is of the form '()' or '(e1, ..., en)', then this is a comma
// epxression.
Tree*
parse_grouped_expr(Parser& p) {
  if (const Token* k = parse::accept(p, lparen_tok)) {
    // This is a comma expression.
    if (parse::accept(p, rparen_tok))
      return new Comma_tree(k, new Tree_seq());

    if (Tree* t = parse_expr(p)) {
      // This is a grouped subexpression.
      if (parse::accept(p, rparen_tok)) {
        return t;
      }

      // This is a grouped sub-expression.
      Tree_seq* ts = new Tree_seq {t};
      while (parse::accept(p, comma_tok)) {
        if (Tree* t = parse_expr(p))
          ts->push_back(t);
        else
          return nullptr;
      }

      // Make sure we have a closing rparen.
      if (parse::expect(p, rparen_tok)) {
        return new Comma_tree(k, ts);
      }
    } else {
      parse::parse_error(p) << "expected 'expr' after '('";
    }
  }
  return nullptr;
}
Example #2
0
/* allocate stuff for volterra equations */
void alloc_v_memory(void) {
  int i, len, formula[256], j;

  /* First parse the kernels   since these were deferred */
  for (i = 0; i < NKernel; i++) {
    kernel[i].k_n = 0.0;
    if (parse_expr(kernel[i].expr, formula, &len)) {
      plintf("Illegal kernel %s=%s\n", kernel[i].name, kernel[i].expr);
      exit(0); /* fatal error ... */
    }
    kernel[i].formula = (int *)malloc((len + 2) * sizeof(int));
    for (j = 0; j < len; j++) {

      kernel[i].formula[j] = formula[j];
    }
    if (kernel[i].flag == CONV) {
      if (parse_expr(kernel[i].kerexpr, formula, &len)) {
        plintf("Illegal convolution %s=%s\n", kernel[i].name,
               kernel[i].kerexpr);
        exit(0); /* fatal error ... */
      }
      kernel[i].kerform = (int *)malloc((len + 2) * sizeof(int));
      for (j = 0; j < len; j++) {
        kernel[i].kerform[j] = formula[j];
      }
    }
  }
  allocate_volterra(MaxPoints, 0);
}
Example #3
0
pointer parse_number_or_pair(parser* parse)
{
    char next = (*(parse->curr+1));

    pointer ret_car;
    pointer ret_cdr;

    if(is_whitespace(next))
    {
        parse->curr++;
        return parse_expr(parse);
    }
    else if(next >= '0' && next <= '9')
    {
        ret_car = parse_number(parse);
        ret_cdr = parse_expr(parse);
        return create_pair(ret_car, ret_cdr);
    }
    else
    {
        ret_car = parse_symbol(parse);
        ret_cdr = parse_expr(parse);
        return create_pair(ret_car, ret_cdr);
    }
}
Example #4
0
pointer parse_expr(parser* parse)
{
    eat_whitespace(parse);
    pointer ret_car;
    pointer ret_cdr;
    switch(*parse->curr)
    {
    case '(':
        parse->curr++;
        ret_car = parse_expr(parse);
        ret_cdr = parse_expr(parse);
        return create_pair(ret_car, ret_cdr);
    case '"':
        ret_car = parse_string(parse);
        ret_cdr = parse_expr(parse);
        return create_pair(ret_car, ret_cdr);
    case '\'':
        parse->curr++;
        ret_car = parse_quote(parse);
        ret_cdr = parse_expr(parse);
        return create_pair(ret_car, ret_cdr);
    case ')':
        parse->curr++;
        return NIL;
    case '+': case '-': case 'b':
        ret_car = parse_number_or_symbol(parse);
        ret_cdr = parse_expr(parse);
        return create_pair(ret_car, ret_cdr);
    case '.':
        return parse_number_or_pair(parse);
    case '\\':
        parse->curr++;
        ret_car = create_char(*(parse->curr++));
        ret_cdr = parse_expr(parse);
        return create_pair(ret_car, ret_cdr);
    case ';':
        while(!is_newline(*parse->curr) && *parse->curr != '\0')
            parse->curr++;
        return parse_expr(parse);
    case 0:
        return NIL;
    default:
        if(is_number_char(*parse->curr))
        {
            ret_car = parse_number(parse);
            ret_cdr = parse_expr(parse);
            return create_pair(ret_car, ret_cdr);
        }
        else if(is_symbol_char(*parse->curr))
        {
            ret_car = parse_symbol(parse);
            ret_cdr = parse_expr(parse);
            return create_pair(ret_car, ret_cdr);
        }
        else
            return parser_error(parse, "Unexpected char in expression.");

    }
    parse->curr++;
}
Example #5
0
File: cpu.c Project: ezrec/vasm
/* Does not do much useful parsing yet. */
int parse_operand(char *p,int len,operand *op,int requires)
{
  p=skip(p);
  if(len==2&&(p[0]=='r'||p[0]=='R')&&p[1]>='0'&&p[1]<='3'){
    op->type=OP_REG;
    op->basereg=p[1]-'0';
  }else if(p[0]=='#'){
    op->type=OP_IMM32;
    p=skip(p+1);
    op->offset=parse_expr(&p);
  }else{
    int parent=0;
    expr *tree;
    op->type=-1;
    if(*p=='('){
      parent=1;
      p=skip(p+1);
    }
    tree=parse_expr(&p);
    if(!tree)
      return 0;
    p=skip(p);
    if(parent){
      if(*p==','){
	p=skip(p+1);
	if((*p!='r'&&*p!='R')||p[1]<'0'||p[1]>'3'){
	  cpu_error(0);
	  return 0;
	}
	op->type=OP_REGIND;
	op->basereg=p[1]-'0';
	p=skip(p+2);
      }
      if(*p!=')'){
	cpu_error(0);
	return 0;
      }else
	p=skip(p+1);
    }
    if(op->type!=OP_REGIND)
      op->type=OP_ABS;
    op->offset=tree;
  }
  if(requires==op->type)
    return 1;
  if(requires==OP_ALL_DEST&&op->type!=OP_IMM32)
    return 1;
  if(requires==OP_MEM&&OP_ISMEM(op->type))
    return 1;
  if(requires==OP_ALL)
    return 1;
  return 0;
}
Example #6
0
expr_list_t parse_arg_expr_list(tokenizer_t t) {
    expr_list_t l = mk_expr_list();
    expr_t x;
    if(cur_tok(t).kind != TOK_RPAREN) {
        x = parse_expr(t);
        expr_list_add(l, x);
        while(cur_tok(t).kind != TOK_RPAREN) {
            eat_it(t, TOK_COMMA);
            x = parse_expr(t);
            expr_list_add(l, x);
        }
    }
    return l;
}
Example #7
0
/*
parse_bool

Matches a valid boolean expression by looking ahead one token

Parameters: none

Return: none
*/
void parse_bool(Tree &cst){
	cst.add_branch_node("boolean");
	if(!(curr_token -> type).compare("open_paren")){
		match_type("open_paren", cst);
		parse_expr(cst);
		match(boolop, cst);
		parse_expr(cst);
		match(")", cst);
	}
	else{
		match(boolval, cst);
	}
	cst.kill_all_children();
}
Example #8
0
/** Parse @c switch statement.
 *
 * @param parse		Parser object.
 * @return		New syntax tree node.
 */
static stree_switch_t *parse_switch(parse_t *parse)
{
	stree_switch_t *switch_s;
	stree_when_t *when_c;
	stree_expr_t *expr;

#ifdef DEBUG_PARSE_TRACE
	printf("Parse 'switch' statement.\n");
#endif
	lmatch(parse, lc_switch);

	switch_s = stree_switch_new();
	list_init(&switch_s->when_clauses);

	switch_s->expr = parse_expr(parse);
	lmatch(parse, lc_is);

	/* Parse @c when clauses. */
	while (lcur_lc(parse) == lc_when) {
		lskip(parse);
		when_c = stree_when_new();
		list_init(&when_c->exprs);
		while (b_true) {
			expr = parse_expr(parse);
			list_append(&when_c->exprs, expr);
			if (lcur_lc(parse) != lc_comma)
				break;
			lskip(parse);
		}

		lmatch(parse, lc_do);
		when_c->block = parse_block(parse);

		list_append(&switch_s->when_clauses, when_c);
	}

	/* Parse @c else clause. */
	if (lcur_lc(parse) == lc_else) {
		lskip(parse);
		lmatch(parse, lc_do);
		switch_s->else_block = parse_block(parse);
	} else {
		switch_s->else_block = NULL;
	}

	lmatch(parse, lc_end);
	return switch_s;
}
/******************************************************************************
    num_op := num rest_num_op
              ( expr ) rest_num_op
 *****************************************************************************/
void
parse_num_op( val_t* val )
{
    printtab();
    dprintf("parse_num_op()\n");
    level++;

    if ( match_num( val ) ) {
        parse_rest_num_op( val );
    } else if ( match_variable( val ) ) {
        resolve_variable( val );
        parse_rest_num_op( val );
    } else if ( match_char( '(' ) ) {
        parse_expr( val );
        if ( !match_char( ')' ) ) {
            buffer[bpos] = 0;
            printf("Missing bracket: %s\n", buffer);
            longjmp( env, 1 );
        }
        parse_rest_num_op( val );
    } else {
        buffer[bpos] = 0;
        printf("Parse error: %s\n", buffer);
        longjmp( env, 1 );
    }
    
    level--;

    return;
}
Example #10
0
static variable_t*
parse_keyvalue(char **ptr, group_t *head) {
    char *p = *ptr;
    char name[MAXIDLEN];
    variable_t* var;

    parse_identifier(&p, name, sizeof(name));

    skip_whitespace(&p);
    if (*p != '=') {
        fprintf(stderr, "%s:%d: No assignment detected!\n", __func__, lineno);
        return NULL;
    } else {
        p++;
    }
    skip_whitespace(&p);

    /* create variable, assume string */
    var = new_variable(name, VT_STRING);
    /* parse value of variable */
    parse_expr(&p, var, head);

    *ptr = p;
    return var;
}
Example #11
0
File: parser.c Project: gnar/zombo
/*
 * let <id>
 * let <id> = <expr>
 * let <id1>, <id2>
 * let <id1> = <expr1>, <id2>, <id3> = <expr3>
 */
static ASTNode *parse_let_expression(Parser *p)
{
	expect(p, TOK_LET, "expected let-expresssion to begin with 'let' keyword");
	
	int have_comma = 1;
	while (peek_id(p) == TOK_IDENTIFIER) {
		
		/* get identifier */
		char *ident = strdup(peek(p)->sval); accept(p);
		
		/* optional init expression */
		ASTNode *init = NULL;
		if (peek_id(p) == TOK_ASSIGN) {
			accept(p);
			init = parse_expr(p);
		}

		/* parse body */
		ASTNode *body = NULL;
		

		free(ident);
		
		if (peek_id(p) == TOK_COMMA) {
			have_comma = 1;
			accept(p);
		} else {
			have_comma = 0;
		}
	}
}
Example #12
0
int main(int argc,char **argv) {
    struct postfix_expr_t expr;
    signed long val;

    if (argc < 2) {
        fprintf(stderr,"Please enter an expression in argv[1]\n");
        return 1;
    }

    if (parse_expr(&expr,argv[1]) < 0) {
        fprintf(stderr,"Failure to parse\n");
        return 1;
    }

    print_expr(&expr);
    printf("\n");

    val = eval_expr(&expr);
    if (val == LONG_MAX) {
        fprintf(stderr,"Failure to eval\n");
        return 1;
    }
    printf("result = %ld\n",val);

    return 0;
}
Example #13
0
stmt_t parse_stmt_return(tokenizer_t t)
{
    eat_it(t, TOK_RETURN);
    expr_t e = parse_expr(t);
    eat_it(t, TOK_SEMICOLON);
    return mk_stmt_return(t->filename, t->line, e);
}
Example #14
0
bool parser::parse_list(utf8str::iterator& it, utf8str::iterator& it_end, shared_ptr<expr>& result)
{
	if (it != it_end)
	{
		uint32_t ch = utf8::peek_next(it, it_end);		
		if (ch == '(')
		{
			utf8::unchecked::next(it);
			vector<shared_ptr<expr> > list;
			shared_ptr<expr> innerExpr;
			bool exprParseRes = true;
			while (exprParseRes)
			{
				exprParseRes = parse_expr(it, it_end, innerExpr);
				if (exprParseRes)
				{
					list.push_back(innerExpr);
					innerExpr.reset();
				}
			}
			skip_whitespaces(it, it_end);
			expect(')', it, it_end);
			result = shared_ptr<expr>(new expr(list));
			return true;			
		}
		else
		{			
			return false;
		}
	}
	return false;
}
Example #15
0
    PExprAST
    Parser::parse_identifier_expr()
    {
        std::string identifier = lex.get_last_token_value<std::string>();
        get_next_token(); // eat identifier

        //If it's a simple identifier
        if (current_tok != Token::StartArg)
            return PExprAST(new VariableExprAST(identifier));

        //It's a function call :
        get_next_token(); // eat '<'
        std::vector<PExprAST> args;

        if (current_tok != Token::EndArg)
            while (true)
            {
                PExprAST expr = parse_expr();

                if (current_tok == Token::EndArg)
                    break;

                if (current_tok != Token::ArgSep)
                    throw ParserException(ParserExceptionType::ExpectedEndOfArg);
                get_next_token(); // eat ','
            }
        get_next_token(); // eat '>'

        return PExprAST(new CallExprAST(identifier, args));
    }
Example #16
0
    PExprAST
    Parser::parse_function()
    {
        get_next_token(); // eat the Define token

        if (!is_type(current_tok))
            throw ParserException(ParserExceptionType::ExpectedType);

        PPrototypeAST prototype = parse_prototype();

        if (current_tok != Token::StartContent)
            throw ParserException(ParserExceptionType::ExpectedStartContent);
        get_next_token(); // eat '['

        InstList imp;
        while (current_tok != Token::EndContent)
        {
            PExprAST inst = parse_expr();

            if (current_tok != Token::EndInstr)
                throw ParserException(ParserExceptionType::ExpectedEndOfInstr);
            get_next_token(); // eat ':'

            imp.push_back(inst);
        }
        get_next_token(); // eat ']'

        return PExprAST(new FunctionAST(prototype, imp));
    }
Example #17
0
static int parse_function_args(ExprParseState *state)
{
  if (!parse_next_token(state) || state->token != '(' || !parse_next_token(state)) {
    return -1;
  }

  int arg_count = 0;

  for (;;) {
    if (!parse_expr(state)) {
      return -1;
    }

    arg_count++;

    switch (state->token) {
      case ',':
        if (!parse_next_token(state)) {
          return -1;
        }
        break;

      case ')':
        if (!parse_next_token(state)) {
          return -1;
        }
        return arg_count;

      default:
        return -1;
    }
  }
}
Example #18
0
/*
parse_assignment

Matches a valid assignment

Parameters: none

Return: none
*/
void parse_assingment(Tree &cst){
	cst.add_branch_node("assignment");
	parse_identifier(cst);
	match("=", cst);
	parse_expr(cst);
	cst.kill_all_children();
}
Example #19
0
static RegExp *
parse_primary(void)
{
    RegExp *e;
    switch (curtok) {
	case ID:
	    if (!yylval.symbol->re)
		Scanner_fatal(in, "can't find symbol");
	    e = yylval.symbol->re;
	    get_next_token();
	    break;
	case RANGE:
	case STRING:
	    e = yylval.regexp;
	    get_next_token();
	    break;
	case '(':
	    get_next_token();
	    e = parse_expr();
	    if (curtok != ')')
		Scanner_fatal(in, "missing closing parenthesis");
	    get_next_token();
	    break;
	default:
	    return NULL;
    }
    return e;
}
Example #20
0
/** Parse variable declaration statement.
 *
 * @param parse		Parser object.
 * @return		New syntax tree node.
 */
static stree_vdecl_t *parse_vdecl(parse_t *parse)
{
	stree_vdecl_t *vdecl;

	vdecl = stree_vdecl_new();

	lmatch(parse, lc_var);
	vdecl->name = parse_ident(parse);
	lmatch(parse, lc_colon);
	vdecl->type = parse_texpr(parse);

	if (lcur_lc(parse) == lc_assign) {
		lskip(parse);
		(void) parse_expr(parse);
	}

	lmatch(parse, lc_scolon);

#ifdef DEBUG_PARSE_TRACE
	printf("Parsed vdecl for '%s'\n", strtab_get_str(vdecl->name->sid));
	printf("vdecl = %p, vdecl->name = %p, sid=%d\n",
	    vdecl, vdecl->name, vdecl->name->sid);
#endif
	return vdecl;
}
Example #21
0
// Parse Join.
// stm t1 join t2
Tree*
parse_join(Parser& p, Tree* t1) {
    if(const Token* s = parse::accept(p, join_tok)) {
      if(Tree* t2 = parse_expr(p))
        if(parse::expect(p, on_tok)) 
          if(Tree* t3 = parse_expr(p))
            return new Join_on_tree(s,t1,t2,t3);
          else
            parse::parse_error(p) << "expected 'expr' after 'on'";
        else
          parse::parse_error(p) << "expected 'expr' after 'join'"; 
      else
        parse::parse_error(p) << "expected 'expr' before 'join'"; 
    }
    return nullptr;
}
Example #22
0
File: parser.c Project: gnar/zombo
static ASTNode *parse_body(Parser *p, int start_token, int end_token, int end_token2)
{
	ASTNode **stmts = NULL; 
	int num_stmts = 0; 
	int have_eol;

	/* parse start token */
	if (start_token != -1) {
		expect(p, start_token, "expected other token at begin of body expression");
		ignore_eols(p);
	}

	/* every expression (except the last one) must be terminated by an TOK_END_OF_LINE. */
	have_eol = 1;
	while (peek_id(p) != end_token && peek_id(p) != end_token2) {
		if (!have_eol) {
			error(p, "statement must be terminated by a new line");
		}

		stmts = (ASTNode**)realloc(stmts, sizeof(ASTNode*) * (num_stmts+1));
		stmts[num_stmts++] = parse_expr(p);

		have_eol = (peek_id(p) == TOK_END_OF_LINE);
		ignore_eols(p);
	}

	accept(p); /* either end_token or end_token2 */

	return ast_create_body(num_stmts, stmts);
}
Example #23
0
expr_t parse_paren_expr(tokenizer_t t)
{
  eat_it(t, TOK_LPAREN);
  expr_t expr = parse_expr(t);
  eat_it(t, TOK_RPAREN);
  return mk_expr_paren(t->filename, t->line, expr);
}
Example #24
0
static int parse_primary (pfstate_t *pf)
{
	int result;

	if (pf->token_type == TOKEN_LPAREN) {

	  next_token (pf);
	  result = parse_expr (pf);
	  	  
	  if (pf->token_type == TOKEN_RPAREN) {
	    next_token (pf);
	  }
	  else {
	    print_error (pf, "Expected \")\" here.\n");
	    result = -1;
	  }
	}
	else if (pf->token_type == TOKEN_NOT) {
	  int e;

	  next_token (pf);
	  e = parse_primary (pf);
	  if (e < 0) result = -1;
	  else result = ! e;
	}
	else if (pf->token_type == TOKEN_FILTER_SPEC) {
	  result = parse_filter_spec (pf);
	}
	else {
	  print_error (pf, "Expected filter specification, (, or ! here.");
	  result = -1;
	}

	return (result);
}
Example #25
0
File: peg.c Project: ctelfer/catlib
static int parse_paren_expr(struct peg_grammar_parser *pgp,
			    struct peg_cursor *pc, int *exprp)
{
	int rv;
	struct peg_cursor npc = *pc;
	int expr = -1;

	if ( !string_match(pgp, "(", &npc) )
		return 0;

	rv = parse_expr(pgp, &npc, &expr);
	if ( rv < 0 )
		return -1;
	if ( rv == 0 )
		goto err;
	if ( !string_match(pgp, ")", &npc) )
		goto err;

	*pc = npc;
	*exprp = expr;
	return 1;

err:
	peg_node_free(pgp->peg, expr);
	pgp->err = PEG_ERR_BAD_PAREXPR;
	pgp->eloc = npc;
	return -1;
}
Example #26
0
void parse_ifClause() {
    expression_t expr;
    size_t conv_expr;
    size_t jc_addr;
    size_t jmp_addr;
    size_t stack_frame;
    bool jmp_used = true;
    switch(next_token.type) {
        case TT_KW_IF:
            match(TT_KW_IF);
            match(TT_PARENTHESES_OPEN);
            expr = parse_expr();
            match(TT_PARENTHESES_CLOSE);
            jc_addr = get_code_seg_top();
            switch (expr.type) {
                case DOUBLE_LIT_DT:
                    if(!((int)expr.double_val))
                        generate_jump(0); //address is unknown yet
                    else
                        jmp_used = false;
                    break;
                case INT_LIT_DT:
                    if(!expr.int_val)
                        generate_jump(0); //address is unknown yet
                    else
                        jmp_used = false;
                    break;
                case DOUBLE_DT:
                    conv_expr = generate_double_to_int(expr.addr);
                    generate_neg_cond_jump(0, conv_expr); //address is unknown yet
                    break;
                case INT_DT:
                    generate_neg_cond_jump(0, expr.addr); //address is unknown yet
                    break;
                case STRING_LIT_DT:
                case STRING_DT:
                    error("String value in a if statement", ERROR_TYPE_COMPAT);
                    break;
                default:
                    ;
            }
            stack_frame = store_stack_frame();
            parse_block(true);
            load_stack_frame(stack_frame);
            generate_data_seg_restore(stack_frame);
            jmp_addr = get_code_seg_top();
            generate_jump(0); //address is unknown yet
            if (jmp_used)
                set_jump_addr(jc_addr, get_code_seg_top());
            match(TT_KW_ELSE);
            stack_frame = store_stack_frame();
            parse_block(true);
            load_stack_frame(stack_frame);
            generate_data_seg_restore(stack_frame);
            set_jump_addr(jmp_addr, get_code_seg_top());
            break;
        default:
            error("Syntactic error: Failed to parse the program", ERROR_SYN);
    }
}
Example #27
0
Statements::Statements() {
    while (1) {
        switch (lookahead(0).tok) {
        case tok_identifier:
            if (lookahead(1).tok == tok_identifier) {
                if (lookahead(2).tok == tok_punc_lparen) {
                    funcs.push_back(new Func_def());
                } else {
                    vars.push_back(new Var_def());
                }
            } else {
            case tok_const_num:
            case tok_const_str:
                stmts.push_back(parse_expr());
            }
            break;
        case tok_kw_if:
            stmts.push_back(new If_block());
            break;
        case tok_kw_while:
            stmts.push_back(new While_block());
            break;
        case tok_kw_return:
            stmts.push_back(new Return_inst());
            break;
        default:
            goto _out;
        }
    }
_out:
    return;
};
Example #28
0
AVEvalExpr * ff_parse(const char *s, const char **const_name,
               double (**func1)(void *, double), const char **func1_name,
               double (**func2)(void *, double, double), char **func2_name,
               const char **error){
    Parser p;
    AVEvalExpr * e;
//    char w[strlen(s) + 1], * wp = w;
	char *w = (char *)malloc((strlen(s) + 1) * sizeof(char));
    char *wp;
	wp = w;
	while (*s)
        if (!isspace(*s++)) *wp++ = s[-1];
    *wp++ = 0;

    p.stack_index=100;
    p.s= w;
    p.const_name = const_name;
    p.func1      = func1;
    p.func1_name = func1_name;
    p.func2      = func2;
    p.func2_name = func2_name;
    p.error= error;

    e = parse_expr(&p);
    if (!verify_expr(e)) {
        ff_eval_free(e);
        return NULL;
    }
    return e;
}
Example #29
0
static Value parse_factor (Context *s) {
    Value v = s->token_value;
    switch (s->token) {
    case '0':
        next (s);
        return v;
    case '-':
        next (s);
        return -parse_factor (s);
    case 'c':
        next (s);
        return s->col;
    case 'r':
        next (s);
        return s->row;
    case '(':
        next (s);
        v = parse_expr (s, 0);
        if (s->token != ')')
            complain (s, "Syntax error: expected ')'");
        next (s);
        return v;
    default:
        complain (s, "Syntax error: expected a factor");
        next (s);
        return 0;
    }
}
Example #30
0
// Parse paren enclosed expressions
// error if no matching beginning and ending paren
Expr*
parse_paren_enclosed(Parser& p, Token_stream& ts)
{
  if (ts.expect(lparen_tok)) {
    // in_paren_enclosed = true;
    if (Expr* e = parse_expr(p, ts)) {
      if (ts.expect(rparen_tok)) {
        // in_paren_enclosed = false;
        return e;
      }
      // expected r paren fail
      else {
        error("Expected ')' after ");
        print(e);
        print("\n");
        return nullptr;
      }
    }
    // no expression after (
    else {
      error("Expected expression after '('");
    }
  }

  return nullptr;
}