home *** CD-ROM | disk | FTP | other *** search
/ Geek Gadgets 1 / ADE-1.bin / ade-dist / octave-1.1.1p1-base.tgz / octave-1.1.1p1-base.tar / fsf / octave / src / lex.l < prev    next >
Text File  |  1995-02-01  |  40KB  |  1,932 lines

  1. /* lex.l                                                -*- C++ -*-
  2.  
  3. Copyright (C) 1992, 1993, 1994, 1995 John W. Eaton
  4.  
  5. This file is part of Octave.
  6.  
  7. Octave is free software; you can redistribute it and/or modify it
  8. under the terms of the GNU General Public License as published by the
  9. Free Software Foundation; either version 2, or (at your option) any
  10. later version.
  11.  
  12. Octave is distributed in the hope that it will be useful, but WITHOUT
  13. ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  14. FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  15. for more details.
  16.  
  17. You should have received a copy of the GNU General Public License
  18. along with GNU CC; see the file COPYING.  If not, write to the Free
  19. Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
  20.  
  21. */
  22.  
  23. %x HELP_FCN
  24. %s TEXT_FCN
  25. %s MATRIX
  26.  
  27. %{
  28. #define SHORT_CIRCUIT_LOGICALS 1
  29.  
  30. #ifdef HAVE_CONFIG_H
  31. #include "config.h"
  32. #endif
  33.  
  34. #include <strstream.h>
  35. #include <ctype.h>
  36. #include <string.h>
  37.  
  38. #include "input.h"
  39. #include "token.h"
  40.  
  41. #include "SLStack.h"
  42.  
  43. // Stack to hold tokens so that we can delete them when the parser is
  44. // reset and avoid growing forever just because we are stashing some
  45. // information.  This has to appear before lex.h is included, because
  46. // one of the macros defined there uses token_stack.
  47. static SLStack <token*> token_stack;
  48.  
  49. #include "user-prefs.h"
  50. #include "variables.h"
  51. #include "octave.h"
  52. #include "symtab.h"
  53. #include "error.h"
  54. #include "utils.h"
  55. #include "tree-base.h"
  56. #include "tree-expr.h"
  57. #include "tree-cmd.h"
  58. #include "tree-misc.h"
  59. #include "tree-plot.h"
  60. #include "tree-const.h"
  61. #include "y.tab.h"
  62. #include "parse.h"
  63. #include "lex.h"
  64.  
  65. // Nonzero means we think we are looking at a set command.
  66. static int doing_set = 0;
  67.  
  68. // GAG.  Stupid kludge so that [[1,2][3,4]] will work.
  69. static do_comma_insert = 0;
  70.  
  71. // Brace level count.
  72. static int braceflag = 0;
  73.  
  74. // Return transpose or start a string?
  75. int quote_is_transpose = 0;
  76.  
  77. // Nonzero means we thing we are looking at the beginning of a
  78. // function definition.
  79. int beginning_of_function = 0;
  80.  
  81. // Nonzero means that we should convert spaces to a comma inside a
  82. // matrix definition.
  83. static int convert_spaces_to_comma = 1;
  84.  
  85. // Another context hack, this time for the plot command's `using',
  86. // `title', and `with' keywords.
  87. static int cant_be_identifier = 0;
  88.  
  89. #define BRACE 1
  90. #define PAREN 2
  91.  
  92. // Did eat_whitespace() eat a space or tab, or a newline, or both?
  93. #define ATE_SPACE_OR_TAB 1
  94. #define ATE_NEWLINE 2
  95.  
  96. // Is the closest nesting level a square brace or a paren?
  97. //
  98. //  BRACE -> spaces are important (they can turn into commas)
  99. //           new lines are important (they can turn into semicolons)
  100. //
  101. //  PAREN -> spaces and new lines are not important
  102.  
  103. static SLStack <int> nesting_level;
  104.  
  105. // Forward declarations for functions defined at the bottom of this
  106. // file.
  107.  
  108. static void do_string_escapes (char *s);
  109. static void fixup_column_count (char *s);
  110. static void do_comma_insert_check (void);
  111. static int is_plot_keyword (char *s);
  112. static int is_keyword (char *s);
  113. static char *plot_style_token (char *s);
  114. static symbol_record *lookup_identifier (char *s);
  115. static void grab_help_text (void);
  116. static int match_any (char c, char *s);
  117. static int next_token_is_bin_op (int spc_prev, char *yytext);
  118. static int next_token_is_postfix_unary_op (int spc_prev, char *yytext);
  119. static char *strip_trailing_whitespace (char *s);
  120. static void handle_number (char *yytext);
  121. static int handle_string (char delim, int text_style = 0);
  122. static int handle_close_brace (int spc_gobbled);
  123. static int handle_identifier (char *tok, int spc_gobbled);
  124. static int have_continuation (int trailing_comments_ok = 1);
  125. static int have_ellipsis_continuation (int trailing_comments_ok = 1);
  126. static int eat_whitespace (void);
  127. static int eat_continuation (void);
  128.  
  129. %}
  130.  
  131. D    [0-9]
  132. S    [ \t]
  133. NL    [\n]
  134. SNL    [ \t\n]
  135. EL    (\.\.\.)
  136. BS    (\\)
  137. CONT    ({EL}|{BS})
  138. Im    [iIjJ]
  139. CCHAR    [#%]
  140. COMMENT    ({CCHAR}.*{NL})
  141. SNLCMT    ({SNL}|{COMMENT})
  142. NOTEQ    ((~=)|(!=)|(<>))
  143. POW    ((\*\*)|(\^))
  144. EPOW    (\.{POW})
  145. PLUS    ((\+)|(\.\+))
  146. MINUS    ((\-)|(\.\-))
  147. NOT    ((\~)|(\!))
  148. IDENT    ([_a-zA-Z][_a-zA-Z0-9]*)
  149. EXPON    ([DdEe][+-]?{D}+)
  150. NUMBER    (({D}+\.?{D}*{EXPON}?)|(\.{D}+{EXPON}?))
  151. %%
  152.  
  153. %{
  154. // Help and other text-style functions are a pain in the ass.  This
  155. // stuff needs to be simplified.  May require some changes in the
  156. // parser too.
  157. %}
  158.  
  159. <HELP_FCN>{NL} |
  160. <TEXT_FCN>{NL} {
  161.     BEGIN 0;
  162.     current_input_column = 1;
  163.     quote_is_transpose = 0;
  164.     cant_be_identifier = 0;
  165.     convert_spaces_to_comma = 1;
  166.     return '\n';
  167.   }
  168.  
  169. <TEXT_FCN>[\;\,] {
  170.     if (doing_set && strcmp (yytext, ",") == 0)
  171.       {
  172.     TOK_PUSH_AND_RETURN (yytext, TEXT);
  173.       }
  174.     else
  175.       {
  176.     BEGIN 0;
  177.     if (strcmp (yytext, ",") == 0)
  178.       TOK_RETURN (',');
  179.     else
  180.       TOK_RETURN (';');
  181.       }
  182.   }
  183.  
  184. <TEXT_FCN>[\"\'] {
  185.     current_input_column++;
  186.     return handle_string (yytext[0], 1);
  187.   }
  188.  
  189. <HELP_FCN>[^ \t\n]*{S}*    |
  190. <TEXT_FCN>[^ \t\n\;\,]*{S}* {
  191.     static char *tok = 0;
  192.     delete [] tok;
  193.     tok = strip_trailing_whitespace (yytext);
  194.     TOK_PUSH_AND_RETURN (tok, TEXT);
  195.   }
  196.  
  197. %{
  198. // For this and the next two rules, we're looking at ']', and we
  199. // need to know if the next token is `=' or `=='.
  200. //
  201. // It would have been so much easier if the delimiters were simply
  202. // different for the expression on the left hand side of the equals
  203. // operator.
  204. //
  205. // It's also a pain in the ass to decide whether to insert a comma
  206. // after seeing a ']' character...
  207. %}
  208.  
  209. <MATRIX>{SNL}*\]{S}* {
  210.     fixup_column_count (yytext);
  211.     int c = yytext[yyleng-1];
  212.     int cont_is_spc = eat_continuation ();
  213.     int spc_gobbled = (cont_is_spc || c == ' ' || c == '\t');
  214.     return handle_close_brace (spc_gobbled);
  215.   }
  216.  
  217. %{
  218. // Commas are element separators in matrix constants.  If we don't
  219. // check for continuations here we can end up inserting too many
  220. // commas.
  221. %}
  222.  
  223. <MATRIX>{S}*\,{S}* {
  224.     current_input_column += yyleng;
  225.     int tmp = eat_continuation ();
  226.     quote_is_transpose = 0;
  227.     cant_be_identifier = 0;
  228.     convert_spaces_to_comma = 1;
  229.     if (user_pref.whitespace_in_literal_matrix != 2
  230.     && (tmp & ATE_NEWLINE) == ATE_NEWLINE)
  231.       unput (';');
  232.     return (',');
  233.   }
  234.  
  235. %{
  236. // In some cases, spaces in matrix constants can turn into commas.
  237. // If commas are required, spaces are not important in matrix
  238. // constants so we just eat them.  If we don't check for continuations
  239. // here we can end up inserting too many commas.
  240. %}
  241.  
  242. <MATRIX>{S}+ {
  243.     current_input_column += yyleng;
  244.     if (user_pref.whitespace_in_literal_matrix != 2)
  245.       {
  246.     int tmp = eat_continuation ();
  247.     int bin_op = next_token_is_bin_op (1, yytext);
  248.     int postfix_un_op = next_token_is_postfix_unary_op (1, yytext);
  249.  
  250.     if (! (postfix_un_op || bin_op || nesting_level.empty ())
  251.         && nesting_level.top () == BRACE
  252.         && convert_spaces_to_comma)
  253.       {
  254.         quote_is_transpose = 0;
  255.         cant_be_identifier = 0;
  256.         convert_spaces_to_comma = 1;
  257.         if ((tmp & ATE_NEWLINE) == ATE_NEWLINE)
  258.           unput (';');
  259.         return (',');
  260.       }
  261.       }
  262.   }
  263.  
  264. %{
  265. // Semicolons are handled as row seprators in matrix constants.  If we
  266. // don't eat whitespace here we can end up inserting too many
  267. // semicolons.
  268. %}
  269.  
  270. <MATRIX>{SNLCMT}*;{SNLCMT}* {
  271.     fixup_column_count (yytext);
  272.     eat_whitespace ();
  273.     quote_is_transpose = 0;
  274.     cant_be_identifier = 0;
  275.     convert_spaces_to_comma = 1;
  276.     return ';';
  277.   }
  278.  
  279. %{
  280. // In some cases, new lines can also become row separators.  If we
  281. // don't eat whitespace here we can end up inserting too many
  282. // semicolons.
  283. %}
  284.  
  285. <MATRIX>{SNLCMT}*\n{SNLCMT}* {
  286.     fixup_column_count (yytext);
  287.     eat_whitespace ();
  288.     if (user_pref.whitespace_in_literal_matrix != 2)
  289.       {
  290.     quote_is_transpose = 0;
  291.     cant_be_identifier = 0;
  292.     convert_spaces_to_comma = 1;
  293.  
  294.     if (nesting_level.empty ())
  295.       return LEXICAL_ERROR;
  296.  
  297.     if (nesting_level.top () == BRACE)
  298.       return ';';
  299.       }
  300.   }
  301.  
  302. %{
  303. // Open and close brace are handled differently if we are in the range
  304. // part of a plot command.
  305. //
  306. %}
  307.  
  308. \[{S}* {
  309.     nesting_level.push (BRACE);
  310.  
  311.     current_input_column += yyleng;
  312.     quote_is_transpose = 0;
  313.     cant_be_identifier = 0;
  314.     convert_spaces_to_comma = 1;
  315.  
  316.     promptflag--;
  317.     eat_whitespace ();
  318.  
  319.     if (plotting && ! past_plot_range)
  320.       {
  321.     in_plot_range = 1;
  322.     return OPEN_BRACE;
  323.       }
  324.     else
  325.       {
  326.     mlnm.push (1);
  327.     braceflag++;
  328.     BEGIN MATRIX;
  329.     return '[';
  330.       }
  331.   }
  332.  
  333. \] {
  334.     if (! nesting_level.empty ())
  335.       nesting_level.pop ();
  336.  
  337.     if (plotting && ! past_plot_range)
  338.       {
  339.     in_plot_range = 0;
  340.     TOK_RETURN (CLOSE_BRACE);
  341.       }
  342.     else
  343.       TOK_RETURN (']');
  344.   }
  345.  
  346. %{
  347. // Imaginary numbers.
  348. %}
  349.  
  350. {NUMBER}{Im} {
  351.     handle_number (yytext);
  352.     return IMAG_NUM;
  353.   }
  354.  
  355. %{
  356. // Real numbers.  Don't grab the `.' part of a dot operator as part of
  357. // the constant.
  358. %}
  359.  
  360. {D}+/\.[\*/\\^'] |
  361. {NUMBER} {
  362.     handle_number (yytext);
  363.     return NUM;
  364.   }
  365.  
  366. %{
  367. // Eat whitespace.  Whitespace inside matrix constants is handled by
  368. // the <MATRIX> start state code above.
  369. %}
  370.  
  371. {S}* {
  372.     current_input_column += yyleng;
  373.   }
  374.  
  375. %{
  376. // Continuation lines.  Allow comments after continuations.
  377. %}
  378.  
  379. {CONT}{S}*{NL} |
  380. {CONT}{S}*{COMMENT} {
  381.     promptflag--;
  382.     current_input_column = 1;
  383.   }
  384.  
  385. %{
  386. // An ellipsis not at the end of a line is not a continuation, but
  387. // does have another meaning.
  388. %}
  389.  
  390. {EL} {
  391.     return ELLIPSIS;
  392.   }
  393.  
  394. %{
  395. // End of file.
  396. %}
  397.  
  398. <<EOF>> {
  399.     TOK_RETURN (END_OF_INPUT);
  400.   }
  401.  
  402. %{
  403. // Identifiers.  Truncate the token at the first space or tab but
  404. // don't write directly on yytext.
  405. %}
  406.  
  407. {IDENT}{S}* {
  408.     static char *tok = 0;
  409.     delete [] tok;
  410.     tok = strip_trailing_whitespace (yytext);
  411.     int c = yytext[yyleng-1];
  412.     int cont_is_spc = eat_continuation ();
  413.     int spc_gobbled = (cont_is_spc || c == ' ' || c == '\t');
  414.     return handle_identifier (tok, spc_gobbled);
  415.   }
  416.  
  417. %{
  418. // A new line character.  New line characters inside matrix constants
  419. // are handled by the <MATRIX> start state code above.  If closest
  420. // nesting is inside parentheses, don't return a row separator.
  421. %}
  422.  
  423. {NL} {
  424.     quote_is_transpose = 0;
  425.     cant_be_identifier = 0;
  426.     current_input_column = 1;
  427.     convert_spaces_to_comma = 1;
  428.  
  429.     if (nesting_level.empty ())
  430.       return '\n';
  431.  
  432.     if (nesting_level.top () == BRACE)
  433.       return LEXICAL_ERROR;
  434.   }
  435.  
  436. %{
  437. // Single quote can either be the beginning of a string or a transpose
  438. // operator. 
  439. %}
  440.  
  441. "'" {
  442.     current_input_column++;
  443.     convert_spaces_to_comma = 1;
  444.  
  445.     if (quote_is_transpose)
  446.       {
  447.     do_comma_insert_check ();
  448.     return QUOTE;
  449.       }
  450.     else
  451.       return handle_string ('\'');
  452.   }
  453.  
  454. %{
  455. // Double quotes always begin strings.
  456. %}
  457.  
  458. \" {
  459.     current_input_column++;
  460.     return handle_string ('"');
  461. }
  462.  
  463. %{
  464. // The colon operator is handled differently if we are in the range
  465. // part of a plot command.
  466. %}
  467.  
  468. ":" {
  469.     if (plotting && (in_plot_range || in_plot_using))
  470.       BIN_OP_RETURN (COLON, 1);
  471.     else
  472.       BIN_OP_RETURN (':', 0);
  473.   }
  474.  
  475. %{
  476. // Gobble comments.  If closest nesting is inside parentheses, don't
  477. // return a new line.
  478. %} 
  479.  
  480. {CCHAR} {
  481.     if (! help_buf && beginning_of_function && nesting_level.empty ())
  482.       {
  483.     grab_help_text ();
  484.     beginning_of_function = 0;
  485.       }
  486.     else
  487.       {
  488.     int c;
  489.     while ((c = yyinput ()) != EOF && c != '\n')
  490.       ; // Eat comment.
  491.       }
  492.  
  493.     quote_is_transpose = 0;
  494.     cant_be_identifier = 0;
  495.     current_input_column = 1;
  496.     convert_spaces_to_comma = 1;
  497.  
  498.     if (nesting_level.empty () || nesting_level.top () == BRACE)
  499.       return '\n';
  500.   }
  501.  
  502. %{
  503. // Other operators.
  504. %}
  505.  
  506. ".*"        { BIN_OP_RETURN (EMUL, 0); }
  507. "./"        { BIN_OP_RETURN (EDIV, 0); }
  508. ".\\"        { BIN_OP_RETURN (ELEFTDIV, 0); }
  509. {EPOW}        { BIN_OP_RETURN (EPOW, 0); }
  510. ".'"        { do_comma_insert_check (); BIN_OP_RETURN (TRANSPOSE, 1); }
  511. "++"        { do_comma_insert_check (); BIN_OP_RETURN (PLUS_PLUS, 1); }
  512. "--"        { do_comma_insert_check (); BIN_OP_RETURN (MINUS_MINUS, 1); }
  513. "<="        { BIN_OP_RETURN (EXPR_LE, 0); }
  514. "=="        { BIN_OP_RETURN (EXPR_EQ, 0); }
  515. {NOTEQ}        { BIN_OP_RETURN (EXPR_NE, 0); }
  516. ">="        { BIN_OP_RETURN (EXPR_GE, 0); }
  517. "|"        { BIN_OP_RETURN (EXPR_OR, 0); }
  518. "&"        { BIN_OP_RETURN (EXPR_AND, 0); }
  519. "<"        { BIN_OP_RETURN (EXPR_LT, 0); }
  520. ">"        { BIN_OP_RETURN (EXPR_GT, 0); }
  521. "*"        { BIN_OP_RETURN ('*', 0); }
  522. "/"        { BIN_OP_RETURN ('/', 0); }
  523. "\\"        { BIN_OP_RETURN (LEFTDIV, 0); }
  524. ";"        { BIN_OP_RETURN (';', 1); }
  525. ","        { BIN_OP_RETURN (',', 1); }
  526. {POW}        { BIN_OP_RETURN (POW, 0); }
  527. "="        { BIN_OP_RETURN ('=', 1); }
  528.  
  529. "||" {
  530. #ifdef SHORT_CIRCUIT_LOGICALS
  531.     BIN_OP_RETURN (EXPR_OR_OR, 0);
  532. #else
  533.     BIN_OP_RETURN (EXPR_OR, 0);
  534. #endif
  535.   }
  536.  
  537. "&&" {
  538. #ifdef SHORT_CIRCUIT_LOGICALS
  539.     BIN_OP_RETURN (EXPR_AND_AND, 0);
  540. #else
  541.     BIN_OP_RETURN (EXPR_AND, 0);
  542. #endif
  543.   }
  544.  
  545. {NOT} {
  546.     if (plotting && ! in_plot_range)
  547.       past_plot_range = 1;
  548.     BIN_OP_RETURN (EXPR_NOT, 0);
  549.   }
  550.  
  551. {PLUS} { 
  552.     if (plotting && ! in_plot_range)
  553.       past_plot_range = 1;
  554.     BIN_OP_RETURN ('+', 0);
  555.   }
  556.  
  557. {MINUS} { 
  558.     if (plotting && ! in_plot_range)
  559.       past_plot_range = 1;
  560.     BIN_OP_RETURN ('-', 0);
  561.   }
  562.  
  563. "(" {
  564.     if (plotting && ! in_plot_range)
  565.       past_plot_range = 1;
  566.     nesting_level.push (PAREN);
  567.     promptflag--;
  568.     TOK_RETURN ('(');
  569.   }
  570.  
  571. ")" {
  572.     if (! nesting_level.empty ())
  573.       nesting_level.pop ();
  574.  
  575.     current_input_column++;
  576.     cant_be_identifier = 1;
  577.     quote_is_transpose = 1;
  578.     convert_spaces_to_comma = (! nesting_level.empty ()
  579.                    && nesting_level.top () == BRACE);
  580.     do_comma_insert_check ();
  581.     return ')';
  582.   }
  583.  
  584. %{
  585. // We return everything else as single character tokens, which should
  586. // eventually result in a parse error.
  587. %}
  588.  
  589. .        { TOK_RETURN (yytext[0]); }
  590.  
  591. %%
  592.  
  593. // GAG.
  594. //
  595. // If we're reading a matrix and the next character is '[', make sure
  596. // that we insert a comma ahead of it.
  597.  
  598. void
  599. do_comma_insert_check (void)
  600. {
  601.   int spc_gobbled = eat_continuation ();
  602.   int c = yyinput ();
  603.   yyunput (c, yytext);
  604.   if (spc_gobbled)
  605.     yyunput (' ', yytext);
  606.   do_comma_insert = (braceflag && c == '[');
  607. }
  608.  
  609. // Fix things up for errors or interrupts.  The parser is never called
  610. // recursively, so it is always safe to reinitialize its state before
  611. // doing any parsing.
  612.  
  613. void
  614. reset_parser (void)
  615. {
  616. // Start off on the right foot.
  617.   BEGIN 0;
  618.   error_state = 0;
  619.  
  620. // We do want a prompt by default.
  621.   promptflag = 1;
  622.  
  623. // Not initially screwed by `function [...] = f (...)' syntax.
  624.   maybe_screwed = 0;
  625.   maybe_screwed_again = 0;
  626.  
  627. // Not initially inside a loop or if statement.
  628.   looping = 0;
  629.   iffing = 0;
  630.  
  631. // Quote marks strings intially.
  632.   quote_is_transpose = 0;
  633.  
  634. // Next token can be identifier.
  635.   cant_be_identifier = 0;
  636.  
  637. // No need to do comma insert or convert spaces to comma at beginning
  638. // of input. 
  639.   do_comma_insert = 0;
  640.   convert_spaces_to_comma = 1;
  641.  
  642. // Not initially defining a function.
  643.   beginning_of_function = 0;
  644.   defining_func = 0;
  645.  
  646. // Not initially doing any plotting or setting of plot attributes.
  647.   plotting = 0;
  648.   in_plot_range = 0;
  649.   past_plot_range = 0;
  650.   in_plot_using = 0;
  651.   in_plot_style = 0;
  652.   doing_set = 0;
  653.  
  654. // Not initially looking at indirect references.
  655.   looking_at_indirect_ref = 0;
  656.  
  657. // Error may have occurred inside some parentheses or braces.
  658.   nesting_level.clear ();
  659.  
  660. // Not initially defining a matrix list.
  661.   braceflag = 0;
  662.   ml.clear ();
  663.   mlnm.clear ();
  664.  
  665. // Clear out the stack of token info used to track line and column
  666. // numbers.
  667.   while (! token_stack.empty ())
  668.     delete token_stack.pop ();
  669.  
  670. // Can be reset by defining a function.
  671.   if (! (reading_script_file || reading_fcn_file))
  672.     {
  673.       current_input_column = 1;
  674.       input_line_number = current_command_number - 1;
  675.     }
  676.  
  677. // Only ask for input from stdin if we are expecting interactive
  678. // input.
  679.   if (interactive && ! (reading_fcn_file || get_input_from_eval_string))
  680.     yyrestart (stdin);
  681.  
  682. // Delete the buffer for help text.
  683.   delete [] help_buf;
  684.   help_buf = 0;
  685. }
  686.  
  687. // Replace backslash escapes in a string with the real values.
  688.  
  689. static void
  690. do_string_escapes (char *s)
  691. {
  692.   char *p1 = s;
  693.   char *p2 = s;
  694.   while (*p2 != '\0')
  695.     {
  696.       if (*p2 == '\\' && *(p2+1) != '\0')
  697.     {
  698.       switch (*++p2)
  699.         {
  700.         case 'a':
  701.           *p1 = '\a';
  702.           break;
  703.  
  704.         case 'b': // backspace
  705.           *p1 = '\b';
  706.           break;
  707.  
  708.         case 'f': // formfeed
  709.           *p1 = '\f';
  710.           break;
  711.  
  712.         case 'n': // newline
  713.           *p1 = '\n';
  714.           break;
  715.  
  716.         case 'r': // carriage return
  717.           *p1 = '\r';
  718.           break;
  719.  
  720.         case 't': // horizontal tab
  721.           *p1 = '\t';
  722.           break;
  723.  
  724.         case 'v': // vertical tab
  725.           *p1 = '\v';
  726.           break;
  727.  
  728.         case '\\': // backslash
  729.           *p1 = '\\';
  730.           break;
  731.  
  732.         case '\'': // quote
  733.           *p1 = '\'';
  734.           break;
  735.  
  736.         case '"': // double quote
  737.           *p1 = '"';
  738.           break;
  739.  
  740.         default:
  741.           warning ("unrecognized escape sequence `\\%c' --\
  742.  converting to `%c'", *p2, *p2);
  743.           *p1 = *p2;
  744.           break;
  745.         }
  746.     }
  747.       else
  748.     {
  749.       *p1 = *p2;
  750.     }
  751.  
  752.       p1++;
  753.       p2++;
  754.     }
  755.  
  756.   *p1 = '\0';
  757. }
  758.  
  759. // If we read some newlines, we need figure out what column we're
  760. // really looking at.
  761.  
  762. static void
  763. fixup_column_count (char *s)
  764. {
  765.   char c;
  766.   while ((c = *s++) != '\0')
  767.     {
  768.       if (c == '\n')
  769.       current_input_column = 1;
  770.       else
  771.     current_input_column++;
  772.     }
  773. }
  774.  
  775. // Include these so that we don't have to link to libfl.a.
  776.  
  777. #ifdef yywrap
  778. #undef yywrap
  779. #endif
  780. static int
  781. yywrap (void)
  782. {
  783.   return 1;
  784. }
  785.  
  786. // These are not needed with flex-2.4.6, but may be needed with
  787. // earlier 2.4.x versions.
  788.  
  789. #if 0
  790. static void *
  791. yy_flex_alloc (int size)
  792. {
  793.   return (void *) malloc ((unsigned) size);
  794. }
  795.  
  796. static void *
  797. yy_flex_realloc (void *ptr, int size)
  798. {
  799.   return (void *) realloc (ptr, (unsigned) size);
  800. }
  801.  
  802. static void
  803. yy_flex_free (void *ptr)
  804. {
  805.   free (ptr);
  806. }
  807. #endif
  808.  
  809. // Tell us all what the current buffer is.
  810.  
  811. YY_BUFFER_STATE
  812. current_buffer (void)
  813. {
  814.   return YY_CURRENT_BUFFER;
  815. }
  816.  
  817. // Create a new buffer.
  818.  
  819. YY_BUFFER_STATE
  820. create_buffer (FILE *f)
  821. {
  822.   return yy_create_buffer (f, YY_BUF_SIZE);
  823. }
  824.  
  825. // Start reading a new buffer.
  826.  
  827. void
  828. switch_to_buffer (YY_BUFFER_STATE buf)
  829. {
  830.   yy_switch_to_buffer (buf);
  831. }
  832.  
  833. // Delete a buffer.
  834.  
  835. void
  836. delete_buffer (YY_BUFFER_STATE buf)
  837. {
  838.   yy_delete_buffer (buf);
  839. }
  840.  
  841. // Restore a buffer (for unwind-prot).
  842.  
  843. void
  844. restore_input_buffer (void *buf)
  845. {
  846.   switch_to_buffer ((YY_BUFFER_STATE) buf);
  847. }
  848.  
  849. // Delete a buffer (for unwind-prot).
  850.  
  851. void
  852. delete_input_buffer (void *buf)
  853. {
  854.   delete_buffer ((YY_BUFFER_STATE) buf);
  855. }
  856.  
  857. // Check to see if a character string matches any of the possible line
  858. // styles for plots.
  859.  
  860. static char *
  861. plot_style_token (char *s)
  862. {
  863.   static char *plot_styles[] = 
  864.     {
  865.       "boxes",
  866.       "boxerrorbars",
  867.       "dots",
  868.       "errorbars",
  869.       "impulses",
  870.       "lines",
  871.       "linespoints",
  872.       "points",
  873.       "steps",
  874.       0,
  875.     };
  876.  
  877.   char **tmp = plot_styles;
  878.   while (*tmp)
  879.     {
  880.       if (almost_match (*tmp, s))
  881.     return *tmp;
  882.  
  883.       tmp++;
  884.     }
  885.  
  886.   return 0;
  887. }
  888.  
  889. // Check to see if a character string matches any one of the plot
  890. // option keywords.  Don't match abbreviations for clear, since that's
  891. // not a gnuplot keyword (users will probably only expect to be able
  892. // to abbreviate actual gnuplot keywords).
  893.  
  894. static int
  895. is_plot_keyword (char *s)
  896. {
  897.   if (almost_match ("title", s))
  898.     {
  899.       return TITLE;
  900.     }
  901.   else if (almost_match ("using", s))
  902.     {
  903.       in_plot_using = 1;
  904.       return USING;
  905.     }
  906.   else if (almost_match ("with", s))
  907.     {
  908.       in_plot_style = 1;
  909.       return WITH;
  910.     }
  911.   else if (strcmp ("clear", s) == 0)
  912.     {
  913.       return CLEAR;
  914.     }
  915.   else
  916.     {
  917.       return 0;
  918.     }
  919. }
  920.  
  921. // Handle keywords.  Could probably be more efficient...
  922.  
  923. static int
  924. is_keyword (char *s)
  925. {
  926.   if (plotting && in_plot_style)
  927.     {
  928.       char *sty = plot_style_token (s);
  929.       if (sty)
  930.     {
  931.       in_plot_style = 0;
  932.       yylval.tok_val = new token (sty);
  933.       token_stack.push (yylval.tok_val);
  934.       return STYLE;
  935.     }
  936.     }
  937.  
  938.   int l = input_line_number;
  939.   int c = current_input_column;
  940.  
  941. // XXX FIXME XXX -- this has really become too large a list to search
  942. // like this...
  943.  
  944.   int end_found = 0;
  945.   if (strcmp ("break", s) == 0)
  946.     {
  947.       yylval.tok_val = new token (l, c);
  948.       token_stack.push (yylval.tok_val);
  949.       return BREAK;
  950.     }
  951.   else if (strcmp ("continue", s) == 0)
  952.     {
  953.       yylval.tok_val = new token (l, c);
  954.       token_stack.push (yylval.tok_val);
  955.       return CONTINUE;
  956.     }
  957.   else if (strcmp ("else", s) == 0)
  958.     {
  959.       yylval.tok_val = new token (l, c);
  960.       token_stack.push (yylval.tok_val);
  961.       return ELSE;
  962.     }
  963.   else if (strcmp ("elseif", s) == 0)
  964.     {
  965.       yylval.tok_val = new token (l, c);
  966.       token_stack.push (yylval.tok_val);
  967.       return ELSEIF;
  968.     }
  969.   else if (strcmp ("end", s) == 0)
  970.     {
  971.       end_found = 1;
  972.       yylval.tok_val = new token (token::simple_end, l, c);
  973.       token_stack.push (yylval.tok_val);
  974.     }
  975.   else if (strcmp ("endfor", s) == 0)
  976.     {
  977.       end_found = 1;
  978.       yylval.tok_val = new token (token::for_end, l, c);
  979.       token_stack.push (yylval.tok_val);
  980.     }
  981.   else if (strcmp ("endfunction", s) == 0)
  982.     {
  983.       end_found = 1;
  984.       yylval.tok_val = new token (token::function_end, l, c);
  985.       token_stack.push (yylval.tok_val);
  986.     }
  987.   else if (strcmp ("endif", s) == 0)
  988.     {
  989.       end_found = 1;
  990.       yylval.tok_val = new token (token::if_end, l, c);
  991.       token_stack.push (yylval.tok_val);
  992.     }
  993.   else if (strcmp ("endwhile", s) == 0)
  994.     {
  995.       end_found = 1;
  996.       yylval.tok_val = new token (token::while_end, l, c);
  997.       token_stack.push (yylval.tok_val);
  998.     }
  999.   else if (strcmp ("for", s) == 0)
  1000.     {
  1001.       promptflag--;
  1002.       looping++;
  1003.       yylval.tok_val = new token (l, c);
  1004.       token_stack.push (yylval.tok_val);
  1005.       return FOR;
  1006.     }
  1007.   else if (strcmp ("function", s) == 0)
  1008.     {
  1009.       if (defining_func)
  1010.     {
  1011.       error ("function keyword invalid within a function body");
  1012.  
  1013.       if ((reading_fcn_file || reading_script_file)
  1014.           && curr_fcn_file_name)
  1015.         error ("defining new function near line %d of file `%s.m'",
  1016.            input_line_number, curr_fcn_file_name);
  1017.       else
  1018.         error ("defining new function near line %d", input_line_number);
  1019.  
  1020.       return LEXICAL_ERROR;
  1021.     }
  1022.       else
  1023.     {
  1024.       tmp_local_sym_tab = new symbol_table ();
  1025.       curr_sym_tab = tmp_local_sym_tab;
  1026.       defining_func = 1;
  1027.       promptflag--;
  1028.       beginning_of_function = 1;
  1029.       if (! (reading_fcn_file || reading_script_file))
  1030.         input_line_number = 1;
  1031.       return FCN;
  1032.     }
  1033.     }
  1034.   else if (strcmp ("global", s) == 0)
  1035.     {
  1036.       yylval.tok_val = new token (l, c);
  1037.       token_stack.push (yylval.tok_val);
  1038.       return GLOBAL;
  1039.     }
  1040.   else if (strcmp ("gplot", s) == 0)
  1041.     {
  1042.       plotting = 1;
  1043.       yylval.tok_val = new token (token::two_dee, l, c);
  1044.       token_stack.push (yylval.tok_val);
  1045.       return PLOT;
  1046.     }
  1047.   else if (strcmp ("gsplot", s) == 0)
  1048.     {
  1049.       plotting = 1;
  1050.       yylval.tok_val = new token (token::three_dee, l, c);
  1051.       token_stack.push (yylval.tok_val);
  1052.       return PLOT;
  1053.     }
  1054.   else if (strcmp ("replot", s) == 0)
  1055.     {
  1056.       plotting = 1;
  1057.       yylval.tok_val = new token (token::replot, l, c);
  1058.       token_stack.push (yylval.tok_val);
  1059.       return PLOT;
  1060.     }
  1061.   else if (strcmp ("if", s) == 0)
  1062.     {
  1063.       iffing++;
  1064.       promptflag--;
  1065.       yylval.tok_val = new token (l, c);
  1066.       token_stack.push (yylval.tok_val);
  1067.       return IF;
  1068.     }
  1069.   else if (strcmp ("return", s) == 0)
  1070.     {
  1071.       yylval.tok_val = new token (l, c);
  1072.       token_stack.push (yylval.tok_val);
  1073.       return FUNC_RET;
  1074.     }
  1075.   else if (strcmp ("while", s) == 0)
  1076.     {
  1077.       promptflag--;
  1078.       looping++;
  1079.       yylval.tok_val = new token (l, c);
  1080.       token_stack.push (yylval.tok_val);
  1081.       return WHILE;
  1082.     }
  1083.   else if (strcmp ("unwind_protect", s) == 0)
  1084.     {
  1085.       promptflag--;
  1086.       yylval.tok_val = new token (l, c);
  1087.       token_stack.push (yylval.tok_val);
  1088.       return UNWIND;
  1089.     }
  1090.   else if (strcmp ("unwind_protect_cleanup", s) == 0)
  1091.     {
  1092.       yylval.tok_val = new token (l, c);
  1093.       token_stack.push (yylval.tok_val);
  1094.       return CLEANUP;
  1095.     }
  1096.   else if (strcmp ("end_unwind_protect", s) == 0)
  1097.     {
  1098.       end_found = 1;
  1099.       yylval.tok_val = new token (token::unwind_protect_end, l, c);
  1100.       token_stack.push (yylval.tok_val);
  1101.     }
  1102.   else if (strcmp ("all_va_args", s) == 0)
  1103.     {
  1104.       yylval.tok_val = new token (l, c);
  1105.       token_stack.push (yylval.tok_val);
  1106.       return ALL_VA_ARGS;
  1107.     }
  1108.  
  1109.   if (end_found)
  1110.     return END;
  1111.  
  1112.   return 0;
  1113. }
  1114.  
  1115. // Try to find an identifier.  All binding to global or builtin
  1116. // variables occurs when expressions are evaluated.
  1117.  
  1118. static symbol_record *
  1119. lookup_identifier (char *name)
  1120. {
  1121.   return curr_sym_tab->lookup (name, 1, 0);
  1122. }
  1123.  
  1124. // Grab the help text from an function file.  Always overwrites the
  1125. // current contents of help_buf.
  1126.  
  1127. static void
  1128. grab_help_text (void)
  1129. {
  1130.   delete [] help_buf;
  1131.   help_buf = 0;
  1132.  
  1133.   ostrstream buf;
  1134.  
  1135.   int in_comment = 1;
  1136.   int c = 0;
  1137.  
  1138.   while ((c = yyinput ()) != EOF)
  1139.     {
  1140.       if (in_comment)
  1141.     {
  1142.       buf << (char) c;
  1143.       if (c == '\n')
  1144.         in_comment = 0;
  1145.     }
  1146.       else
  1147.     {
  1148.       switch (c)
  1149.         {
  1150.         case '%':
  1151.         case '#':
  1152.           in_comment = 1;
  1153.           break;
  1154.  
  1155.         case ' ':
  1156.         case '\t':
  1157.           break;
  1158.  
  1159.         default:
  1160.           goto done;
  1161.         }
  1162.     }
  1163.     }
  1164.  
  1165.  done:
  1166.  
  1167.   if (c)
  1168.     yyunput (c, yytext);
  1169.  
  1170.   buf << ends;
  1171.  
  1172.   help_buf = buf.str ();
  1173.  
  1174.   if (! help_buf || ! *help_buf)
  1175.     {
  1176.       delete [] help_buf;
  1177.       help_buf = 0;
  1178.     }
  1179. }
  1180.  
  1181. // Return 1 if the given character matches any character in the given
  1182. // string.
  1183.  
  1184. static int
  1185. match_any (char c, char *s)
  1186. {
  1187.   char tmp;
  1188.   while ((tmp = *s++) != '\0')
  1189.     {
  1190.       if (c == tmp)
  1191.     return 1;
  1192.     }
  1193.   return 0;
  1194. }
  1195.  
  1196. // Given information about the spacing surrounding an operator,
  1197. // return 1 if it looks like it should be treated as a binary
  1198. // operator.  For example,
  1199. //
  1200. //   [ 1 + 2 ]  or  [ 1+ 2]  or  [ 1+2 ]  ==> binary
  1201.  
  1202. static int
  1203. looks_like_bin_op (int spc_prev, int spc_next)
  1204. {
  1205.   return ((spc_prev && spc_next) || ! spc_prev);
  1206. }
  1207.  
  1208. // Duh.
  1209.  
  1210. static int
  1211. next_char_is_space (void)
  1212. {
  1213.   int c = yyinput ();
  1214.   yyunput (c, yytext);
  1215.   return (c == ' ' || c == '\t');
  1216. }
  1217.  
  1218. // Try to determine if the next token should be treated as a postfix
  1219. // unary operator.  This is ugly, but it seems to do the right thing.
  1220.  
  1221. static int
  1222. next_token_is_postfix_unary_op (int spc_prev, char *yytext)
  1223. {
  1224.   int un_op = 0;
  1225.  
  1226.   int c0 = yyinput ();
  1227.   int c1 = yyinput ();
  1228.  
  1229.   yyunput (c1, yytext);
  1230.   yyunput (c0, yytext);
  1231.  
  1232.   int transpose = (c0 == '.' && c1 == '\'');
  1233.   int hermitian = (c0 == '\'');
  1234.  
  1235.   un_op = (transpose || (hermitian && ! spc_prev));
  1236.  
  1237.   return un_op;
  1238. }
  1239.  
  1240. // Try to determine if the next token should be treated as a binary
  1241. // operator.  This is even uglier, but it also seems to do the right
  1242. // thing.
  1243.  
  1244. static int
  1245. next_token_is_bin_op (int spc_prev, char *yytext)
  1246. {
  1247.   int bin_op = 0;
  1248.   int spc_next = 0;
  1249.  
  1250.   int c0 = yyinput ();
  1251.   int c1 = yyinput ();
  1252.  
  1253.   switch (c0)
  1254.     {
  1255.     case '+':
  1256.     case '-':
  1257.     case '/':
  1258.     case ':':
  1259.     case '\\':
  1260.     case '^':
  1261.       spc_next = (c1 == ' ' || c1 == '\t');
  1262.       break;
  1263.  
  1264.     case '&':
  1265.       if (c1 == '&')
  1266.     spc_next = next_char_is_space ();
  1267.       else
  1268.     spc_next = (c1 == ' ' || c1 == '\t');
  1269.       break;
  1270.  
  1271.     case '*':
  1272.       if (c1 == '*')
  1273.     spc_next = next_char_is_space ();
  1274.       else
  1275.     spc_next = (c1 == ' ' || c1 == '\t');
  1276.       break;
  1277.     
  1278.     case '|':
  1279.       if (c1 == '|')
  1280.     spc_next = next_char_is_space ();
  1281.       else
  1282.     spc_next = (c1 == ' ' || c1 == '\t');
  1283.       break;
  1284.  
  1285.     case '<':
  1286.       if (c1 == '=' || c1 == '>')
  1287.     spc_next = next_char_is_space ();
  1288.       else
  1289.     spc_next = (c1 == ' ' || c1 == '\t');
  1290.       break;
  1291.  
  1292.     case '>':
  1293.       if (c1 == '=')
  1294.     spc_next = next_char_is_space ();
  1295.       else
  1296.     spc_next = (c1 == ' ' || c1 == '\t');
  1297.       break;
  1298.  
  1299.     case '~':
  1300.     case '!':
  1301.     case '=':
  1302.       if (c1 == '=')
  1303.     spc_next = next_char_is_space ();
  1304.       else
  1305.     goto done;
  1306.       break;
  1307.  
  1308.     case '.':
  1309.       if (c1 == '*')
  1310.     {
  1311.       int c2 = yyinput ();
  1312.       if (c2 == '*')
  1313.         spc_next = next_char_is_space ();
  1314.       else
  1315.         spc_next = (c2 == ' ' || c2 == '\t');
  1316.       yyunput (c2, yytext);
  1317.     }
  1318.       else if (c1 == '/' || c1 == '\\' || c1 == '^')
  1319.     spc_next = next_char_is_space ();
  1320.       else
  1321.     goto done;
  1322.       break;
  1323.  
  1324.     default:
  1325.       goto done;
  1326.     }
  1327.  
  1328.   bin_op = looks_like_bin_op (spc_prev, spc_next);
  1329.  
  1330.  done:
  1331.   yyunput (c1, yytext);
  1332.   yyunput (c0, yytext);
  1333.  
  1334.   return bin_op;
  1335. }
  1336.  
  1337. // Used to delete trailing white space from tokens.
  1338.  
  1339. static char *
  1340. strip_trailing_whitespace (char *s)
  1341. {
  1342.   char *retval = strsave (s);
  1343.  
  1344.   char *t = strchr (retval, ' ');
  1345.   if (t)
  1346.     *t = '\0';
  1347.  
  1348.   t = strchr (retval, '\t');
  1349.   if (t)
  1350.     *t = '\0';
  1351.  
  1352.   return retval;
  1353. }
  1354.  
  1355. // Discard whitespace, including comments and continuations.
  1356. //
  1357. // Return value is logical OR of the following values:
  1358. //
  1359. //  ATE_SPACE_OR_TAB : space or tab in input
  1360. //  ATE_NEWLINE      : bare new line in input
  1361.  
  1362. static int
  1363. eat_whitespace (void)
  1364. {
  1365.   int retval = 0;
  1366.   int in_comment = 0;
  1367.   int c;
  1368.   while ((c = yyinput ()) != EOF)
  1369.     {
  1370.       current_input_column++;
  1371.  
  1372.       switch (c)
  1373.     {
  1374.     case ' ':
  1375.     case '\t':
  1376.       retval |= ATE_SPACE_OR_TAB;
  1377.       break;
  1378.  
  1379.     case '\n':
  1380.       retval |= ATE_NEWLINE;
  1381.       in_comment = 0;
  1382.       current_input_column = 0;
  1383.       break;
  1384.  
  1385.     case '#':
  1386.     case '%':
  1387.       in_comment = 1;
  1388.       break;
  1389.  
  1390.     case '.':
  1391.       if (in_comment)
  1392.         break;
  1393.       else
  1394.         {
  1395.           if (have_ellipsis_continuation ())
  1396.         break;
  1397.           else
  1398.         goto done;
  1399.         }
  1400.  
  1401.     case '\\':
  1402.       if (in_comment)
  1403.         break;
  1404.       else
  1405.         {
  1406.           if (have_continuation ())
  1407.         break;
  1408.           else
  1409.         goto done;
  1410.         }
  1411.  
  1412.     default:
  1413.       if (in_comment)
  1414.         break;
  1415.       else
  1416.         goto done;
  1417.     }
  1418.     }
  1419.  
  1420.  done:
  1421.   yyunput (c, yytext);
  1422.   current_input_column--;
  1423.   return retval;
  1424. }
  1425.  
  1426. static void
  1427. handle_number (char *yytext)
  1428. {
  1429.   double value;
  1430.   int nread = sscanf (yytext, "%lf", &value);
  1431.  
  1432. // If yytext doesn't contain a valid number, we are in deep doo doo.
  1433.  
  1434.   assert (nread == 1);
  1435.  
  1436.   quote_is_transpose = 1;
  1437.   cant_be_identifier = 1;
  1438.   convert_spaces_to_comma = 1;
  1439.  
  1440.   if (plotting && ! in_plot_range)
  1441.     past_plot_range = 1;
  1442.  
  1443.   yylval.tok_val = new token (value, yytext, input_line_number,
  1444.                   current_input_column);
  1445.  
  1446.   token_stack.push (yylval.tok_val);
  1447.  
  1448.   current_input_column += yyleng;
  1449.  
  1450.   do_comma_insert_check ();
  1451. }
  1452.  
  1453. // We have seen a backslash and need to find out if it should be
  1454. // treated as a continuation character.  If so, this eats it, up to
  1455. // and including the new line character.
  1456. //
  1457. // Match whitespace only, followed by a comment character or newline.
  1458. // Once a comment character is found, discard all input until newline.
  1459. // If non-whitespace characters are found before comment
  1460. // characters, return 0.  Otherwise, return 1.
  1461.  
  1462. static int
  1463. have_continuation (int trailing_comments_ok)
  1464. {
  1465.   ostrstream buf;
  1466.  
  1467.   int in_comment = 0;
  1468.   char c;
  1469.   while ((c = yyinput ()) != EOF)
  1470.     {
  1471.       buf << (char) c;
  1472.  
  1473.       switch (c)
  1474.     {
  1475.     case ' ':
  1476.     case '\t':
  1477.       break;
  1478.  
  1479.     case '%':
  1480.     case '#':
  1481.       if (trailing_comments_ok)
  1482.         in_comment = 1;
  1483.       else
  1484.         goto cleanup;
  1485.       break;
  1486.  
  1487.     case '\n':
  1488.       current_input_column = 0;
  1489.       promptflag--;
  1490.       return 1;
  1491.  
  1492.     default:
  1493.       if (! in_comment)
  1494.         goto cleanup;
  1495.       break;
  1496.     }
  1497.     }
  1498.  
  1499.   yyunput (c, yytext);
  1500.   return 0;
  1501.  
  1502.  cleanup:
  1503.   buf << ends;
  1504.   char *s = buf.str ();
  1505.   if (s)
  1506.     {
  1507.       int len = strlen (s);
  1508.       while (len--)
  1509.     yyunput (s[len], yytext);
  1510.     }
  1511.   delete [] s;
  1512.   return 0;
  1513. }
  1514.  
  1515. // We have seen a `.' and need to see if it is the start of a
  1516. // continuation.  If so, this eats it, up to and including the new
  1517. // line character.
  1518.  
  1519. static int
  1520. have_ellipsis_continuation (int trailing_comments_ok)
  1521. {
  1522.   char c1 = yyinput ();
  1523.   if (c1 == '.')
  1524.     {
  1525.       char c2 = yyinput ();
  1526.       if (c2 == '.' && have_continuation (trailing_comments_ok))
  1527.     return 1;
  1528.       else
  1529.     {
  1530.       yyunput (c2, yytext);
  1531.       yyunput (c1, yytext);
  1532.     }
  1533.     }
  1534.   else
  1535.     yyunput (c1, yytext);
  1536.  
  1537.   return 0;
  1538. }
  1539.  
  1540. // See if we have a continuation line.  If so, eat it and the leading
  1541. // whitespace on the next line.
  1542. //
  1543. // Return value is the same as described for eat_whitespace().
  1544.  
  1545. static int
  1546. eat_continuation (void)
  1547. {
  1548.   int retval = 0;
  1549.   int c = yyinput ();
  1550.   if ((c == '.' && have_ellipsis_continuation ())
  1551.       || (c == '\\' && have_continuation ()))
  1552.     retval = eat_whitespace ();
  1553.   else
  1554.     yyunput (c, yytext);
  1555.  
  1556.   return retval;
  1557. }
  1558.  
  1559. static int
  1560. handle_string (char delim, int text_style)
  1561. {
  1562.   ostrstream buf;
  1563.  
  1564.   int c;
  1565.   int escape_pending = 0;
  1566.  
  1567.   while ((c = yyinput ()) != EOF)
  1568.     {
  1569.       current_input_column++;
  1570.  
  1571.       if (c == '\\')
  1572.     {
  1573.       if (escape_pending)
  1574.         {
  1575.           buf << (char) c;
  1576.           escape_pending = 0;
  1577.         }
  1578.       else
  1579.         {
  1580.           if (have_continuation (0))
  1581.         escape_pending = 0;
  1582.           else
  1583.         {
  1584.           buf << (char) c;
  1585.           escape_pending = 1;
  1586.         }
  1587.         }
  1588.       continue;
  1589.     }
  1590.       else if (c == '.')
  1591.     {
  1592.       if (! have_ellipsis_continuation (0))
  1593.         buf << (char) c;
  1594.     }
  1595.       else if (c == '\n')
  1596.     {
  1597.       error ("unterminated string constant");
  1598.       break;
  1599.     }
  1600.       else if (c == delim)
  1601.     {
  1602.       if (escape_pending)
  1603.         buf << (char) c;
  1604.       else
  1605.         {
  1606.           c = yyinput ();
  1607.           if (c == delim)
  1608.         buf << (char) c;
  1609.           else
  1610.         {
  1611.           yyunput (c, yytext);
  1612.           buf << ends;
  1613.           char *tok = buf.str ();
  1614.           do_string_escapes (tok);
  1615.  
  1616.           if (text_style && doing_set)
  1617.             {
  1618.               if (tok)
  1619.             {
  1620.               int len = strlen (tok) + 3;
  1621.               char *tmp = tok;
  1622.               tok = new char [len];
  1623.               tok[0] = delim;
  1624.               strcpy (tok+1, tmp);
  1625.               tok[len-2] = delim;
  1626.               tok[len-1] = '\0';
  1627.               delete [] tmp;
  1628.             }
  1629.             }
  1630.           else
  1631.             {
  1632.               quote_is_transpose = 1;
  1633.               cant_be_identifier = 1;
  1634.               convert_spaces_to_comma = 1;
  1635.             }
  1636.  
  1637.           yylval.tok_val = new token (tok);
  1638.           delete [] tok;
  1639.           token_stack.push (yylval.tok_val);
  1640.           return TEXT;
  1641.         }
  1642.         }
  1643.     }
  1644.       else
  1645.     {
  1646.       buf << (char) c;
  1647.     }
  1648.  
  1649.       escape_pending = 0;
  1650.     }
  1651.  
  1652.   return LEXICAL_ERROR;
  1653. }
  1654.  
  1655. static int
  1656. handle_close_brace (int spc_gobbled)
  1657. {
  1658.   if (! nesting_level.empty ())
  1659.     {
  1660.       nesting_level.pop ();
  1661.       braceflag--;
  1662.     }
  1663.  
  1664.   if (braceflag == 0)
  1665.     BEGIN 0;
  1666.  
  1667.   int c1 = yyinput ();
  1668.   if (c1 == '=')
  1669.     {
  1670.       quote_is_transpose = 0;
  1671.       cant_be_identifier = 0;
  1672.       convert_spaces_to_comma = 1;
  1673.  
  1674.       int c2 = yyinput ();
  1675.       unput (c2);
  1676.       unput (c1);
  1677.  
  1678.       if (c2 != '=' && maybe_screwed_again)
  1679.     return SCREW_TWO;
  1680.       else
  1681.     return ']';
  1682.     }
  1683.   else
  1684.     {
  1685.       unput (c1);
  1686.  
  1687.       if (braceflag && user_pref.whitespace_in_literal_matrix != 2)
  1688.     {
  1689.       int bin_op = next_token_is_bin_op (spc_gobbled, yytext);
  1690.       int postfix_un_op = next_token_is_postfix_unary_op
  1691.         (spc_gobbled, yytext);
  1692.  
  1693.       int other_op = match_any (c1, ",;\n]");
  1694.  
  1695.       if (! (postfix_un_op || bin_op || other_op
  1696.          || nesting_level.empty ())
  1697.           && nesting_level.top () == BRACE
  1698.           && convert_spaces_to_comma)
  1699.         {
  1700.           unput (',');
  1701.           return ']';
  1702.         }
  1703.     }
  1704.     }
  1705.  
  1706.   quote_is_transpose = 1;
  1707.   cant_be_identifier = 0;
  1708.   convert_spaces_to_comma = 1;
  1709.   return ']';
  1710. }
  1711.  
  1712. static void
  1713. maybe_unput_comma (int spc_gobbled)
  1714. {
  1715.   if (user_pref.whitespace_in_literal_matrix != 2
  1716.       && ! nesting_level.empty ()
  1717.       && nesting_level.top () == BRACE) 
  1718.     {
  1719.       int bin_op = next_token_is_bin_op (spc_gobbled, yytext);
  1720.  
  1721.       int postfix_un_op = next_token_is_postfix_unary_op (spc_gobbled,
  1722.                               yytext);
  1723.  
  1724.       int c1 = yyinput ();
  1725.       int c2 = yyinput ();
  1726.       unput (c2);
  1727.       unput (c1);
  1728.       int sep_op = match_any (c1, ",;\n]");
  1729.       int dot_op = (c1 == '.'
  1730.             && (isalpha (c2) || isspace (c2) || c2 == '_'));
  1731.       int index_op = (c1 == '('
  1732.               && (user_pref.whitespace_in_literal_matrix == 0
  1733.               || ! spc_gobbled));
  1734.  
  1735.       if (! (postfix_un_op || bin_op || sep_op || dot_op || index_op))
  1736.     unput (',');
  1737.     }
  1738. }
  1739.  
  1740. // Figure out exactly what kind of token to return when we have seen
  1741. // an identifier.  Handles keywords.
  1742.  
  1743. static int
  1744. handle_identifier (char *tok, int spc_gobbled)
  1745. {
  1746. // It is almost always an error for an identifier to be followed
  1747. // directly by another identifier.  Special cases are handled below.
  1748.  
  1749.   cant_be_identifier = 1;
  1750.  
  1751. // If we are expecting a structure element, we just want to return
  1752. // TEXT_ID, which is a string that is also a valid identifier.  But
  1753. // first, we have to decide whether to insert a comma.
  1754.  
  1755.   if (looking_at_indirect_ref)
  1756.     {
  1757.       maybe_unput_comma (spc_gobbled);
  1758.       TOK_PUSH_AND_RETURN (tok, TEXT_ID);
  1759.     }
  1760.  
  1761. // If we have a regular keyword, or a plot STYLE, return it.  Keywords
  1762. // can be followed by identifiers (TOK_RETURN handles that).
  1763.  
  1764.   int kw_token = is_keyword (tok);
  1765.   if (kw_token)
  1766.     {
  1767.       if (kw_token == STYLE)
  1768.     {
  1769.       current_input_column += yyleng;
  1770.       quote_is_transpose = 0;
  1771.       convert_spaces_to_comma = 1;
  1772.       return kw_token;
  1773.     }
  1774.       else
  1775.     TOK_RETURN (kw_token);
  1776.     }
  1777.  
  1778. // See if we have a plot keyword (title, using, with, or clear).
  1779.  
  1780.   if (plotting)
  1781.     {
  1782. // Yes, we really do need both of these plot_range variables.  One
  1783. // is used to mark when we are past all possiblity of a plot range,
  1784. // the other is used to mark when we are actually between the square
  1785. // brackets that surround the range.
  1786.  
  1787.       if (! in_plot_range)
  1788.     past_plot_range = 1;
  1789.  
  1790.       int plot_option_kw = is_plot_keyword (tok);
  1791.  
  1792.       if (cant_be_identifier && plot_option_kw)
  1793.     TOK_RETURN (plot_option_kw);
  1794.     }
  1795.  
  1796. // If we are looking at a text style function, set up to gobble its
  1797. // arguments.  These are also reserved words, but only because it
  1798. // would be very difficult to do anything intelligent with them if
  1799. // they were not reserved.
  1800.  
  1801.   if (is_text_function_name (tok))
  1802.     {
  1803.       BEGIN TEXT_FCN;
  1804.  
  1805.       if (strcmp (tok, "help") == 0)
  1806.     BEGIN HELP_FCN;
  1807.       else if (strcmp (tok, "set") == 0)
  1808.     doing_set = 1;
  1809.     }
  1810.  
  1811.   int c = yyinput ();
  1812.   yyunput (c, yytext);
  1813.   int next_tok_is_eq = (c == '=');
  1814.  
  1815. // Make sure we put the return values of a function in the symbol
  1816. // table that is local to the function.
  1817.  
  1818.   if (next_tok_is_eq && defining_func && maybe_screwed)
  1819.     curr_sym_tab = tmp_local_sym_tab;
  1820.  
  1821. // Find the token in the symbol table.
  1822.  
  1823.   yylval.tok_val = new token (lookup_identifier (tok),
  1824.                   input_line_number,
  1825.                   current_input_column);
  1826.  
  1827.   token_stack.push (yylval.tok_val);
  1828.  
  1829. // After seeing an identifer, it is ok to convert spaces to a comma
  1830. // (if needed).
  1831.  
  1832.   convert_spaces_to_comma = 1;
  1833.  
  1834. // If we are defining a function and we have not seen the parameter
  1835. // list yet and the next token is `=', return a token that represents
  1836. // the only return value for the function.  For example,
  1837. //
  1838. //   function SCREW = f (args);
  1839. //
  1840. // The variable maybe_screwed is reset in parse.y.
  1841.  
  1842.   if (next_tok_is_eq)
  1843.     {
  1844.       current_input_column += yyleng;
  1845.       if (defining_func && maybe_screwed)
  1846.     return SCREW;
  1847.       else
  1848.     return NAME;
  1849.     }
  1850.  
  1851. // At this point, we are only dealing with identifiers that are not
  1852. // followed by `=' (if the next token is `=', there is no need to
  1853. // check to see if we should insert a comma (invalid syntax), or allow
  1854. // a following `'' to be treated as a transpose (the next token is
  1855. // `=', so it can't be `''.
  1856.  
  1857.   quote_is_transpose = 1;
  1858.   do_comma_insert_check ();
  1859.  
  1860.   maybe_unput_comma (spc_gobbled);
  1861.  
  1862.   current_input_column += yyleng;
  1863.   return NAME;
  1864. }
  1865.  
  1866. // Print a warning if a function file that defines a function has
  1867. // anything other than comments and whitespace following the END token
  1868. // that matches the FUNCTION statement.
  1869.  
  1870. void
  1871. check_for_garbage_after_fcn_def (void)
  1872. {
  1873. // By making a newline be the next character to be read, we will force
  1874. // the parser to return after reading the function.  Calling yyunput
  1875. // with EOF seems not to work...
  1876.  
  1877.   int in_comment = 0;
  1878.   int lineno = input_line_number;
  1879.   int c;
  1880.   while ((c = yyinput ()) != EOF)
  1881.     {
  1882.       switch (c)
  1883.     {
  1884.     case ' ':
  1885.     case '\t':
  1886.     case ';':
  1887.     case ',':
  1888.       break;
  1889.  
  1890.     case '\n':
  1891.       if (in_comment)
  1892.         in_comment = 0;
  1893.       break;
  1894.  
  1895.     case '%':
  1896.     case '#':
  1897.       in_comment = 1;
  1898.       break;
  1899.  
  1900.     default:
  1901.       if (in_comment)
  1902.         break;
  1903.       else
  1904.         {
  1905.           warning ("ignoring trailing garbage after end of function\n\
  1906.          near line %d of file `%s.m'", lineno, curr_fcn_file_name);
  1907.           
  1908.           yyunput ('\n', yytext);
  1909.           return;
  1910.         }
  1911.     }
  1912.     }
  1913.   yyunput ('\n', yytext);
  1914. }
  1915.  
  1916. /*
  1917.  
  1918. Maybe someday...
  1919.  
  1920. "+="        return ADD_EQ;
  1921. "-="        return SUB_EQ;
  1922. "*="        return MUL_EQ;
  1923. "/="        return DIV_EQ;
  1924. "\\="        return LEFTDIV_EQ;
  1925. ".+="        return ADD_EQ;
  1926. ".-="        return SUB_EQ;
  1927. ".*="        return EMUL_EQ;
  1928. "./="        return EDIV_EQ;
  1929. ".\\="        return ELEFTDIV_EQ;
  1930.  
  1931. */
  1932.