ast_t* ast_from(ast_t* ast, token_id id) { assert(ast != NULL); ast_t* new_ast = ast_token(token_dup_new_id(ast->t, id)); set_scope_no_parent(new_ast, ast->parent); return new_ast; }
static ast_t* duplicate(ast_t* parent, ast_t* ast) { if(ast == NULL) return NULL; assert(ast_id(ast) != TK_PROGRAM && ast_id(ast) != TK_PACKAGE && ast_id(ast) != TK_MODULE); ast_t* n = ast_token(token_dup(ast->t)); n->data = ast->data; n->flags = ast->flags & AST_ALL_FLAGS; // We don't actually want to copy the orphan flag, but the following if // always explicitly sets or clears it. if(parent == NULL) set_scope_no_parent(n, ast->parent); else set_scope_and_parent(n, parent); n->child = duplicate(n, ast->child); n->type = duplicate(n, ast->type); if(ast->symtab != NULL) n->symtab = symtab_dup(ast->symtab); if(parent != NULL) n->sibling = duplicate(parent, ast->sibling); return n; }
/* Load an ID node. * IDs are indicated by the keyword id followed by the ID name, all contained * within parentheses. For example: * (id foo) * * The ( and id keyword must have been parsed before this is called. */ static ast_t* get_id(build_parser_t* builder, ast_t* existing_ast) { assert(builder != NULL); if(existing_ast != NULL) { ast_free(existing_ast); build_error(builder, "Seen ID not first in node"); return NULL; } ast_token_id id = get_token(builder); if(id != AT_ID && id != AT_STRING) { build_error(builder, "ID name expected"); return NULL; } ast_t* ast = ast_token(builder->token); ast_setid(ast, TK_ID); save_token(builder); if(get_token(builder) != AT_RPAREN) { build_error(builder, "Close paren expected for ID"); ast_free(ast); return NULL; } return ast; }
static ast_t* consume_token(parser_t* parser) { ast_t* ast = ast_token(parser->token); ast_setflag(ast, parser->next_flags); parser->next_flags = 0; fetch_next_lexer_token(parser, false); return ast; }
ast_t* ast_from_float(ast_t* ast, double value) { assert(ast != NULL); token_t* t = token_dup(ast->t); token_set_id(t, TK_FLOAT); token_set_float(t, value); ast_t* new_ast = ast_token(t); set_scope_no_parent(new_ast, ast->parent); return new_ast; }
ast_t* ast_from_int(ast_t* ast, uint64_t value) { assert(ast != NULL); token_t* t = token_dup(ast->t); token_set_id(t, TK_INT); lexint_t lexint = {value, 0}; token_set_int(t, &lexint); ast_t* new_ast = ast_token(t); set_scope_no_parent(new_ast, ast->parent); return new_ast; }
ast_t* ast_from_string(ast_t* ast, const char* name) { if(name == NULL) return ast_from(ast, TK_NONE); token_t* t = token_dup(ast->t); token_set_id(t, TK_ID); token_set_string(t, name, 0); ast_t* new_ast = ast_token(t); set_scope_no_parent(new_ast, ast->parent); return new_ast; }
// Process any deferred token we have static void process_deferred_ast(parser_t* parser, rule_state_t* state) { assert(parser != NULL); assert(state != NULL); if(state->deferred) { token_t* deferred_token = token_new(state->deferred_id); token_set_pos(deferred_token, parser->source, state->line, state->pos); state->ast = ast_token(deferred_token); state->deferred = false; } }
ast_t* ast_blank(token_id id) { return ast_token(token_new(id)); }
ast_t* ast_new(token_t* t, token_id id) { return ast_token(token_dup_new_id(t, id)); }
// Load a sequence of nodes until the specified terminator is found static ast_t* get_nodes(build_parser_t* builder, ast_token_id terminator) { assert(builder != NULL); ast_t* ast = NULL; ast_t* last_child = NULL; while(true) { ast_token_id id = get_token(builder); ast_t* child = NULL; bool is_type = false; if(id == terminator) { if(ast == NULL) build_error(builder, "Syntax error"); if(ast_id(ast) == TK_MINUS && ast_childcount(ast) == 1) ast_setid(ast, TK_UNARY_MINUS); return ast; } if(id == AT_ID) id = keyword_replace(builder); switch(id) { case AT_LPAREN: child = get_nodes(builder, AT_RPAREN); break; case AT_LSQUARE: child = get_type(builder, ast); is_type = true; break; case AT_ERROR: // Propogate break; case AT_STRING: case AT_TOKEN: child = ast_token(builder->token); save_token(builder); get_attributes(builder, child); break; case AT_ID: if(strcmp("id", token_string(builder->token)) == 0) return get_id(builder, ast); build_error(builder, "Unrecognised identifier \"%s\"", token_string(builder->token)); break; default: build_error(builder, "Syntax error"); break; } if(child == NULL) { // An error occurred and should already have been reported ast_free(ast); return NULL; } if(ast == NULL) { ast = child; last_child = NULL; } else if(is_type) { ast_settype(ast, child); } else { if(last_child == NULL) ast_add(ast, child); else ast_add_sibling(last_child, child); last_child = child; } } }