/*----------------------------------------------------------------------*/ static ast_expression_t *parse_term_op(parse_state_t *p, ast_expression_t *left) { token_t* token; token = peek_token(p); if (token == NULL) { return NULL; } else if (token->type == TK_STAR || token->type == TK_SLASH) { ast_expression_t *right; ast_expression_t *bin_op; ast_expression_t *term_op; next_token(p); right = parse_signed_factor(p); bin_op = ALLOC(sizeof(ast_expression_t)); bin_op->tag = AST_EXPRESSION_BIN_OP; bin_op->u.bin_op.left = left; bin_op->u.bin_op.right = right; bin_op->u.bin_op.operation = token->type; term_op = parse_term_op(p, bin_op); return term_op != NULL ? term_op : bin_op; } else { return NULL; } }
/* * Parse a term. */ static bool parse_term_op(context_t cxt, term_t *val, unsigned priority) { term_t lval; if (!parse_term_head(cxt, &lval)) return false; do { char *op_name = (char *)gc_malloc(TOKEN_MAXLEN+1); token_t tok = token_peek(cxt, NULL, op_name); unsigned op_priority; assoc_t op_assoc; if (!parse_maybe_op(tok) || !binop_lookup(cxt->opinfo, op_name, &op_assoc, &op_priority, NULL, NULL) || op_priority > priority) { *val = lval; gc_free(op_name); return true; } if (op_priority == priority) { switch (op_assoc) { case YFX: *val = lval; return true; case XFY: break; case XFX: parse_error(cxt, "operator `!y%s!d' associativity error", op_name); gc_free(op_name); return false; } } if (!token_expect(cxt, tok)) { gc_free(op_name); return false; } term_t rval; if (!parse_term_op(cxt, &rval, op_priority)) { gc_free(op_name); return false; } atom_t atom = make_atom(gc_strdup(op_name), 2); gc_free(op_name); func_t f = make_func(atom, lval, rval); lval = term_func(f); } while (true); }
/* * Parse a term. */ extern term_t parse_term(const char *filename, size_t *line, opinfo_t opinfo, const char *str, const char **end, varset_t *vars) { struct context_s cxt_0; context_t cxt = &cxt_0; cxt->file = filename; cxt->line = *line; if (vars == NULL) cxt->vars = varset_init(); else cxt->vars = *vars; cxt->opinfo = opinfo; cxt->str = (char *)str; cxt->peeked_token = TOKEN_NONE; cxt->peeked_val = TERM_NIL; term_t val; const char *end0; if (end == NULL) end = &end0; if (token_peek(cxt, NULL, NULL) == TOKEN_END) val = (term_t)NULL; else if (!parse_term_op(cxt, &val, UINT32_MAX)) val = (term_t)NULL; else if (!token_expect(cxt, TOKEN_END)) val = (term_t)NULL; else { if (vars != NULL) *vars = cxt->vars; } *end = cxt->str; *line = cxt->line; return val; }
/*----------------------------------------------------------------------*/ static ast_expression_t *parse_term(parse_state_t *p) { ast_expression_t *left; ast_expression_t *term_op; left = parse_argument(p); term_op = parse_term_op(p, left); return term_op != NULL ? term_op : left; }
/* * Parse a term (no operators). */ static bool parse_term_head(context_t cxt, term_t *val) { char *tokstr = (char *)gc_malloc(TOKEN_MAXLEN+1); term_t tokval; token_t tok = token_get(cxt, &tokval, tokstr); unsigned priority; if (parse_maybe_op(tok) && unop_lookup(cxt->opinfo, tokstr, &priority, NULL)) { term_t lval; if (!parse_term_op(cxt, &lval, priority)) { gc_free(tokstr); return false; } atom_t atom = make_atom(gc_strdup(tokstr), 1); func_t f = make_func(atom, lval); tokval = term_func(f); *val = tokval; gc_free(tokstr); return true; } bool ok = true; term_t *args = NULL; switch ((int)tok) { case '(': if (!parse_term_op(cxt, val, UINT32_MAX) || !token_expect(cxt, ')')) ok = false; break; case TOKEN_NIL: case TOKEN_BOOLEAN: case TOKEN_ATOM: case TOKEN_STRING: case TOKEN_NUMBER: *val = tokval; break; case TOKEN_VARIABLE: { if (token_peek(cxt, NULL, NULL) != '(') { // Really is a variable: *val = tokval; break; } // Otherwise this is a functor: var_t x = var(tokval); atom_t atom = make_atom(x->name, 0); if (!token_expect(cxt, '(')) { ok = false; break; } args = (term_t *)gc_malloc(MAX_ARGS * sizeof(term_t)); uint_t a = 0; if (token_peek(cxt, NULL, NULL) == ')') token_get(cxt, NULL, NULL); else { while (true) { ok = parse_term_op(cxt, &tokval, UINT32_MAX); if (!ok) break; if (a >= MAX_ARGS) { parse_error(cxt, "too many arguments; maximum is %zu", MAX_ARGS); ok = false; break; } args[a++] = tokval; tok = token_get(cxt, NULL, tokstr); if (tok == ',') continue; if (tok == ')') break; parse_error(cxt, "expected token `,' or `)'; got token " "`%s'", tokstr); ok = false; break; } if (!ok) break; } atom = atom_set_arity(atom, a); func_t f = make_func_a(atom, args); tokval = term_func(f); *val = tokval; break; } default: if (tok != TOKEN_ERROR) parse_error(cxt, "unexpected token `%s'", tokstr); ok = false; break; } gc_free(tokstr); gc_free(args); return ok; }