#include "ctx.h" #include "interface.h" #include "lex.h" #include "msg.h" #include #define report_error(...) fprintf(stderr, __VA_ARGS__) static bool peek_keyword(struct lex *lex, enum token_keyword kw) { struct token *tok = lex_peek(lex); return (tok && tok->tok_type == TOK_KEYWORD && tok->tok_kw == kw); } static bool parse_keyword(struct lex *lex, enum token_keyword kw) { struct token *tok = lex_peek(lex); if (!tok || tok->tok_type != TOK_KEYWORD || tok->tok_kw != kw) { return false; } lex_advance(lex); return true; } static bool parse_symbol(struct lex *lex, enum token_symbol sym) { struct token *tok = lex_peek(lex); if (!tok || tok->tok_type != TOK_SYMBOL || tok->tok_sym != sym) { return false; } lex_advance(lex); return true; } static bool parse_word(struct lex *lex, char **out) { struct token *tok = lex_peek(lex); if (!tok || tok->tok_type != TOK_WORD) { return false; } *out = tok->tok_str; tok->tok_str = NULL; lex_advance(lex); return true; } struct msg_definition *parse_msg_definition(struct ctx *ctx, struct lex *lex) { struct msg_definition *msg = NULL; if (!parse_keyword(lex, KW_MSG)) { report_error("expected `msg` keyword\n"); goto fail; } char *msg_name = NULL; if (!parse_word(lex, &msg_name)) { report_error("expected message identifier\n"); goto fail; } msg = msg_definition_create(msg_name); free(msg_name); if (!parse_symbol(lex, SYM_LEFT_PAREN)) { report_error("expected `(` after message identifier\n"); goto fail; } size_t i = 0; bool ok = true; while (ok) { if (parse_symbol(lex, SYM_RIGHT_PAREN)) { break; } if (i > 0 && !parse_symbol(lex, SYM_COMMA)) { report_error("expected `,` after message parameter\n"); ok = false; break; } char *type_name; if (!parse_word(lex, &type_name)) { report_error("expected message parameter type\n"); ok = false; break; } const struct type *type = ctx_get_type(ctx, type_name); if (!type) { report_error( "message parameter has unknown type " "'%s'\n", type_name); free(type_name); ok = false; break; } free(type_name); char *param_name; if (!parse_word(lex, ¶m_name)) { report_error("expected message parameter name\n"); ok = false; break; } bool duplicate = msg_definition_has_param(msg, param_name) || msg_definition_has_result(msg, param_name); if (duplicate) { free(param_name); report_error( "message has multiple parameters/results with " "name '%s'\n", param_name); ok = false; break; } msg_definition_add_param(msg, type, param_name); free(param_name); i++; } if (!ok) { goto fail; } if (!parse_symbol(lex, SYM_HYPHEN_RIGHT_ANGLE)) { report_error("expected `->` after message parameter list\n"); goto fail; } if (!parse_symbol(lex, SYM_LEFT_PAREN)) { report_error("expected `(` for message results list\n"); goto fail; } i = 0; while (ok) { if (parse_symbol(lex, SYM_RIGHT_PAREN)) { break; } if (i > 0 && !parse_symbol(lex, SYM_COMMA)) { report_error( "expected `,` or `)` after message result\n"); ok = false; break; } char *type_name; if (!parse_word(lex, &type_name)) { report_error("expected message result type\n"); ok = false; break; } const struct type *type = ctx_get_type(ctx, type_name); if (!type) { report_error( "message result has unknown type " "'%s'\n", type_name); free(type_name); ok = false; break; } free(type_name); char *result_name; if (!parse_word(lex, &result_name)) { report_error("expected message parameter name\n"); ok = false; break; } bool duplicate = msg_definition_has_param(msg, result_name) || msg_definition_has_result(msg, result_name); if (duplicate) { report_error( "message has multiple parameters/results with " "name '%s'\n", result_name); free(result_name); ok = false; break; } msg_definition_add_result(msg, type, result_name); free(result_name); } if (!parse_symbol(lex, SYM_SEMICOLON)) { report_error("expected `;` after message definition\n"); goto fail; } return msg; fail: if (msg) { msg_definition_destroy(msg); } return NULL; } struct interface_definition *parse_interface_definition( struct ctx *ctx, struct lex *lex) { struct interface_definition *iface = NULL; if (!parse_keyword(lex, KW_INTERFACE)) { report_error("expected `interface` keyword"); goto fail; } char *if_name = NULL; if (!parse_word(lex, &if_name)) { report_error("expected interface identifier"); goto fail; } iface = interface_definition_create(if_name); free(if_name); if (!iface) { goto fail; } if (!parse_symbol(lex, SYM_LEFT_BRACE)) { report_error("expected `{` after interface identifier"); goto fail; } bool ok = true; while (ok) { if (parse_symbol(lex, SYM_RIGHT_BRACE)) { break; } if (peek_keyword(lex, KW_MSG)) { struct msg_definition *msg = parse_msg_definition(ctx, lex); if (!msg) { ok = false; break; } if (interface_definition_has_msg( iface, msg->msg_name)) { msg_definition_destroy(msg); ok = false; break; } interface_definition_add_msg(iface, msg); continue; } report_error("expected `}` or message definition\n"); ok = false; break; } if (!ok) { goto fail; } return iface; fail: if (iface) { interface_definition_destroy(iface); } return NULL; }