/* ** PostgreSQL SQL Tokenizer for Lime Parser -- Public Interface ** ** This header defines the tokenizer API for feeding tokens to a ** Lime-generated PostgreSQL parser. The tokenizer implements the ** lexical analysis rules from PostgreSQL's scan.l (with extensions ** from parser.c for lookahead token injection). ** ** Token codes come from pg_grammar.h (generated by Lime from ** pg_grammar.lime). All token constants (IDENT, ICONST, SELECT, ** LPAREN, etc.) are defined there. ** ** Usage: ** PgScanner *s = pg_scanner_create(sql, strlen(sql)); ** PgTokenValue val; ** int loc, tok; ** while ((tok = pg_scan_with_lookahead(s, &val, &loc)) > 0) { ** pgParse(parser, tok, make_token(val, loc)); ** } ** pgParse(parser, 0, empty_token); // signal EOF ** pg_scanner_destroy(s); */ #ifndef PG_TOKENIZE_H #define PG_TOKENIZE_H #include #include #include /* Token code #defines from the Lime-generated parser header. ** This provides IDENT, ICONST, SCONST, SELECT, LPAREN, etc. */ #include "pg_grammar.h" #ifdef __cplusplus extern "C" { #endif /* ====================================================================== ** Semantic value type ** ** Mirrors PostgreSQL's core_YYSTYPE. The Lime grammar's %token_type ** should be set to PgTokenValue (or a compatible union). ** ====================================================================== */ typedef union PgTokenValue { int32_t ival; /* Integer constants, PARAM */ char *str; /* String constants, identifiers, operators (caller owns) */ const char *keyword; /* Keyword canonical form (static, do not free) */ } PgTokenValue; /* ====================================================================== ** Opaque scanner handle ** ====================================================================== */ typedef struct PgScanner PgScanner; /* ====================================================================== ** Scanner lifecycle ** ====================================================================== */ /* ** Create a scanner for the given input SQL string. ** The input buffer must remain valid for the lifetime of the scanner. ** Returns NULL on allocation failure. */ PgScanner *pg_scanner_create(const char *input, size_t length); /* ** Destroy a scanner and free all associated resources. ** Passing NULL is safe (no-op). */ void pg_scanner_destroy(PgScanner *s); /* ====================================================================== ** Token extraction -- raw layer ** ====================================================================== */ /* ** Extract the next raw token from the input. ** ** Returns: ** > 0 Token code from pg_grammar.h (IDENT, ICONST, SELECT, LPAREN, etc.) ** 0 End of input ** -1 Lexical error (call pg_scanner_error() for details) ** ** On success, *val is filled with the semantic value and *loc with ** the byte offset of the token start in the input string. ** ** Caller owns any val->str pointer returned (must free when done). ** val->keyword points to static storage (do not free). */ int pg_scan(PgScanner *s, PgTokenValue *val, int *loc); /* ====================================================================== ** Token extraction -- lookahead layer ** ====================================================================== */ /* ** Extract the next token with one-token lookahead for LALR(1) fixups. ** ** This wraps pg_scan() and implements the same lookahead logic as ** PostgreSQL's parser.c: certain keywords are replaced with their ** _LA variant based on what follows: ** ** NOT -> NOT_LA when followed by BETWEEN, IN, LIKE, ILIKE, SIMILAR ** NULLS_P -> NULLS_LA when followed by FIRST_P, LAST_P ** WITH -> WITH_LA when followed by TIME, ORDINALITY ** WITHOUT -> WITHOUT_LA when followed by TIME ** FORMAT -> FORMAT_LA when followed by JSON ** ** The interface is identical to pg_scan(). */ int pg_scan_with_lookahead(PgScanner *s, PgTokenValue *val, int *loc); /* ====================================================================== ** Error reporting ** ====================================================================== */ /* ** Return the last error message, or NULL if no error occurred. */ const char *pg_scanner_error(const PgScanner *s); /* ** Return the byte offset of the last error, or -1 if no error. */ int pg_scanner_error_location(const PgScanner *s); /* ====================================================================== ** Debugging / introspection ** ====================================================================== */ /* ** Return a human-readable name for a token code. ** Returns a static string; do not free. */ const char *pg_token_name(int token); /* ** Return the number of entries in the keyword table. */ int pg_keyword_count(void); /* ** Look up a keyword by name (case-insensitive). ** Returns the token code, or 0 if not a keyword. ** (0 means IDENT; all real keyword tokens are > 0.) */ int pg_keyword_lookup(const char *text, size_t len); /* ** Return the canonical (lowercase) name for a keyword token. ** Returns NULL if the token is not a keyword. */ const char *pg_keyword_name(int token); #ifdef __cplusplus } #endif #endif /* PG_TOKENIZE_H */