X-Git-Url: https://pintos-os.org/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=src%2Flanguage%2Flexer%2Flexer.c;h=a20cc17506db62d170a7a084b7ff0afabf3882e5;hb=60fc7f6c520d2193364997bc50008a3a2665e089;hp=b1c05c81c4cd1ca091165f6ac077ee90720d1b63;hpb=65e61cc92b48297625bc71cf31b8a19e301eb6c1;p=pspp diff --git a/src/language/lexer/lexer.c b/src/language/lexer/lexer.c index b1c05c81c4..a20cc17506 100644 --- a/src/language/lexer/lexer.c +++ b/src/language/lexer/lexer.c @@ -1,21 +1,18 @@ -/* PSPP - computes sample statistics. - Copyright (C) 1997-9, 2000 Free Software Foundation, Inc. - Written by Ben Pfaff . +/* PSPP - a program for statistical analysis. + Copyright (C) 1997-9, 2000, 2006 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 the Free Software Foundation; either version 2 of the - License, or (at your option) any later version. + 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 + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. - This program is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - 02110-1301, USA. */ + along with this program. If not, see . */ #include #include "lexer.h" @@ -41,11 +38,11 @@ #define _(msgid) gettext (msgid) #define N_(msgid) msgid -/* -#define DUMP_TOKENS 1 -*/ -struct lexer +#define DUMP_TOKENS 0 + + +struct lexer { struct string line_buffer; @@ -57,16 +54,15 @@ struct lexer char tokid [LONG_NAME_LEN + 1]; /* T_ID: the identifier. */ struct string tokstr; /* T_ID, T_STRING: token string value. - For T_ID, this is not truncated as is + For T_ID, this is not truncated as is tokid. */ char *prog; /* Pointer to next token in line_buffer. */ bool dot; /* True only if this line ends with a terminal dot. */ - bool eof; /* True only if the last token returned was T_STOP. */ int put_token ; /* If nonzero, next token returned by lex_get(). Used only in exceptional circumstances. */ - + struct string put_tokstr; double put_tokval; }; @@ -75,7 +71,7 @@ struct lexer static int parse_id (struct lexer *); /* How a string represents its contents. */ -enum string_type +enum string_type { CHARACTER_STRING, /* Characters. */ BINARY_STRING, /* Binary digits. */ @@ -86,7 +82,7 @@ enum string_type static int parse_string (struct lexer *, enum string_type); #if DUMP_TOKENS -static void dump_token (void); +static void dump_token (struct lexer *); #endif /* Initialization. */ @@ -102,9 +98,6 @@ lex_create (struct source_stream *ss) ds_init_empty (&lexer->line_buffer); lexer->ss = ss; - if (!lex_get_line (lexer)) - lexer->eof = true; - return lexer; } @@ -118,7 +111,7 @@ lex_get_source_stream (const struct lexer *lex) void lex_destroy (struct lexer *lexer) { - if ( NULL != lexer ) + if ( NULL != lexer ) { ds_destroy (&lexer->put_tokstr); ds_destroy (&lexer->tokstr); @@ -134,7 +127,7 @@ lex_destroy (struct lexer *lexer) /* Copies put_token, lexer->put_tokstr, put_tokval into token, tokstr, tokval, respectively, and sets tokid appropriately. */ static void -restore_token (struct lexer *lexer) +restore_token (struct lexer *lexer) { assert (lexer->put_token != 0); lexer->token = lexer->put_token; @@ -147,7 +140,7 @@ restore_token (struct lexer *lexer) /* Copies token, tokstr, lexer->tokval into lexer->put_token, put_tokstr, put_lexer->tokval respectively. */ static void -save_token (struct lexer *lexer) +save_token (struct lexer *lexer) { lexer->put_token = lexer->token; ds_assign_string (&lexer->put_tokstr, &lexer->tokstr); @@ -159,30 +152,31 @@ save_token (struct lexer *lexer) void lex_get (struct lexer *lexer) { + /* Find a token. */ + for (;;) + { + if (NULL == lexer->prog && ! lex_get_line (lexer) ) + { + lexer->token = T_STOP; + return; + } + /* If a token was pushed ahead, return it. */ if (lexer->put_token) { restore_token (lexer); #if DUMP_TOKENS - dump_token (); + dump_token (lexer); #endif return; } - /* Find a token. */ for (;;) { /* Skip whitespace. */ - if (lexer->eof) - { - lexer->token = T_STOP; - return; - } - - for (;;) - { while (isspace ((unsigned char) *lexer->prog)) lexer->prog++; + if (*lexer->prog) break; @@ -191,16 +185,16 @@ lex_get (struct lexer *lexer) lexer->dot = 0; lexer->token = '.'; #if DUMP_TOKENS - dump_token (); + dump_token (lexer); #endif return; } else if (!lex_get_line (lexer)) { - lexer->eof = true; + lexer->prog = NULL; lexer->token = T_STOP; #if DUMP_TOKENS - dump_token (); + dump_token (lexer); #endif return; } @@ -209,7 +203,7 @@ lex_get (struct lexer *lexer) { restore_token (lexer); #if DUMP_TOKENS - dump_token (); + dump_token (lexer); #endif return; } @@ -218,7 +212,7 @@ lex_get (struct lexer *lexer) /* Actually parse the token. */ ds_clear (&lexer->tokstr); - + switch (*lexer->prog) { case '-': case '.': @@ -247,9 +241,9 @@ lex_get (struct lexer *lexer) } lexer->token = T_NEG_NUM; } - else + else lexer->token = T_POS_NUM; - + /* Parse the number, copying it into tokstr. */ while (isdigit ((unsigned char) *lexer->prog)) ds_put_char (&lexer->tokstr, *lexer->prog++); @@ -352,26 +346,26 @@ lex_get (struct lexer *lexer) else lexer->token = parse_id (lexer); break; - + case 'o': case 'O': if (lexer->prog[1] == '\'' || lexer->prog[1] == '"') lexer->token = parse_string (lexer, OCTAL_STRING); else lexer->token = parse_id (lexer); break; - + case 'x': case 'X': if (lexer->prog[1] == '\'' || lexer->prog[1] == '"') lexer->token = parse_string (lexer, HEX_STRING); else lexer->token = parse_id (lexer); break; - + default: - if (lex_is_id1 (*lexer->prog)) + if (lex_is_id1 (*lexer->prog)) { lexer->token = parse_id (lexer); - break; + break; } else { @@ -379,14 +373,14 @@ lex_get (struct lexer *lexer) msg (SE, _("Bad character in input: `%c'."), *lexer->prog++); else msg (SE, _("Bad character in input: `\\%o'."), *lexer->prog++); - continue; + continue; } } break; } #if DUMP_TOKENS - dump_token (); + dump_token (lexer); #endif } @@ -394,7 +388,7 @@ lex_get (struct lexer *lexer) tokstr. Returns the correct token type. */ static int -parse_id (struct lexer *lexer) +parse_id (struct lexer *lexer) { struct substring rest_of_line = ss_substr (ds_ss (&lexer->line_buffer), @@ -412,7 +406,7 @@ parse_id (struct lexer *lexer) /* Reports an error to the effect that subcommand SBC may only be specified once. */ void -lex_sbc_only_once (const char *sbc) +lex_sbc_only_once (const char *sbc) { msg (SE, _("Subcommand %s may only be specified once."), sbc); } @@ -420,7 +414,7 @@ lex_sbc_only_once (const char *sbc) /* Reports an error to the effect that subcommand SBC is missing. */ void -lex_sbc_missing (struct lexer *lexer, const char *sbc) +lex_sbc_missing (struct lexer *lexer, const char *sbc) { lex_error (lexer, _("missing required subcommand %s"), sbc); } @@ -446,7 +440,7 @@ lex_error (struct lexer *lexer, const char *message, ...) { char buf[1024]; va_list args; - + va_start (args, message); vsnprintf (buf, 1024, message, args); va_end (args); @@ -477,11 +471,20 @@ lex_end_of_command (struct lexer *lexer) /* Returns true if the current token is a number. */ bool -lex_is_number (struct lexer *lexer) +lex_is_number (struct lexer *lexer) { return lexer->token == T_POS_NUM || lexer->token == T_NEG_NUM; } + +/* Returns true if the current token is a string. */ +bool +lex_is_string (struct lexer *lexer) +{ + return lexer->token == T_STRING; +} + + /* Returns the value of the current token, which must be a floating point number. */ double @@ -510,7 +513,7 @@ lex_integer (struct lexer *lexer) assert (lex_is_integer (lexer)); return lexer->tokval; } - + /* Token matching functions. */ /* If TOK is the current token, skips it and returns true @@ -619,7 +622,7 @@ lex_force_int (struct lexer *lexer) return false; } } - + /* If this token is a number, does nothing and returns true. Otherwise, reports an error and returns false. */ bool @@ -631,7 +634,7 @@ lex_force_num (struct lexer *lexer) lex_error (lexer, _("expecting number")); return false; } - + /* If this token is an identifier, does nothing and returns true. Otherwise, reports an error and returns false. */ bool @@ -660,7 +663,7 @@ lex_look_ahead (struct lexer *lexer) for (;;) { - if (lexer->eof) + if (NULL == lexer->prog && ! lex_get_line (lexer) ) return 0; for (;;) @@ -675,7 +678,7 @@ lex_look_ahead (struct lexer *lexer) else if (!lex_get_line (lexer)) return 0; - if (lexer->put_token) + if (lexer->put_token) return lexer->put_token; } @@ -714,29 +717,33 @@ lex_put_back_id (struct lexer *lexer, const char *id) /* Returns the entire contents of the current line. */ const char * -lex_entire_line (struct lexer *lexer) +lex_entire_line (const struct lexer *lexer) { return ds_cstr (&lexer->line_buffer); } const struct string * -lex_entire_line_ds (struct lexer *lexer) +lex_entire_line_ds (const struct lexer *lexer) { return &lexer->line_buffer; } /* As lex_entire_line(), but only returns the part of the current line - that hasn't already been tokenized. - If END_DOT is non-null, stores nonzero into *END_DOT if the line - ends with a terminal dot, or zero if it doesn't. */ + that hasn't already been tokenized. */ const char * -lex_rest_of_line (struct lexer *lexer, int *end_dot) +lex_rest_of_line (const struct lexer *lexer) { - if (end_dot) - *end_dot = lexer->dot; return lexer->prog; } +/* Returns true if the current line ends in a terminal dot, + false otherwise. */ +bool +lex_end_dot (const struct lexer *lexer) +{ + return lexer->dot; +} + /* Causes the rest of the current input line to be ignored for tokenization purposes. */ void @@ -757,15 +764,15 @@ lex_discard_line (struct lexer *lexer) the user doesn't want to finish typing a command that will be ignored anyway. */ void -lex_discard_rest_of_command (struct lexer *lexer) +lex_discard_rest_of_command (struct lexer *lexer) { if (!getl_is_interactive (lexer->ss)) { while (lexer->token != T_STOP && lexer->token != '.') lex_get (lexer); } - else - lex_discard_line (lexer); + else + lex_discard_line (lexer); } /* Weird line reading functions. */ @@ -791,7 +798,7 @@ strip_comments (struct string *string) else if (*cp == '\'' || *cp == '"') quote = *cp; } - + /* If we're not inside a quotation, check for comment. */ if (quote == EOF) { @@ -810,7 +817,7 @@ strip_comments (struct string *string) continue; } } - + /* Check commenting. */ if (in_comment) *cp = ' '; @@ -837,7 +844,7 @@ lex_preprocess_line (struct string *line, { int first = ds_first (line); *line_starts_command = !isspace (first); - if (first == '+' || first == '-') + if (first == '+' || first == '-') *ds_data (line) = ' '; } } @@ -845,7 +852,7 @@ lex_preprocess_line (struct string *line, /* Reads a line, without performing any preprocessing. Sets *SYNTAX, if SYNTAX is non-null, to the line's syntax mode. */ -bool +bool lex_get_line_raw (struct lexer *lexer, enum getl_syntax *syntax) { enum getl_syntax dummy; @@ -861,13 +868,17 @@ bool lex_get_line (struct lexer *lexer) { bool line_starts_command; - enum getl_syntax syntax; + enum getl_syntax syntax = GETL_BATCH; if (!lex_get_line_raw (lexer, &syntax)) - return false; + { + lexer->prog = NULL; + return false; + } lex_preprocess_line (&lexer->line_buffer, syntax, &line_starts_command, &lexer->dot); + if (line_starts_command) lexer->put_token = '.'; @@ -901,7 +912,7 @@ char * lex_token_representation (struct lexer *lexer) { char *token_rep; - + switch (lexer->token) { case T_ID: @@ -921,7 +932,7 @@ lex_token_representation (struct lexer *lexer) hexstring = 1; break; } - + token_rep = xmalloc (2 + ds_length (&lexer->tokstr) * 2 + 1 + 1); dp = token_rep; @@ -944,7 +955,7 @@ lex_token_representation (struct lexer *lexer) } *dp++ = '\''; *dp = '\0'; - + return token_rep; } break; @@ -960,7 +971,7 @@ lex_token_representation (struct lexer *lexer) default: return xstrdup (lex_token_name (lexer->token)); } - + NOT_REACHED (); } @@ -982,20 +993,20 @@ lex_negative_to_dash (struct lexer *lexer) lexer->token = '-'; } } - + /* Skip a COMMENT command. */ void lex_skip_comment (struct lexer *lexer) { for (;;) { - if (!lex_get_line (lexer)) + if (!lex_get_line (lexer)) { lexer->put_token = T_STOP; - lexer->eof = true; + lexer->prog = NULL; return; } - + if (lexer->put_token == '.') break; @@ -1012,7 +1023,7 @@ lex_skip_comment (struct lexer *lexer) hex digits, according to TYPE. The string is converted to characters having the specified values. */ static void -convert_numeric_string_to_char_string (struct lexer *lexer, +convert_numeric_string_to_char_string (struct lexer *lexer, enum string_type type) { const char *base_name; @@ -1022,7 +1033,7 @@ convert_numeric_string_to_char_string (struct lexer *lexer, size_t i; char *p; - switch (type) + switch (type) { case BINARY_STRING: base_name = _("binary"); @@ -1042,19 +1053,19 @@ convert_numeric_string_to_char_string (struct lexer *lexer, default: NOT_REACHED (); } - + byte_cnt = ds_length (&lexer->tokstr) / chars_per_byte; if (ds_length (&lexer->tokstr) % chars_per_byte) msg (SE, _("String of %s digits has %d characters, which is not a " "multiple of %d."), - base_name, ds_length (&lexer->tokstr), chars_per_byte); + base_name, (int) ds_length (&lexer->tokstr), chars_per_byte); p = ds_cstr (&lexer->tokstr); for (i = 0; i < byte_cnt; i++) { int value; int j; - + value = 0; for (j = 0; j < chars_per_byte; j++, p++) { @@ -1089,7 +1100,7 @@ convert_numeric_string_to_char_string (struct lexer *lexer, buffer pointer lexer->prog must point to the initial single or double quote. TYPE indicates the type of string to be parsed. Returns token type. */ -static int +static int parse_string (struct lexer *lexer, enum string_type type) { if (type != CHARACTER_STRING) @@ -1101,7 +1112,7 @@ parse_string (struct lexer *lexer, enum string_type type) { /* Single or double quote. */ int c = *lexer->prog++; - + /* Accumulate section. */ for (;;) { @@ -1111,7 +1122,7 @@ parse_string (struct lexer *lexer, enum string_type type) msg (SE, _("Unterminated string constant.")); goto finish; } - + /* Double quote characters to embed them in strings. */ if (*lexer->prog == c) { @@ -1126,7 +1137,7 @@ parse_string (struct lexer *lexer, enum string_type type) lexer->prog++; /* Skip whitespace after final quote mark. */ - if (lexer->eof) + if (lexer->prog == NULL) break; for (;;) { @@ -1148,7 +1159,7 @@ parse_string (struct lexer *lexer, enum string_type type) lexer->prog++; /* Skip whitespace after plus sign. */ - if (lexer->eof) + if (lexer->prog == NULL) break; for (;;) { @@ -1184,13 +1195,13 @@ finish: if (ds_length (&lexer->tokstr) > 255) { msg (SE, _("String exceeds 255 characters in length (%d characters)."), - ds_length (&lexer->tokstr)); + (int) ds_length (&lexer->tokstr)); ds_truncate (&lexer->tokstr, 255); } - + return T_STRING; } - + #if DUMP_TOKENS /* Reads one token from the lexer and writes a textual representation on stdout for debugging purposes. */ @@ -1201,11 +1212,12 @@ dump_token (struct lexer *lexer) const char *curfn; int curln; - getl_location (&curfn, &curln); + curln = getl_source_location (lexer->ss); + curfn = getl_source_name (lexer->ss); if (curfn) fprintf (stderr, "%s:%d\t", curfn, curln); } - + switch (lexer->token) { case T_ID: @@ -1234,8 +1246,8 @@ dump_token (struct lexer *lexer) break; default: - if (lex_is_keyword (token)) - fprintf (stderr, "KEYWORD\t%s\n", lex_token_name (token)); + if (lex_is_keyword (lexer->token)) + fprintf (stderr, "KEYWORD\t%s\n", lex_token_name (lexer->token)); else fprintf (stderr, "PUNCT\t%c\n", lexer->token); break; @@ -1246,13 +1258,13 @@ dump_token (struct lexer *lexer) /* Token Accessor Functions */ -int +int lex_token (const struct lexer *lexer) { return lexer->token; } -double +double lex_tokval (const struct lexer *lexer) { return lexer->tokval;