1 /* PSPP - a program for statistical analysis.
2 Copyright (C) 1997-9, 2000, 2006, 2009, 2010 Free Software Foundation, Inc.
4 This program is free software: you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation, either version 3 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program. If not, see <http://www.gnu.org/licenses/>. */
28 #include <language/command.h>
29 #include <data/settings.h>
30 #include <libpspp/assertion.h>
31 #include <libpspp/getl.h>
32 #include <libpspp/message.h>
33 #include <libpspp/str.h>
34 #include <output/journal.h>
35 #include <output/text-item.h>
40 #define _(msgid) gettext (msgid)
41 #define N_(msgid) msgid
45 struct string line_buffer;
47 struct source_stream *ss;
49 int token; /* Current token. */
50 double tokval; /* T_POS_NUM, T_NEG_NUM: the token's value. */
52 char tokid [VAR_NAME_LEN + 1]; /* T_ID: the identifier. */
54 struct string tokstr; /* T_ID, T_STRING: token string value.
55 For T_ID, this is not truncated as is
58 char *prog; /* Pointer to next token in line_buffer. */
59 bool dot; /* True only if this line ends with a terminal dot. */
61 int put_token ; /* If nonzero, next token returned by lex_get().
62 Used only in exceptional circumstances. */
64 struct string put_tokstr;
69 static int parse_id (struct lexer *);
71 /* How a string represents its contents. */
74 CHARACTER_STRING, /* Characters. */
75 BINARY_STRING, /* Binary digits. */
76 OCTAL_STRING, /* Octal digits. */
77 HEX_STRING /* Hexadecimal digits. */
80 static int parse_string (struct lexer *, enum string_type);
84 /* Initializes the lexer. */
86 lex_create (struct source_stream *ss)
88 struct lexer *lexer = xzalloc (sizeof (*lexer));
90 ds_init_empty (&lexer->tokstr);
91 ds_init_empty (&lexer->put_tokstr);
92 ds_init_empty (&lexer->line_buffer);
98 struct source_stream *
99 lex_get_source_stream (const struct lexer *lex)
105 lex_current_syntax_mode (const struct lexer *lex)
107 return source_stream_current_syntax_mode (lex->ss);
111 lex_current_error_mode (const struct lexer *lex)
113 return source_stream_current_error_mode (lex->ss);
118 lex_destroy (struct lexer *lexer)
122 ds_destroy (&lexer->put_tokstr);
123 ds_destroy (&lexer->tokstr);
124 ds_destroy (&lexer->line_buffer);
131 /* Common functions. */
133 /* Copies put_token, lexer->put_tokstr, put_tokval into token, tokstr,
134 tokval, respectively, and sets tokid appropriately. */
136 restore_token (struct lexer *lexer)
138 assert (lexer->put_token != 0);
139 lexer->token = lexer->put_token;
140 ds_assign_string (&lexer->tokstr, &lexer->put_tokstr);
141 str_copy_trunc (lexer->tokid, sizeof lexer->tokid, ds_cstr (&lexer->tokstr));
142 lexer->tokval = lexer->put_tokval;
143 lexer->put_token = 0;
146 /* Copies token, tokstr, lexer->tokval into lexer->put_token, put_tokstr,
147 put_lexer->tokval respectively. */
149 save_token (struct lexer *lexer)
151 lexer->put_token = lexer->token;
152 ds_assign_string (&lexer->put_tokstr, &lexer->tokstr);
153 lexer->put_tokval = lexer->tokval;
156 /* Parses a single token, setting appropriate global variables to
157 indicate the token's attributes. */
159 lex_get (struct lexer *lexer)
164 if (NULL == lexer->prog && ! lex_get_line (lexer) )
166 lexer->token = T_STOP;
170 /* If a token was pushed ahead, return it. */
171 if (lexer->put_token)
173 restore_token (lexer);
179 /* Skip whitespace. */
180 while (c_isspace ((unsigned char) *lexer->prog))
189 lexer->token = T_ENDCMD;
192 else if (!lex_get_line (lexer))
195 lexer->token = T_STOP;
199 if (lexer->put_token)
201 restore_token (lexer);
207 /* Actually parse the token. */
208 ds_clear (&lexer->tokstr);
210 switch (*lexer->prog)
213 case '0': case '1': case '2': case '3': case '4':
214 case '5': case '6': case '7': case '8': case '9':
218 /* `-' can introduce a negative number, or it can be a
219 token by itself. If it is not followed by a digit or a
220 decimal point, it is definitely not a number.
221 Otherwise, it might be either, but most of the time we
222 want it as a number. When the syntax calls for a `-'
223 token, lex_negative_to_dash() must be used to break
224 negative numbers into two tokens. */
225 if (*lexer->prog == '-')
227 ds_put_byte (&lexer->tokstr, *lexer->prog++);
228 while (c_isspace ((unsigned char) *lexer->prog))
231 if (!c_isdigit ((unsigned char) *lexer->prog) && *lexer->prog != '.')
233 lexer->token = T_DASH;
236 lexer->token = T_NEG_NUM;
239 lexer->token = T_POS_NUM;
241 /* Parse the number, copying it into tokstr. */
242 while (c_isdigit ((unsigned char) *lexer->prog))
243 ds_put_byte (&lexer->tokstr, *lexer->prog++);
244 if (*lexer->prog == '.')
246 ds_put_byte (&lexer->tokstr, *lexer->prog++);
247 while (c_isdigit ((unsigned char) *lexer->prog))
248 ds_put_byte (&lexer->tokstr, *lexer->prog++);
250 if (*lexer->prog == 'e' || *lexer->prog == 'E')
252 ds_put_byte (&lexer->tokstr, *lexer->prog++);
253 if (*lexer->prog == '+' || *lexer->prog == '-')
254 ds_put_byte (&lexer->tokstr, *lexer->prog++);
255 while (c_isdigit ((unsigned char) *lexer->prog))
256 ds_put_byte (&lexer->tokstr, *lexer->prog++);
259 /* Parse as floating point. */
260 lexer->tokval = c_strtod (ds_cstr (&lexer->tokstr), &tail);
263 msg (SE, _("%s does not form a valid number."),
264 ds_cstr (&lexer->tokstr));
267 ds_clear (&lexer->tokstr);
268 ds_put_byte (&lexer->tokstr, '0');
275 lexer->token = parse_string (lexer, CHARACTER_STRING);
279 lexer->token = T_PLUS;
284 lexer->token = T_SLASH;
289 lexer->token = T_EQUALS;
294 lexer->token = T_LPAREN;
299 lexer->token = T_RPAREN;
304 lexer->token = T_LBRACK;
309 lexer->token = T_RBRACK;
314 lexer->token = T_COMMA;
319 if (*++lexer->prog == '*')
322 lexer->token = T_EXP;
325 lexer->token = T_ASTERISK;
329 if (*++lexer->prog == '=')
334 else if (*lexer->prog == '>')
344 if (*++lexer->prog == '=')
354 if (*++lexer->prog == '=')
360 lexer->token = T_NOT;
365 lexer->token = T_AND;
374 if (lexer->prog[1] == '\'' || lexer->prog[1] == '"')
375 lexer->token = parse_string (lexer, BINARY_STRING);
377 lexer->token = parse_id (lexer);
381 if (lexer->prog[1] == '\'' || lexer->prog[1] == '"')
382 lexer->token = parse_string (lexer, OCTAL_STRING);
384 lexer->token = parse_id (lexer);
388 if (lexer->prog[1] == '\'' || lexer->prog[1] == '"')
389 lexer->token = parse_string (lexer, HEX_STRING);
391 lexer->token = parse_id (lexer);
395 if (lex_is_id1 (*lexer->prog))
397 lexer->token = parse_id (lexer);
402 unsigned char c = *lexer->prog++;
403 char *c_name = xasprintf (c_isgraph (c) ? "%c" : "\\%o", c);
404 msg (SE, _("Bad character in input: `%s'."), c_name);
413 /* Parses an identifier at the current position into tokid and
415 Returns the correct token type. */
417 parse_id (struct lexer *lexer)
419 struct substring rest_of_line
420 = ss_substr (ds_ss (&lexer->line_buffer),
421 ds_pointer_to_position (&lexer->line_buffer, lexer->prog),
423 struct substring id = ss_head (rest_of_line,
424 lex_id_get_length (rest_of_line));
425 lexer->prog += ss_length (id);
427 ds_assign_substring (&lexer->tokstr, id);
428 str_copy_trunc (lexer->tokid, sizeof lexer->tokid, ds_cstr (&lexer->tokstr));
429 return lex_id_to_token (id);
432 /* Reports an error to the effect that subcommand SBC may only be
435 lex_sbc_only_once (const char *sbc)
437 msg (SE, _("Subcommand %s may only be specified once."), sbc);
440 /* Reports an error to the effect that subcommand SBC is
443 lex_sbc_missing (struct lexer *lexer, const char *sbc)
445 lex_error (lexer, _("missing required subcommand %s"), sbc);
448 /* Prints a syntax error message containing the current token and
449 given message MESSAGE (if non-null). */
451 lex_error (struct lexer *lexer, const char *message, ...)
457 if (lexer->token == T_STOP)
458 ds_put_cstr (&s, _("Syntax error at end of file"));
459 else if (lexer->token == T_ENDCMD)
460 ds_put_cstr (&s, _("Syntax error at end of command"));
463 char *token_rep = lex_token_representation (lexer);
464 ds_put_format (&s, _("Syntax error at `%s'"), token_rep);
472 ds_put_cstr (&s, ": ");
474 va_start (args, message);
475 ds_put_vformat (&s, message, args);
479 msg (SE, "%s.", ds_cstr (&s));
483 /* Checks that we're at end of command.
484 If so, returns a successful command completion code.
485 If not, flags a syntax error and returns an error command
488 lex_end_of_command (struct lexer *lexer)
490 if (lexer->token != T_ENDCMD)
492 lex_error (lexer, _("expecting end of command"));
499 /* Token testing functions. */
501 /* Returns true if the current token is a number. */
503 lex_is_number (struct lexer *lexer)
505 return lexer->token == T_POS_NUM || lexer->token == T_NEG_NUM;
509 /* Returns true if the current token is a string. */
511 lex_is_string (struct lexer *lexer)
513 return lexer->token == T_STRING;
517 /* Returns the value of the current token, which must be a
518 floating point number. */
520 lex_number (struct lexer *lexer)
522 assert (lex_is_number (lexer));
523 return lexer->tokval;
526 /* Returns true iff the current token is an integer. */
528 lex_is_integer (struct lexer *lexer)
530 return (lex_is_number (lexer)
531 && lexer->tokval > LONG_MIN
532 && lexer->tokval <= LONG_MAX
533 && floor (lexer->tokval) == lexer->tokval);
536 /* Returns the value of the current token, which must be an
539 lex_integer (struct lexer *lexer)
541 assert (lex_is_integer (lexer));
542 return lexer->tokval;
545 /* Token matching functions. */
547 /* If TOK is the current token, skips it and returns true
548 Otherwise, returns false. */
550 lex_match (struct lexer *lexer, enum token_type t)
552 if (lexer->token == t)
561 /* If the current token is the identifier S, skips it and returns
562 true. The identifier may be abbreviated to its first three
564 Otherwise, returns false. */
566 lex_match_id (struct lexer *lexer, const char *s)
568 return lex_match_id_n (lexer, s, 3);
571 /* If the current token is the identifier S, skips it and returns
572 true. The identifier may be abbreviated to its first N
574 Otherwise, returns false. */
576 lex_match_id_n (struct lexer *lexer, const char *s, size_t n)
578 if (lexer->token == T_ID
579 && lex_id_match_n (ss_cstr (s), ss_cstr (lexer->tokid), n))
588 /* If the current token is integer N, skips it and returns true.
589 Otherwise, returns false. */
591 lex_match_int (struct lexer *lexer, int x)
593 if (lex_is_integer (lexer) && lex_integer (lexer) == x)
602 /* Forced matches. */
604 /* If this token is identifier S, fetches the next token and returns
606 Otherwise, reports an error and returns zero. */
608 lex_force_match_id (struct lexer *lexer, const char *s)
610 if (lex_match_id (lexer, s))
614 lex_error (lexer, _("expecting `%s'"), s);
619 /* If the current token is T, skips the token. Otherwise, reports an
620 error and returns from the current function with return value false. */
622 lex_force_match (struct lexer *lexer, enum token_type t)
624 if (lexer->token == t)
631 lex_error (lexer, _("expecting `%s'"), lex_token_name (t));
636 /* If this token is a string, does nothing and returns true.
637 Otherwise, reports an error and returns false. */
639 lex_force_string (struct lexer *lexer)
641 if (lex_is_string (lexer))
645 lex_error (lexer, _("expecting string"));
650 /* If this token is an integer, does nothing and returns true.
651 Otherwise, reports an error and returns false. */
653 lex_force_int (struct lexer *lexer)
655 if (lex_is_integer (lexer))
659 lex_error (lexer, _("expecting integer"));
664 /* If this token is a number, does nothing and returns true.
665 Otherwise, reports an error and returns false. */
667 lex_force_num (struct lexer *lexer)
669 if (lex_is_number (lexer))
672 lex_error (lexer, _("expecting number"));
676 /* If this token is an identifier, does nothing and returns true.
677 Otherwise, reports an error and returns false. */
679 lex_force_id (struct lexer *lexer)
681 if (lexer->token == T_ID)
684 lex_error (lexer, _("expecting identifier"));
688 /* Weird token functions. */
690 /* Returns the likely type of the next token, or 0 if it's hard to tell. */
692 lex_look_ahead (struct lexer *lexer)
694 if (lexer->put_token)
695 return lexer->put_token;
699 if (NULL == lexer->prog && ! lex_get_line (lexer) )
704 while (c_isspace ((unsigned char) *lexer->prog))
711 else if (!lex_get_line (lexer))
714 if (lexer->put_token)
715 return lexer->put_token;
718 switch (toupper ((unsigned char) *lexer->prog))
720 case 'X': case 'B': case 'O':
721 if (lexer->prog[1] == '\'' || lexer->prog[1] == '"')
729 case '0': case '1': case '2': case '3': case '4':
730 case '5': case '6': case '7': case '8': case '9':
761 return lexer->prog[1] == '*' ? T_EXP : T_ASTERISK;
764 return (lexer->prog[1] == '=' ? T_LE
765 : lexer->prog[1] == '>' ? T_NE
769 return lexer->prog[1] == '=' ? T_GE : T_GT;
772 return lexer->prog[1] == '=' ? T_NE : T_NOT;
781 if (lex_is_id1 (*lexer->prog))
788 /* Makes the current token become the next token to be read; the
789 current token is set to T. */
791 lex_put_back (struct lexer *lexer, enum token_type t)
797 /* Makes the current token become the next token to be read; the
798 current token is set to the identifier ID. */
800 lex_put_back_id (struct lexer *lexer, const char *id)
802 assert (lex_id_to_token (ss_cstr (id)) == T_ID);
805 ds_assign_cstr (&lexer->tokstr, id);
806 str_copy_trunc (lexer->tokid, sizeof lexer->tokid, ds_cstr (&lexer->tokstr));
809 /* Weird line processing functions. */
811 /* Returns the entire contents of the current line. */
813 lex_entire_line (const struct lexer *lexer)
815 return ds_cstr (&lexer->line_buffer);
818 const struct string *
819 lex_entire_line_ds (const struct lexer *lexer)
821 return &lexer->line_buffer;
824 /* As lex_entire_line(), but only returns the part of the current line
825 that hasn't already been tokenized. */
827 lex_rest_of_line (const struct lexer *lexer)
832 /* Returns true if the current line ends in a terminal dot,
835 lex_end_dot (const struct lexer *lexer)
840 /* Causes the rest of the current input line to be ignored for
841 tokenization purposes. */
843 lex_discard_line (struct lexer *lexer)
845 ds_cstr (&lexer->line_buffer); /* Ensures ds_end points to something valid */
846 lexer->prog = ds_end (&lexer->line_buffer);
848 lexer->put_token = 0;
852 /* Discards the rest of the current command.
853 When we're reading commands from a file, we skip tokens until
854 a terminal dot or EOF.
855 When we're reading commands interactively from the user,
856 that's just discarding the current line, because presumably
857 the user doesn't want to finish typing a command that will be
860 lex_discard_rest_of_command (struct lexer *lexer)
862 if (!getl_is_interactive (lexer->ss))
864 while (lexer->token != T_STOP && lexer->token != T_ENDCMD)
868 lex_discard_line (lexer);
871 /* Weird line reading functions. */
873 /* Remove C-style comments in STRING, begun by slash-star and
874 terminated by star-slash or newline. */
876 strip_comments (struct string *string)
884 for (cp = ds_cstr (string); *cp; )
886 /* If we're not in a comment, check for quote marks. */
891 else if (*cp == '\'' || *cp == '"')
895 /* If we're not inside a quotation, check for comment. */
898 if (cp[0] == '/' && cp[1] == '*')
905 else if (in_comment && cp[0] == '*' && cp[1] == '/')
914 /* Check commenting. */
921 /* Prepares LINE, which is subject to the given SYNTAX rules, for
922 tokenization by stripping comments and determining whether it
923 is the beginning or end of a command and storing into
924 *LINE_STARTS_COMMAND and *LINE_ENDS_COMMAND appropriately. */
926 lex_preprocess_line (struct string *line,
927 enum syntax_mode syntax,
928 bool *line_starts_command,
929 bool *line_ends_command)
931 strip_comments (line);
932 ds_rtrim (line, ss_cstr (CC_SPACES));
933 *line_ends_command = (ds_chomp (line, settings_get_endcmd ())
934 || (ds_is_empty (line) && settings_get_nulline ()));
935 *line_starts_command = false;
936 if (syntax == GETL_BATCH)
938 int first = ds_first (line);
939 *line_starts_command = !c_isspace (first);
940 if (first == '+' || first == '-')
941 *ds_data (line) = ' ';
945 /* Reads a line, without performing any preprocessing. */
947 lex_get_line_raw (struct lexer *lexer)
949 bool ok = getl_read_line (lexer->ss, &lexer->line_buffer);
952 const char *line = ds_cstr (&lexer->line_buffer);
953 text_item_submit (text_item_create (TEXT_ITEM_SYNTAX, line));
960 /* Reads a line for use by the tokenizer, and preprocesses it by
961 removing comments, stripping trailing whitespace and the
962 terminal dot, and removing leading indentors. */
964 lex_get_line (struct lexer *lexer)
966 bool line_starts_command;
968 if (!lex_get_line_raw (lexer))
971 lex_preprocess_line (&lexer->line_buffer,
972 lex_current_syntax_mode (lexer),
973 &line_starts_command, &lexer->dot);
975 if (line_starts_command)
976 lexer->put_token = T_ENDCMD;
978 lexer->prog = ds_cstr (&lexer->line_buffer);
984 /* Returns the name of a token. */
986 lex_token_name (enum token_type token)
1078 /* Returns an ASCII representation of the current token as a
1079 malloc()'d string. */
1081 lex_token_representation (struct lexer *lexer)
1085 switch (lexer->token)
1090 return ds_xstrdup (&lexer->tokstr);
1097 for (sp = ds_cstr (&lexer->tokstr); sp < ds_end (&lexer->tokstr); sp++)
1098 if (!c_isprint ((unsigned char) *sp))
1104 token_rep = xmalloc (2 + ds_length (&lexer->tokstr) * 2 + 1 + 1);
1112 for (sp = ds_cstr (&lexer->tokstr); *sp; )
1116 *dp++ = (unsigned char) *sp++;
1119 for (sp = ds_cstr (&lexer->tokstr); sp < ds_end (&lexer->tokstr); sp++)
1121 *dp++ = (((unsigned char) *sp) >> 4)["0123456789ABCDEF"];
1122 *dp++ = (((unsigned char) *sp) & 15)["0123456789ABCDEF"];
1131 return xstrdup (lex_token_name (lexer->token));
1135 /* Really weird functions. */
1137 /* Most of the time, a `-' is a lead-in to a negative number. But
1138 sometimes it's actually part of the syntax. If a dash can be part
1139 of syntax then this function is called to rip it off of a
1142 lex_negative_to_dash (struct lexer *lexer)
1144 if (lexer->token == T_NEG_NUM)
1146 lexer->token = T_POS_NUM;
1147 lexer->tokval = -lexer->tokval;
1148 ds_assign_substring (&lexer->tokstr, ds_substr (&lexer->tokstr, 1, SIZE_MAX));
1150 lexer->token = T_DASH;
1154 /* Skip a COMMENT command. */
1156 lex_skip_comment (struct lexer *lexer)
1160 if (!lex_get_line (lexer))
1162 lexer->put_token = T_STOP;
1167 if (lexer->put_token == T_ENDCMD)
1170 ds_cstr (&lexer->line_buffer); /* Ensures ds_end will point to a valid char */
1171 lexer->prog = ds_end (&lexer->line_buffer);
1177 /* Private functions. */
1179 /* When invoked, tokstr contains a string of binary, octal, or
1180 hex digits, according to TYPE. The string is converted to
1181 characters having the specified values. */
1183 convert_numeric_string_to_char_string (struct lexer *lexer,
1184 enum string_type type)
1186 const char *base_name;
1196 base_name = _("binary");
1201 base_name = _("octal");
1206 base_name = _("hex");
1214 byte_cnt = ds_length (&lexer->tokstr) / chars_per_byte;
1215 if (ds_length (&lexer->tokstr) % chars_per_byte)
1216 msg (SE, _("String of %s digits has %zu characters, which is not a "
1218 base_name, ds_length (&lexer->tokstr), chars_per_byte);
1220 p = ds_cstr (&lexer->tokstr);
1221 for (i = 0; i < byte_cnt; i++)
1227 for (j = 0; j < chars_per_byte; j++, p++)
1231 if (*p >= '0' && *p <= '9')
1235 static const char alpha[] = "abcdef";
1236 const char *q = strchr (alpha, tolower ((unsigned char) *p));
1245 msg (SE, _("`%c' is not a valid %s digit."), *p, base_name);
1247 value = value * base + v;
1250 ds_cstr (&lexer->tokstr)[i] = (unsigned char) value;
1253 ds_truncate (&lexer->tokstr, byte_cnt);
1256 /* Parses a string from the input buffer into tokstr. The input
1257 buffer pointer lexer->prog must point to the initial single or double
1258 quote. TYPE indicates the type of string to be parsed.
1259 Returns token type. */
1261 parse_string (struct lexer *lexer, enum string_type type)
1263 if (type != CHARACTER_STRING)
1266 /* Accumulate the entire string, joining sections indicated by +
1270 /* Single or double quote. */
1271 int c = *lexer->prog++;
1273 /* Accumulate section. */
1276 /* Check end of line. */
1277 if (*lexer->prog == '\0')
1279 msg (SE, _("Unterminated string constant."));
1283 /* Double quote characters to embed them in strings. */
1284 if (*lexer->prog == c)
1286 if (lexer->prog[1] == c)
1292 ds_put_byte (&lexer->tokstr, *lexer->prog++);
1296 /* Skip whitespace after final quote mark. */
1297 if (lexer->prog == NULL)
1301 while (c_isspace ((unsigned char) *lexer->prog))
1309 if (!lex_get_line (lexer))
1313 /* Skip plus sign. */
1314 if (*lexer->prog != '+')
1318 /* Skip whitespace after plus sign. */
1319 if (lexer->prog == NULL)
1323 while (c_isspace ((unsigned char) *lexer->prog))
1331 if (!lex_get_line (lexer))
1333 msg (SE, _("Unexpected end of file in string concatenation."));
1338 /* Ensure that a valid string follows. */
1339 if (*lexer->prog != '\'' && *lexer->prog != '"')
1341 msg (SE, _("String expected following `+'."));
1346 /* We come here when we've finished concatenating all the string sections
1347 into one large string. */
1349 if (type != CHARACTER_STRING)
1350 convert_numeric_string_to_char_string (lexer, type);
1355 /* Token Accessor Functions */
1358 lex_token (const struct lexer *lexer)
1360 return lexer->token;
1364 lex_tokval (const struct lexer *lexer)
1366 return lexer->tokval;
1370 lex_tokid (const struct lexer *lexer)
1372 return lexer->tokid;
1375 const struct string *
1376 lex_tokstr (const struct lexer *lexer)
1378 return &lexer->tokstr;
1381 /* If the lexer is positioned at the (pseudo)identifier S, which
1382 may contain a hyphen ('-'), skips it and returns true. Each
1383 half of the identifier may be abbreviated to its first three
1385 Otherwise, returns false. */
1387 lex_match_hyphenated_word (struct lexer *lexer, const char *s)
1389 const char *hyphen = strchr (s, '-');
1391 return lex_match_id (lexer, s);
1392 else if (lexer->token != T_ID
1393 || !lex_id_match (ss_buffer (s, hyphen - s), ss_cstr (lexer->tokid))
1394 || lex_look_ahead (lexer) != T_DASH)
1399 lex_force_match (lexer, T_DASH);
1400 lex_force_match_id (lexer, hyphen + 1);