/* 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
{
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;
}
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;
- }
-
- 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_POS_NUM:
+ case T_NEG_NUM:
+ return actual->number == expected->number;
- 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_ID:
+ return lex_id_match (expected->string, actual->string);
- if (token != T_POS_NUM)
- return false;
+ case T_STRING:
+ return (actual->string.length == expected->string.length
+ && !memcmp (actual->string.string, expected->string.string,
+ actual->string.length));
- 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
}
/* 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
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
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;
}
/* 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)
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);
}
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.
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;