bool lexer_lookahead_matches_special(lexer_state_t* lex, const char* special) { if ( lex->error || lexer_lookahead(lex) == NULL ) return NULL; token_t* token = lexer_lookahead(lex); if ( token->type == special_token ) { return strcmp((char*) token->value, special) == 0; } return false; }
static void parse_actions(struct action_context *ctx) { /* "drop;" by itself is a valid (empty) set of actions, but it can't be * combined with other actions because that doesn't make sense. */ if (ctx->lexer->token.type == LEX_T_ID && !strcmp(ctx->lexer->token.s, "drop") && lexer_lookahead(ctx->lexer) == LEX_T_SEMICOLON) { lexer_get(ctx->lexer); /* Skip "drop". */ lexer_get(ctx->lexer); /* Skip ";". */ if (ctx->lexer->token.type != LEX_T_END) { action_syntax_error(ctx, "expecting end of input"); } return; } while (ctx->lexer->token.type != LEX_T_END) { if (ctx->lexer->token.type != LEX_T_ID) { action_syntax_error(ctx, NULL); break; } enum lex_type lookahead = lexer_lookahead(ctx->lexer); if (lookahead == LEX_T_EQUALS || lookahead == LEX_T_EXCHANGE || lookahead == LEX_T_LSQUARE) { parse_set_action(ctx); } else if (lexer_match_id(ctx->lexer, "next")) { parse_next_action(ctx); } else if (lexer_match_id(ctx->lexer, "output")) { emit_resubmit(ctx, ctx->output_ptable); } else if (lexer_match_id(ctx->lexer, "ip4.ttl")) { if (lexer_match(ctx->lexer, LEX_T_DECREMENT)) { struct expr *e = expr_parse_string("ip4", ctx->symtab, &ctx->error); ctx->prereqs = expr_combine(EXPR_T_AND, ctx->prereqs, e); ofpact_put_DEC_TTL(ctx->ofpacts); } else { action_syntax_error(ctx, "expecting `--'"); } } else if (lexer_match_id(ctx->lexer, "ct_next")) { emit_ct(ctx, true, false); } else if (lexer_match_id(ctx->lexer, "ct_commit")) { emit_ct(ctx, false, true); } else { action_syntax_error(ctx, "expecting action"); } if (!lexer_match(ctx->lexer, LEX_T_SEMICOLON)) { action_syntax_error(ctx, "expecting ';'"); } if (ctx->error) { return; } } }
static bool parse_action(struct action_context *ctx) { if (ctx->lexer->token.type != LEX_T_ID) { action_syntax_error(ctx, NULL); return false; } enum lex_type lookahead = lexer_lookahead(ctx->lexer); if (lookahead == LEX_T_EQUALS || lookahead == LEX_T_EXCHANGE || lookahead == LEX_T_LSQUARE) { parse_set_action(ctx); } else if (lexer_match_id(ctx->lexer, "next")) { parse_next_action(ctx); } else if (lexer_match_id(ctx->lexer, "output")) { emit_resubmit(ctx, ctx->ap->output_ptable); } else if (lexer_match_id(ctx->lexer, "ip.ttl")) { if (lexer_match(ctx->lexer, LEX_T_DECREMENT)) { add_prerequisite(ctx, "ip"); ofpact_put_DEC_TTL(ctx->ofpacts); } else { action_syntax_error(ctx, "expecting `--'"); } } else if (lexer_match_id(ctx->lexer, "ct_next")) { emit_ct(ctx, true, false); } else if (lexer_match_id(ctx->lexer, "ct_commit")) { emit_ct(ctx, false, true); } else { action_syntax_error(ctx, "expecting action"); } if (!lexer_match(ctx->lexer, LEX_T_SEMICOLON)) { action_syntax_error(ctx, "expecting ';'"); } return !ctx->error; }
static struct ast_node *ast_parser_acc_return_statement(struct ast_parser *p) { struct token *tok; struct ast_node *expr; struct ast_node *n = NULL; const struct inplocation_mark *start; tok = lexer_lookahead(parser_lexer(p), 1); if (!tok) { return NULL; } if (tok->type != TOKEN_KW_RETURN) { return NULL; } start = token_get_start(tok); //consume the return keyword lexer_curr_token_advance(parser_lexer(p)); expr = ast_parser_acc_expression(p); if (!expr) { parser_synerr(p, lexer_last_token_end(parser_lexer(p)), NULL, "Expected an expression for the return statement"); goto end; } n = ast_returnstmt_create(start, ast_node_endmark(expr), expr); if (!n) { RF_ERROR("Could not create a return statement during parsing"); } end: return n; }
struct ast_node *parser_acc_fnimpl(struct parser *p) { struct ast_node *n; struct ast_node *decl; struct ast_node *body; struct token *tok; decl = parser_acc_fndecl(p, FNDECL_PARTOF_IMPL); if (!decl) { return NULL; } tok = lexer_lookahead(p->lexer, 1); if (!tok) { goto fail_free_decl; } if (tok->type == TOKEN_SM_OCBRACE) { // normal function body body = parser_acc_block(p, true); if (!body) { parser_synerr(p, ast_node_endmark(decl), NULL, "Expected a body for \""RF_STR_PF_FMT"\" function " "implementation", RF_STR_PF_ARG(ast_fndecl_name_str(decl))); goto fail_free_decl; } } else { // attempt to find a headless match expression as the function body body = parser_acc_matchexpr(p, false, true); if (!body) { parser_synerr(p, ast_node_endmark(decl), NULL, "Expected a body for \""RF_STR_PF_FMT"\" function " "implementation", RF_STR_PF_ARG(ast_fndecl_name_str(decl))); goto fail_free_decl; } // now set the matchexpr's fn_args since this is a headless matchexpr ast_matchexpr_set_fnargs(body, ast_fndecl_args_get(decl)); } n = ast_fnimpl_create(ast_node_startmark(decl), ast_node_endmark(body), decl, body); if (!n) { RF_ERRNOMEM(); ast_node_destroy(body); ast_node_destroy(decl); return NULL; } return n; fail_free_decl: ast_node_destroy(decl); return NULL; }
enum parser_fnimpl_list_err parser_acc_fnimpl_list(struct parser *p, struct ast_node *parent) { struct ast_node *impl; struct token *tok; tok = lexer_lookahead(p->lexer, 1); if (!tok || tok->type != TOKEN_KW_FUNCTION) { return PARSER_FNIMPL_LIST_EMPTY; } while (tok && tok->type == TOKEN_KW_FUNCTION) { impl = parser_acc_fnimpl(p); if (!impl) { return PARSER_FNIMPL_LIST_FAILURE; } ast_node_add_child(parent, impl); tok = lexer_lookahead(p->lexer, 1); } return PARSER_FNIMPL_LIST_SUCCESS; }
enum parser_fndecl_list_err parser_acc_fndecl_list(struct parser *p, struct ast_node *parent, int fndecl_position) { struct ast_node *decl; struct token *tok; tok = lexer_lookahead(p->lexer, 1); if (!tok || tok->type != TOKEN_KW_FUNCTION) { return PARSER_FNDECL_LIST_EMPTY; } while (tok && tok->type == TOKEN_KW_FUNCTION) { decl = parser_acc_fndecl(p, fndecl_position); if (!decl) { return PARSER_FNDECL_LIST_FAILURE; } ast_node_add_child(parent, decl); tok = lexer_lookahead(p->lexer, 1); } return PARSER_FNDECL_LIST_SUCCESS; }
static struct ast_node *ast_parser_acc_expr_statement(struct ast_parser *p) { struct token *tok; struct ast_node *n = NULL; tok = lexer_lookahead(parser_lexer(p), 1); if (TOKEN_IS_BLOCK_START(tok)) { n = ast_parser_acc_block(p, true); } else if (TOKEN_IS_TYPEDECL_START(tok)) { n = ast_parser_acc_typedecl(p); } else if (TOKEN_IS_RETURNSTMT_START(tok)) { n = ast_parser_acc_return_statement(p); } return n; }
static void parse_actions(struct action_context *ctx) { /* "drop;" by itself is a valid (empty) set of actions, but it can't be * combined with other actions because that doesn't make sense. */ if (ctx->lexer->token.type == LEX_T_ID && !strcmp(ctx->lexer->token.s, "drop") && lexer_lookahead(ctx->lexer) == LEX_T_SEMICOLON) { lexer_get(ctx->lexer); /* Skip "drop". */ lexer_get(ctx->lexer); /* Skip ";". */ if (ctx->lexer->token.type != LEX_T_END) { action_syntax_error(ctx, "expecting end of input"); } return; } while (ctx->lexer->token.type != LEX_T_END) { if (!parse_action(ctx)) { return; } } }
bool lexer_lookahead_matches(lexer_state_t* lex, token_types_t tokentype) { if ( lex->error || lexer_lookahead(lex) == NULL ) return NULL; return lexer_lookahead(lex)->type == tokentype; }
struct ast_node *ast_parser_acc_block(struct ast_parser *p, bool expect_braces) { struct ast_node *n; struct token *tok; struct ast_node *element; const struct inplocation_mark *start = NULL; const struct inplocation_mark *end = NULL; lexer_push(parser_lexer(p)); tok = lexer_lookahead(parser_lexer(p), 1); if (!tok) { goto err; } if (expect_braces) { if (tok->type != TOKEN_SM_OCBRACE) { goto err; } // consume '{' lexer_curr_token_advance(parser_lexer(p)); start = token_get_start(tok); } if (!(n = ast_block_create())) { goto err; } //try to parse the first element if (!(element = ast_parser_acc_block_element(p))) { if (!expect_braces) { goto err_free_block; } //else just find the terminating '}' and return tok = lexer_lookahead(parser_lexer(p), 1); if (!tok || tok->type != TOKEN_SM_CCBRACE) { parser_synerr( p, lexer_last_token_end(parser_lexer(p)), NULL, "Expected an expression or a '}' at block end" ); goto err_free_block; } //consume the '}' lexer_curr_token_advance(parser_lexer(p)); ast_node_set_start(n, start); ast_node_set_end(n, token_get_end(tok)); return n; //empty block } if (!start) { start = ast_node_startmark(element); } end = ast_node_endmark(element); ast_block_add_element(n, element); // now add elements to the block while ((element = ast_parser_acc_block_element(p))) { ast_block_add_element(n, element); end = ast_node_endmark(element); } if (expect_braces) { tok = lexer_lookahead(parser_lexer(p), 1); if (!tok || tok->type != TOKEN_SM_CCBRACE) { parser_synerr( p, lexer_last_token_end(parser_lexer(p)), NULL, "Expected an expression or a '}' at block end" ); goto err_free_block; } //consume the '}' lexer_curr_token_advance(parser_lexer(p)); end = token_get_end(tok); } ast_node_set_start(n, start); ast_node_set_end(n, end); lexer_pop(parser_lexer(p)); return n; err_free_block: ast_node_destroy(n); err: lexer_rollback(parser_lexer(p)); return NULL; }
struct ast_node *parser_acc_fncall(struct parser *p, bool expect_it) { struct ast_node *n; struct token *tok; struct ast_node *name; struct ast_node *genr = NULL; struct ast_node *args = NULL; lexer_push(p->lexer); name = parser_acc_identifier(p); if (!name) { goto err; } genr = parser_acc_genrattr(p, false); if (!genr && parser_has_syntax_error(p)) { // name is an identifier and even in failure does not need to get destroyed here goto err; } tok = lexer_lookahead(p->lexer, 1); if (!tok || tok->type != TOKEN_SM_OPAREN) { if (expect_it) { parser_synerr(p, lexer_last_token_start(p->lexer), NULL, "Expected '('"); } goto err_free_genr; } //consume '(' lexer_next_token(p->lexer); args = parser_acc_expression(p); if (!args) { if (parser_has_syntax_error(p)) { parser_synerr(p, lexer_last_token_start(p->lexer), NULL, "Expected argument expression for function call"); goto err_free_genr; } } tok = lexer_lookahead(p->lexer, 1); if (!tok || tok->type != TOKEN_SM_CPAREN) { if (expect_it) { parser_synerr(p, lexer_last_token_end(p->lexer), NULL, "Expected ')' at end of "RF_STR_PF_FMT" function call", RF_STR_PF_ARG(ast_identifier_str(name))); } goto err_free_args; } //consume ')' lexer_next_token(p->lexer); n = ast_fncall_create(ast_node_startmark(name), token_get_end(tok), name, args, genr); if (!n) { RF_ERRNOMEM(); goto err_free_args; } lexer_pop(p->lexer); return n; err_free_args: if (args) { ast_node_destroy(args); } err_free_genr: if (genr) { ast_node_destroy(genr); } err: lexer_rollback(p->lexer); return NULL; }
struct ast_node *parser_acc_fndecl(struct parser *p, int fndecl_position) { struct ast_node *n; struct token *tok; struct token *oparen_tok; struct ast_node *name; struct ast_node *genr = NULL; struct ast_node *args = NULL; struct ast_node *ret_type = NULL; const struct inplocation_mark *start; const struct inplocation_mark *end; lexer_push(p->lexer); tok = lexer_lookahead(p->lexer, 1); if (fndecl_position != FNDECL_PARTOF_FOREIGN_IMPORT) { if (!tok || tok->type != TOKEN_KW_FUNCTION) { goto err; } //consume function keyword lexer_next_token(p->lexer); } // start should be either start of fn, or start of next token (an identifier) start = token_get_start(tok); name = parser_acc_identifier(p); if (!name) { parser_synerr(p, lexer_last_token_start(p->lexer), NULL, "Expected an identifier for the function name after 'fn'"); goto err; } tok = lexer_lookahead(p->lexer, 1); if (GENRDECL_START_COND(tok)) { genr = parser_acc_genrdecl(p); if (!genr) { goto err; } } tok = lexer_next_token(p->lexer); if (!tok || tok->type != TOKEN_SM_OPAREN) { parser_synerr(p, lexer_last_token_start(p->lexer), NULL, "Expected '(' at function declaration"); goto err_free_genr; } oparen_tok = tok; args = parser_acc_typedesc(p); if (!args && parser_has_syntax_error_reset(p)) { parser_synerr(p, token_get_end(tok), NULL, "Expected either a type description for the function's " "arguments or ')' after '('"); goto err_free_genr; } tok = lexer_next_token(p->lexer); if (!tok || tok->type != TOKEN_SM_CPAREN) { if (args) { parser_synerr(p, lexer_last_token_end(p->lexer), NULL, "Expected ')' at function declaration after " "type description"); } else { parser_synerr(p, token_get_end(oparen_tok), NULL, "Expected ')' at function declaration after '('"); } goto err_free_args; } end = token_get_end(tok); tok = lexer_lookahead(p->lexer, 1); if (tok && tok->type == TOKEN_OP_IMPL) { //consume '->' lexer_next_token(p->lexer); ret_type = parser_acc_typedesc(p); if (!ret_type) { parser_synerr(p, token_get_end(tok), NULL, "Expected type description for the function's " "return type after '->'"); goto err_free_args; } end = ast_node_endmark(ret_type); } n = ast_fndecl_create(start, end, fndecl_position, name, genr, args, ret_type); if (!n) { RF_ERRNOMEM(); goto err_free_rettype; } lexer_pop(p->lexer); return n; err_free_rettype: if (ret_type) { ast_node_destroy(ret_type); } err_free_args: if (args) { ast_node_destroy(args); } err_free_genr: if (genr) { ast_node_destroy(genr); } err: lexer_rollback(p->lexer); return NULL; }
struct ast_node *parser_acc_typeinstance(struct parser *p) { struct ast_node *n = NULL; struct token *tok; struct ast_node *class_name; struct ast_node *type_name; struct ast_node *genr = NULL; const struct inplocation_mark *start; enum parser_fnimpl_list_err err; tok = lexer_lookahead(p->lexer, 1); if (!tok || tok->type != TOKEN_KW_TYPEINSTANCE) { return NULL; } start = token_get_start(tok); //consumer typeclass isntance keyword lexer_next_token(p->lexer); class_name = parser_acc_identifier(p); if (!class_name) { parser_synerr(p, lexer_last_token_start(p->lexer), NULL, "Expected an identifier for the typeclass instance " "name after 'instance'"); goto err; } type_name = parser_acc_identifier(p); if (!type_name) { parser_synerr(p, lexer_last_token_start(p->lexer), NULL, "Expected an identifier for the name of \""RF_STR_PF_FMT"\" " "typeclass instance", RF_STR_PF_ARG(ast_identifier_str(class_name))); goto err; } genr = parser_acc_genrdecl(p); if (!genr && parser_has_syntax_error_reset(p)) { parser_synerr(p, ast_node_endmark(type_name), NULL, "Expected a generic declaration for type instance \"" RF_STR_PF_FMT"\" after type name \""RF_STR_PF_FMT"\"", RF_STR_PF_ARG(ast_identifier_str(class_name)), RF_STR_PF_ARG(ast_identifier_str(type_name))); goto err; } tok = lexer_next_token(p->lexer); if (!tok || tok->type != TOKEN_SM_OCBRACE) { parser_synerr(p, ast_node_endmark(type_name), NULL, "Expected '{' at type instance \""RF_STR_PF_FMT"\" " "after \""RF_STR_PF_FMT"\"", RF_STR_PF_ARG(ast_identifier_str(class_name)), RF_STR_PF_ARG(ast_identifier_str(type_name))); goto err_free_genr; } n = ast_typeinstance_create(start, NULL, class_name, type_name, genr); if (!n) { RF_ERRNOMEM(); goto err_free_genr; } err = parser_acc_fnimpl_list(p, n); switch (err) { case PARSER_FNIMPL_LIST_EMPTY: parser_synerr(p, token_get_end(tok), NULL, "Expected at least one function implementation inside " "the body of typeinstace \""RF_STR_PF_FMT"\" for " "\""RF_STR_PF_FMT"\" after'{'", RF_STR_PF_ARG(ast_identifier_str(class_name)), RF_STR_PF_ARG(ast_identifier_str(type_name))); goto err_free_typeinstance; break; case PARSER_FNIMPL_LIST_FAILURE: parser_synerr(p, lexer_last_token_end(p->lexer), NULL, "Expected a proper function implementation inside " "the body of typeinstace \""RF_STR_PF_FMT"\" for " "\""RF_STR_PF_FMT"\" after'{'", RF_STR_PF_ARG(ast_identifier_str(class_name)), RF_STR_PF_ARG(ast_identifier_str(type_name))); goto err_free_typeinstance; break; default: // SUCCESS break; } tok = lexer_next_token(p->lexer); if (!tok || tok->type != TOKEN_SM_CCBRACE) { parser_synerr(p, lexer_last_token_end(p->lexer), NULL, "Expected '}' at the end of \""RF_STR_PF_FMT"\" " "typeinstance for \""RF_STR_PF_FMT"\"", RF_STR_PF_ARG(ast_identifier_str(class_name)), RF_STR_PF_ARG(ast_identifier_str(type_name))); goto err_free_typeinstance; } ast_node_set_end(n, token_get_end(tok)); return n; err_free_genr: if (genr) { ast_node_destroy(genr); } err_free_typeinstance: if (n) { ast_node_destroy(n); } err: return NULL; }
struct ast_node *parser_acc_typeclass(struct parser *p) { struct ast_node *n = NULL; struct token *tok; struct ast_node *name; struct ast_node *genr = NULL; const struct inplocation_mark *start; enum parser_fndecl_list_err err; tok = lexer_lookahead(p->lexer, 1); if (!tok || tok->type != TOKEN_KW_TYPECLASS) { return NULL; } start = token_get_start(tok); lexer_push(p->lexer); //consume typeclass keyword lexer_next_token(p->lexer); name = parser_acc_identifier(p); if (!name) { parser_synerr(p, lexer_last_token_start(p->lexer), NULL, "Expected an identifier for the typeclass " "name after 'class'"); goto err; } genr = parser_acc_genrdecl(p); if (!genr && parser_has_syntax_error_reset(p)) { parser_synerr(p, ast_node_endmark(name), NULL, "Expected a generic declaration for typeclass \"" RF_STR_PF_FMT"\" after identifier", RF_STR_PF_ARG(ast_identifier_str(name))); goto err_free_genr; } tok = lexer_next_token(p->lexer); if (!tok || tok->type != TOKEN_SM_OCBRACE) { parser_synerr(p, ast_node_endmark(name), NULL, "Expected '{' at \""RF_STR_PF_FMT"\" typeclass " "declaration after identifier", RF_STR_PF_ARG(ast_identifier_str(name))); goto err_free_genr; } n = ast_typeclass_create(start, NULL, name, genr); if (!n) { RF_ERRNOMEM(); goto err_free_genr; } err = parser_acc_fndecl_list(p, n, FNDECL_PARTOF_TYPECLASS); switch (err) { case PARSER_FNDECL_LIST_EMPTY: parser_synerr(p, token_get_end(tok), NULL, "Expected at least one function declaration inside " "the body of typeclass \""RF_STR_PF_FMT"\" after '{'", RF_STR_PF_ARG(ast_identifier_str(name))); goto err_free_typeclass; break; case PARSER_FNDECL_LIST_FAILURE: parser_synerr(p, lexer_last_token_end(p->lexer), NULL, "Expected a proper function declaration inside " "typeclass \""RF_STR_PF_FMT"\"", RF_STR_PF_ARG(ast_identifier_str(name))); goto err_free_typeclass; break; default: // SUCCESS break; } tok = lexer_next_token(p->lexer); if (!tok || tok->type != TOKEN_SM_CCBRACE) { parser_synerr(p, lexer_last_token_end(p->lexer), NULL, "Expected '}' at the end of \""RF_STR_PF_FMT"\" " "typeclass declaration", RF_STR_PF_ARG(ast_identifier_str(name))); goto err_free_typeclass; } ast_node_set_end(n, token_get_end(tok)); lexer_pop(p->lexer); return n; err_free_genr: if (genr) { ast_node_destroy(genr); } err_free_typeclass: if (n) { ast_node_destroy(n); } err: lexer_rollback(p->lexer); return NULL; }
struct ast_node *parser_acc_ifexpr(struct parser *p, enum token_type if_type) { struct ast_node *n; struct ast_node *branch; struct token *tok; const struct inplocation_mark *start; RF_ASSERT(if_type == TOKEN_KW_IF || if_type == TOKEN_KW_ELIF, "parse_ifexp called with invalid token type"); tok = lexer_lookahead(p->lexer, 1); if (!tok || tok->type != if_type) { return NULL; } start = token_get_start(tok); // consume 'if' or 'elif' lexer_next_token(p->lexer); lexer_push(p->lexer); // parse the taken branch branch = parser_acc_condbranch(p, tok); if (!branch) { goto err; } // create the if expression n = ast_ifexpr_create(start, ast_node_endmark(branch), branch, NULL); if (!n) { ast_node_destroy(branch); RF_ERRNOMEM(); goto err; } tok = lexer_lookahead(p->lexer, 1); while (tok && (tok->type == TOKEN_KW_ELIF || tok->type == TOKEN_KW_ELSE)) { if (tok->type == TOKEN_KW_ELIF) { branch = parser_acc_ifexpr(p, TOKEN_KW_ELIF); if (!branch) { // error reporting should already happen in parser_acc_ifexpr() goto err_free; } } else { //can only be an else lexer_next_token(p->lexer); // consume it branch = parser_acc_block(p, true); if (!branch) { parser_synerr(p, token_get_end(tok), NULL, "Expected a block after 'else'"); goto err_free; } } ast_ifexpr_add_fallthrough_branch(n, branch); ast_node_set_end(n, ast_node_endmark(branch)); tok = lexer_lookahead(p->lexer, 1); } lexer_pop(p->lexer); return n; err_free: ast_node_destroy(n); err: lexer_rollback(p->lexer); return NULL; }