X-Git-Url: https://pintos-os.org/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=src%2Flanguage%2Flexer%2Flexer.c;h=bbe16cbe17a2c02305f631e8a04cfed5355a805b;hb=bd0fbcb4295cf0fbcfa5c2a8fc607842c958ad65;hp=e3725681c9c6a207332987046e5e9bee721008ee;hpb=f7e9711f020ba507719f1f21cac04ae1199a4ac0;p=pspp diff --git a/src/language/lexer/lexer.c b/src/language/lexer/lexer.c index e3725681c9..bbe16cbe17 100644 --- a/src/language/lexer/lexer.c +++ b/src/language/lexer/lexer.c @@ -1,5 +1,5 @@ /* PSPP - a program for statistical analysis. - Copyright (C) 1997-9, 2000, 2006, 2009, 2010, 2011 Free Software Foundation, Inc. + Copyright (C) 1997-9, 2000, 2006, 2009, 2010, 2011, 2013 Free Software Foundation, Inc. This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -129,7 +129,7 @@ lex_reader_init (struct lex_reader *reader, { reader->class = class; reader->syntax = LEX_SYNTAX_AUTO; - reader->error = LEX_ERROR_INTERACTIVE; + reader->error = LEX_ERROR_CONTINUE; reader->file_name = NULL; reader->line_number = 0; } @@ -362,6 +362,24 @@ lex_sbc_missing (const char *sbc) msg (SE, _("Required subcommand %s was not specified."), sbc); } +/* Reports an error to the effect that specification SPEC may only be specified + once within subcommand SBC. */ +void +lex_spec_only_once (struct lexer *lexer, const char *sbc, const char *spec) +{ + lex_error (lexer, _("%s may only be specified once within subcommand %s"), + spec, sbc); +} + +/* Reports an error to the effect that specification SPEC is missing within + subcommand SBC. */ +void +lex_spec_missing (struct lexer *lexer, const char *sbc, const char *spec) +{ + lex_error (lexer, _("Required %s specification missing from %s subcommand"), + sbc, spec); +} + /* Prints a syntax error message containing the current token and given message MESSAGE (if non-null). */ void @@ -607,6 +625,21 @@ lex_force_string (struct lexer *lexer) } } +/* If the current token is a string or an identifier, does nothing and returns + true. Otherwise, reports an error and returns false. + + This is meant for use in syntactic situations where we want to encourage the + user to supply a quoted string, but for compatibility we also accept + identifiers. (One example of such a situation is file names.) Therefore, + the error message issued when the current token is wrong only says that a + string is expected and doesn't mention that an identifier would also be + accepted. */ +bool +lex_force_string_or_id (struct lexer *lexer) +{ + return lex_is_integer (lexer) || lex_force_string (lexer); +} + /* If the current token is an integer, does nothing and returns true. Otherwise, reports an error and returns false. */ bool @@ -797,99 +830,58 @@ lex_next_tokss (const struct lexer *lexer, int n) return lex_next (lexer, n)->string; } -/* If LEXER is positioned at the (pseudo)identifier S, skips it and returns - true. Otherwise, returns false. - - S may consist of an arbitrary number of identifiers, integers, and - punctuation e.g. "KRUSKAL-WALLIS", "2SLS", or "END INPUT PROGRAM". - Identifiers may be abbreviated to their first three letters. Currently only - hyphens, slashes, and equals signs are supported as punctuation (but it - would be easy to add more). - - S must be an ASCII string. */ -bool -lex_match_phrase (struct lexer *lexer, const char *s) +static bool +lex_tokens_match (const struct token *actual, const struct token *expected) { - int tok_idx; + if (actual->type != expected->type) + return false; - for (tok_idx = 0; ; tok_idx++) + switch (actual->type) { - enum token_type token; - unsigned char c; - - while (c_isspace (*s)) - s++; - - c = *s; - if (c == '\0') - { - int i; - - for (i = 0; i < tok_idx; i++) - lex_get (lexer); - return true; - } + case T_POS_NUM: + case T_NEG_NUM: + return actual->number == expected->number; - token = lex_next_token (lexer, tok_idx); - switch (c) - { - case '-': - if (token != T_DASH) - return false; - s++; - break; - - case '/': - if (token != T_SLASH) - return false; - s++; - break; - - case '=': - if (token != T_EQUALS) - return false; - s++; - break; + case T_ID: + return lex_id_match (expected->string, actual->string); - case '0': case '1': case '2': case '3': case '4': - case '5': case '6': case '7': case '8': case '9': - { - unsigned int value; + case T_STRING: + return (actual->string.length == expected->string.length + && !memcmp (actual->string.string, expected->string.string, + actual->string.length)); - if (token != T_POS_NUM) - return false; - - value = 0; - do - { - value = value * 10 + (*s++ - '0'); - } - while (c_isdigit (*s)); - - if (lex_next_tokval (lexer, tok_idx) != value) - return false; - } - break; + default: + return true; + } +} - default: - if (lex_is_id1 (c)) - { - int len; +/* If LEXER is positioned at the sequence of tokens that may be parsed from S, + skips it and returns true. Otherwise, returns false. - if (token != T_ID) - return false; + S may consist of an arbitrary sequence of tokens, e.g. "KRUSKAL-WALLIS", + "2SLS", or "END INPUT PROGRAM". Identifiers may be abbreviated to their + first three letters. */ +bool +lex_match_phrase (struct lexer *lexer, const char *s) +{ + struct string_lexer slex; + struct token token; + int i; - len = lex_id_get_length (ss_cstr (s)); - if (!lex_id_match (ss_buffer (s, len), - lex_next_tokss (lexer, tok_idx))) - return false; + i = 0; + string_lexer_init (&slex, s, SEG_MODE_INTERACTIVE); + while (string_lexer_next (&slex, &token)) + if (token.type != SCAN_SKIP) + { + bool match = lex_tokens_match (lex_next (lexer, i++), &token); + token_destroy (&token); + if (!match) + return false; + } - s += len; - } - else - NOT_REACHED (); - } - } + while (i-- > 0) + lex_get (lexer); + return true; } static int @@ -1061,7 +1053,7 @@ lex_get_syntax_mode (const struct lexer *lexer) } /* Returns the error mode for the syntax file from which the current drawn is - drawn. Returns LEX_ERROR_INTERACTIVE for a T_STOP token or if the command's + drawn. Returns LEX_ERROR_TERMINAL for a T_STOP token or if the command's source does not have line numbers. There is no version of this function that takes an N argument because @@ -1071,13 +1063,12 @@ enum lex_error_mode lex_get_error_mode (const struct lexer *lexer) { struct lex_source *src = lex_source__ (lexer); - return src == NULL ? LEX_ERROR_INTERACTIVE : src->reader->error; + return src == NULL ? LEX_ERROR_TERMINAL : src->reader->error; } /* If the source that LEXER is currently reading has error mode - LEX_ERROR_INTERACTIVE, discards all buffered input and tokens, so that the - next token to be read comes directly from whatever is next read from the - stream. + LEX_ERROR_TERMINAL, discards all buffered input and tokens, so that the next + token to be read comes directly from whatever is next read from the stream. It makes sense to call this function after encountering an error in a command entered on the console, because usually the user would prefer not to @@ -1086,7 +1077,7 @@ void lex_interactive_reset (struct lexer *lexer) { struct lex_source *src = lex_source__ (lexer); - if (src != NULL && src->reader->error == LEX_ERROR_INTERACTIVE) + if (src != NULL && src->reader->error == LEX_ERROR_TERMINAL) { src->head = src->tail = 0; src->journal_pos = src->seg_pos = src->line_pos = 0; @@ -1108,7 +1099,7 @@ lex_discard_rest_of_command (struct lexer *lexer) } /* Discards all lookahead tokens in LEXER, then discards all input sources - until it encounters one with error mode LEX_ERROR_INTERACTIVE or until it + until it encounters one with error mode LEX_ERROR_TERMINAL or until it runs out of input sources. */ void lex_discard_noninteractive (struct lexer *lexer) @@ -1120,7 +1111,7 @@ lex_discard_noninteractive (struct lexer *lexer) while (!deque_is_empty (&src->deque)) lex_source_pop__ (src); - for (; src != NULL && src->reader->error != LEX_ERROR_INTERACTIVE; + for (; src != NULL && src->reader->error != LEX_ERROR_TERMINAL; src = lex_source__ (lexer)) lex_source_destroy (src); } @@ -1176,14 +1167,18 @@ lex_source_read__ (struct lex_source *src) do { size_t head_ofs; + size_t space; size_t n; lex_source_expand__ (src); head_ofs = src->head - src->tail; + space = src->allocated - head_ofs; n = src->reader->class->read (src->reader, &src->buffer[head_ofs], - src->allocated - head_ofs, + space, segmenter_get_prompt (&src->segmenter)); + assert (n <= space); + if (n == 0) { /* End of input. @@ -1650,7 +1645,7 @@ lex_reader_for_substring_nocopy (struct substring s) r = xmalloc (sizeof *r); lex_reader_init (&r->reader, &lex_string_reader_class); - r->reader.syntax = LEX_SYNTAX_INTERACTIVE; + r->reader.syntax = LEX_SYNTAX_AUTO; r->s = s; r->offset = 0;