/* * Copyright (c) 2026, Apollo Telephone Laboratories. * Provided under the BSD-3 clause. */ #include "defconf/parser.h" #include "defconf/lexer.h" #include "defconf/token.h" #include "defconf/data.h" #include "defconf/emit.h" #include "defconf/trace.h" /* Symbolic token */ #define SYMTOK(TOKSTR) \ "[" TOKSTR "]" /* Literal token */ #define TOKLIT(TOKSTR) \ "'" TOKSTR "'" /* Safe macro to convert token type to string */ #define TOKSTR(TT) \ ((TT) >= _TT_MAX) \ ? "bad" \ : toktab[(TT)] /* Token to string table */ static const char *toktab[_TT_MAX] = { [TT_NONE] = SYMTOK("none"), [TT_DEFINE] = SYMTOK("define"), [TT_TRUE] = TOKLIT("true"), [TT_FALSE] = TOKLIT("false"), [TT_INTLIT] = SYMTOK("int"), [TT_IDENT] = SYMTOK("ident") }; static int token_to_data(struct token *tok, struct data_value *result) { if (tok == NULL || result == NULL) { return -1; } switch (tok->type) { case TT_TRUE: result->v = 1; result->type = DATA_TYPE_INT; return 0; case TT_FALSE: result->v = 0; result->type = DATA_TYPE_INT; return 0; default: return -1; } return -1; } /* * Assert that the next token is of a specific type * * @state: Defconf state * @tok: Last token * @exp: Expected token */ static int parse_expect(struct defconf_state *state, struct token *tok, tt_t exp) { int error; if (state == NULL || tok == NULL) { return -1; } /* Try to grab the next token */ if ((error = lexer_scan(state, tok)) < 0) { trace_fatal(state, "expected '%s', got eof\n", TOKSTR(exp)); return error; } if (tok->type != exp) { trace_fatal(state, "expected '%s', got %s instead\n", TOKSTR(exp), TOKSTR(tok->type)); return -1; } return 0; } /* * Parse a define directive * * @state: Defconf state * @tok: Last token * * Returns zero on success */ static int parse_define(struct defconf_state *state, struct token *tok) { struct data_value value; char *ident; int error; if (state == NULL || tok == NULL) { return -1; } /* Expect an identifier */ if ((error = parse_expect(state, tok, TT_IDENT)) < 0) { return error; } /* Save the identifier */ ident = tok->s; /* Scan the value */ if ((error = lexer_scan(state, tok)) < 0) { trace_fatal(state, "expected value, got eof\n"); return error; } /* Convert token to data */ if ((error = token_to_data(tok, &value)) < 0) { trace_fatal(state, "got bad data [%s]\n", TOKSTR(tok->type)); return error; } /* Emit the define */ if ((error = emit_data(ident, &value)) < 0) { return error; } return 0; } int parse_begin(struct defconf_state *state) { struct token tok; int error; if (state == NULL) { return -1; } while (lexer_scan(state, &tok) == 0) { switch (tok.type) { case TT_DEFINE: if ((error = parse_define(state, &tok)) < 0) { return error; } break; default: trace_fatal(state, "got unexpected token: %s\n", TOKSTR(tok.type)); return -1; } } return 0; }