X-Git-Url: https://pintos-os.org/cgi-bin/gitweb.cgi?a=blobdiff_plain;ds=sidebyside;f=src%2Flanguage%2Flexer%2Flexer.c;h=ff3c43e35edd4c01ee555e721ee930f0416f5ba1;hb=fcb970c24584cf72f46676ff1cb2e08013951392;hp=c322dec54fec94f38939e00fc65d2a105664bd00;hpb=321290aa58ad553951a4448ea512ebeed4ddf9b1;p=pspp diff --git a/src/language/lexer/lexer.c b/src/language/lexer/lexer.c index c322dec54f..ff3c43e35e 100644 --- a/src/language/lexer/lexer.c +++ b/src/language/lexer/lexer.c @@ -31,6 +31,7 @@ #include #include "language/command.h" +#include "language/lexer/macro.h" #include "language/lexer/scan.h" #include "language/lexer/segment.h" #include "language/lexer/token.h" @@ -67,6 +68,7 @@ struct lex_token size_t token_len; /* Length of source for token in bytes. */ size_t line_pos; /* Start of line containing token_pos. */ int first_line; /* Line number at token_pos. */ + bool from_macro; }; /* A source of tokens, corresponding to a syntax file. @@ -77,6 +79,7 @@ struct lex_source { struct ll ll; /* In lexer's list of sources. */ struct lex_reader *reader; + struct lexer *lexer; struct segmenter segmenter; bool eof; /* True if T_STOP was read from 'reader'. */ @@ -99,13 +102,15 @@ struct lex_source struct lex_token *tokens; /* Lookahead tokens for parser. */ }; -static struct lex_source *lex_source_create (struct lex_reader *); +static struct lex_source *lex_source_create (struct lexer *, + struct lex_reader *); static void lex_source_destroy (struct lex_source *); /* Lexer. */ struct lexer { struct ll_list sources; /* Contains "struct lex_source"s. */ + struct macro_set *macros; }; static struct lex_source *lex_source__ (const struct lexer *); @@ -113,7 +118,7 @@ static const struct lex_token *lex_next__ (const struct lexer *, int n); static void lex_source_push_endcmd__ (struct lex_source *); static void lex_source_pop__ (struct lex_source *); -static bool lex_source_get__ (const struct lex_source *); +static bool lex_source_get (const struct lex_source *); static void lex_source_error_valist (struct lex_source *, int n0, int n1, const char *format, va_list) PRINTF_FORMAT (4, 0); @@ -148,8 +153,11 @@ lex_reader_set_file_name (struct lex_reader *reader, const char *file_name) struct lexer * lex_create (void) { - struct lexer *lexer = xzalloc (sizeof *lexer); - ll_init (&lexer->sources); + struct lexer *lexer = xmalloc (sizeof *lexer); + *lexer = (struct lexer) { + .sources = LL_INITIALIZER (lexer->sources), + .macros = macro_set_create (), + }; return lexer; } @@ -163,10 +171,19 @@ lex_destroy (struct lexer *lexer) ll_for_each_safe (source, next, struct lex_source, ll, &lexer->sources) lex_source_destroy (source); + macro_set_destroy (lexer->macros); free (lexer); } } +/* Adds M to LEXER's set of macros. M replaces any existing macro with the + same name. Takes ownership of M. */ +void +lex_define_macro (struct lexer *lexer, struct macro *m) +{ + macro_set_add (lexer->macros, m); +} + /* Inserts READER into LEXER so that the next token read by LEXER comes from READER. Before the caller, LEXER must either be empty or at a T_ENDCMD token. */ @@ -174,7 +191,7 @@ void lex_include (struct lexer *lexer, struct lex_reader *reader) { assert (ll_is_empty (&lexer->sources) || lex_token (lexer) == T_ENDCMD); - ll_push_head (&lexer->sources, &lex_source_create (reader)->ll); + ll_push_head (&lexer->sources, &lex_source_create (lexer, reader)->ll); } /* Appends READER to LEXER, so that it will be read after all other current @@ -182,7 +199,7 @@ lex_include (struct lexer *lexer, struct lex_reader *reader) void lex_append (struct lexer *lexer, struct lex_reader *reader) { - ll_push_tail (&lexer->sources, &lex_source_create (reader)->ll); + ll_push_tail (&lexer->sources, &lex_source_create (lexer, reader)->ll); } /* Advancing. */ @@ -196,20 +213,20 @@ lex_push_token__ (struct lex_source *src) src->tokens = deque_expand (&src->deque, src->tokens, sizeof *src->tokens); token = &src->tokens[deque_push_front (&src->deque)]; - token_init (&token->token); + token->token = (struct token) { .type = T_STOP }; return token; } static void lex_source_pop__ (struct lex_source *src) { - token_destroy (&src->tokens[deque_pop_back (&src->deque)].token); + token_uninit (&src->tokens[deque_pop_back (&src->deque)].token); } static void lex_source_pop_front (struct lex_source *src) { - token_destroy (&src->tokens[deque_pop_front (&src->deque)].token); + token_uninit (&src->tokens[deque_pop_front (&src->deque)].token); } /* Advances LEXER to the next token, consuming the current token. */ @@ -226,7 +243,7 @@ lex_get (struct lexer *lexer) lex_source_pop__ (src); while (deque_is_empty (&src->deque)) - if (!lex_source_get__ (src)) + if (!lex_source_get (src)) { lex_source_destroy (src); src = lex_source__ (lexer); @@ -859,13 +876,17 @@ lex_next__ (const struct lexer *lexer_, int n) return lex_source_next__ (src, n); else { - static const struct lex_token stop_token = - { TOKEN_INITIALIZER (T_STOP, 0.0, ""), 0, 0, 0, 0 }; - + static const struct lex_token stop_token = { .token = { .type = T_STOP } }; return &stop_token; } } +static const struct lex_token * +lex_source_front (const struct lex_source *src) +{ + return &src->tokens[deque_front (&src->deque, 0)]; +} + static const struct lex_token * lex_source_next__ (const struct lex_source *src, int n) { @@ -873,14 +894,12 @@ lex_source_next__ (const struct lex_source *src, int n) { if (!deque_is_empty (&src->deque)) { - struct lex_token *front; - - front = &src->tokens[deque_front (&src->deque, 0)]; + const struct lex_token *front = lex_source_front (src); if (front->token.type == T_STOP || front->token.type == T_ENDCMD) return front; } - lex_source_get__ (src); + lex_source_get (src); } return &src->tokens[deque_back (&src->deque, n)]; @@ -989,7 +1008,7 @@ lex_match_phrase (struct lexer *lexer, const char *s) if (token.type != SCAN_SKIP) { bool match = lex_tokens_match (lex_next (lexer, i++), &token); - token_destroy (&token); + token_uninit (&token); if (!match) return false; } @@ -1377,6 +1396,16 @@ lex_source_error_valist (struct lex_source *src, int n0, int n1, token = lex_source_next__ (src, n0); if (token->token.type == T_ENDCMD) ds_put_cstr (&s, _("Syntax error at end of command")); + else if (token->from_macro) + { + /* XXX this isn't ideal, we should get the actual syntax */ + char *syntax = token_to_string (&token->token); + if (syntax) + ds_put_format (&s, _("Syntax error at `%s'"), syntax); + else + ds_put_cstr (&s, _("Syntax error")); + free (syntax); + } else { struct substring syntax = lex_source_get_syntax__ (src, n0, n1); @@ -1428,16 +1457,11 @@ lex_get_error (struct lex_source *src, const char *format, ...) } /* Attempts to append an additional token into SRC's deque, reading more from - the underlying lex_reader if necessary. Returns true if successful, false - if the deque already represents (a suffix of) the whole lex_reader's - contents, */ + the underlying lex_reader if necessary. Returns true if a new token was + added to SRC's deque, false otherwise. */ static bool -lex_source_get__ (const struct lex_source *src_) +lex_source_try_get (struct lex_source *src) { - struct lex_source *src = CONST_CAST (struct lex_source *, src_); - if (src->eof) - return false; - /* State maintained while scanning tokens. Usually we only need a single state, but scanner_push() can return SCAN_SAVE to indicate that the state needs to be saved and possibly restored later with SCAN_BACK. */ @@ -1568,57 +1592,125 @@ lex_source_get__ (const struct lex_source *src_) switch (token->token.type) { default: - break; + return true; case T_STOP: token->token.type = T_ENDCMD; src->eof = true; - break; + return true; case SCAN_BAD_HEX_LENGTH: lex_get_error (src, _("String of hex digits has %d characters, which " "is not a multiple of 2"), (int) token->token.number); - break; + return false; case SCAN_BAD_HEX_DIGIT: case SCAN_BAD_UNICODE_DIGIT: lex_get_error (src, _("`%c' is not a valid hex digit"), (int) token->token.number); - break; + return false; case SCAN_BAD_UNICODE_LENGTH: lex_get_error (src, _("Unicode string contains %d bytes, which is " "not in the valid range of 1 to 8 bytes"), (int) token->token.number); - break; + return false; case SCAN_BAD_UNICODE_CODE_POINT: lex_get_error (src, _("U+%04X is not a valid Unicode code point"), (int) token->token.number); - break; + return false; case SCAN_EXPECTED_QUOTE: lex_get_error (src, _("Unterminated string constant")); - break; + return false; case SCAN_EXPECTED_EXPONENT: lex_get_error (src, _("Missing exponent following `%s'"), token->token.string.string); - break; + return false; case SCAN_UNEXPECTED_CHAR: { char c_name[16]; lex_get_error (src, _("Bad character %s in input"), uc_name (token->token.number, c_name)); + return false; } - break; case SCAN_SKIP: lex_source_pop_front (src); - break; + return false; + } + + NOT_REACHED (); +} + +static bool +lex_source_get__ (struct lex_source *src) +{ + for (;;) + { + if (src->eof) + return false; + else if (lex_source_try_get (src)) + return true; + } +} + +static bool +lex_source_get (const struct lex_source *src_) +{ + struct lex_source *src = CONST_CAST (struct lex_source *, src_); + + size_t old_count = deque_count (&src->deque); + if (!lex_source_get__ (src)) + return false; + + if (!settings_get_mexpand ()) + return true; + + struct macro_expander *me; + int retval = macro_expander_create (src->lexer->macros, + &lex_source_front (src)->token, &me); + while (!retval) + { + if (!lex_source_get__ (src)) + { + /* This should not be reachable because we always get a T_STOP at the + end of input and the macro_expander should always terminate + expansion on T_STOP. */ + NOT_REACHED (); + } + + retval = macro_expander_add (me, &lex_source_front (src)->token); + } + if (retval < 0) + { + /* XXX handle case where there's a macro invocation starting from some + later token we've already obtained */ + macro_expander_destroy (me); + return true; + } + + /* XXX handle case where the macro invocation doesn't use all the tokens */ + while (deque_count (&src->deque) > old_count) + lex_source_pop_front (src); + + struct tokens expansion = { .tokens = NULL }; + macro_expander_get_expansion (me, &expansion); + macro_expander_destroy (me); + + for (size_t i = 0; i < expansion.n; i++) + { + *lex_push_token__ (src) = (struct lex_token) { + .token = expansion.tokens[i], + .from_macro = true, + /* XXX the rest */ + }; } + free (expansion.tokens); return true; } @@ -1635,13 +1727,14 @@ lex_source_push_endcmd__ (struct lex_source *src) } static struct lex_source * -lex_source_create (struct lex_reader *reader) +lex_source_create (struct lexer *lexer, struct lex_reader *reader) { struct lex_source *src; src = xzalloc (sizeof *src); src->reader = reader; segmenter_init (&src->segmenter, reader->syntax); + src->lexer = lexer; src->tokens = deque_init (&src->deque, 4, sizeof *src->tokens); lex_source_push_endcmd__ (src);