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 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 void parse_next_action(struct action_context *ctx) { if (!ctx->n_tables) { action_error(ctx, "\"next\" action not allowed here."); } else if (lexer_match(ctx->lexer, LEX_T_LPAREN)) { int ltable; if (!action_get_int(ctx, <able)) { return; } if (!lexer_match(ctx->lexer, LEX_T_RPAREN)) { action_syntax_error(ctx, "expecting `)'"); return; } if (ltable >= ctx->n_tables) { action_error(ctx, "\"next\" argument must be in range 0 to %d.", ctx->n_tables - 1); return; } emit_resubmit(ctx, ctx->first_ptable + ltable); } else { if (ctx->cur_ltable < ctx->n_tables) { emit_resubmit(ctx, ctx->first_ptable + ctx->cur_ltable + 1); } else { action_error(ctx, "\"next\" action not allowed in last table."); } } }
static bool action_get_int(struct action_context *ctx, int *value) { bool ok = lexer_get_int(ctx->lexer, value); if (!ok) { action_syntax_error(ctx, "expecting small integer"); } return ok; }
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; } } }