【问题标题】:How to get entire input string in Lex and Yacc?如何在 Lex 和 Yacc 中获取整个输入字符串?
【发布时间】:2009-08-05 23:25:45
【问题描述】:

好的,这就是交易。

用我的语言我有一些命令,比如说

XYZ 3 5
GGB 8 9
HDH 8783 33

在我的 Lex 文件中

XYZ { return XYZ; }
GGB { return GGB; }
HDH { return HDH; }
[0-9]+ { yylval.ival = atoi(yytext); return NUMBER; }
\n  { return EOL; }

在我的 yacc 文件中

start : commands
    ;

commands : command
         | command EOL commands
    ;

    command : xyz
            | ggb
            | hdh
    ;

    xyz : XYZ NUMBER NUMBER { /* Do something with the numbers */ }
       ;

    etc. etc. etc. etc.

我的问题是,我怎样才能得到整个文本

XYZ 3 5
GGB 8 9
HDH 8783 33

在返回 NUMBER 的同时进入命令?

另外,当我的 Lex 返回一个 STRING [0-9a-zA-Z]+,并且我想验证它的长度时,我应该这样做

rule: STRING STRING { if (strlen($1) < 5 ) /* Do some shit else error */ }

或者实际上在我的 Lex 中有一个根据长度返回不同标记的标记?

【问题讨论】:

    标签: c parsing yacc lex


    【解决方案1】:

    如果我正确理解了您的第一个问题,您可以进行语义操作,例如

    { $$ = makeXYZ($2, $3); }
    

    这将允许您根据需要构建命令的值。

    对于第二个问题,词汇分析和语法分析之间以及语法分析和语义分析之间的界限并不难确定。移动它们是在易于描述、错误消息的清晰度和出现错误时的稳健性等因素之间进行权衡。考虑到字符串长度的验证,出错的可能性是相当高的,如果通过返回不同长度的不同终端来处理,错误信息可能会不清楚。所以如果有可能——这取决于语法——我会在语义分析阶段处理它,在那里可以轻松地定制消息。

    【讨论】:

      【解决方案2】:

      如果您安排您的词法分析器 (yylex()) 将整个字符串存储在某个变量中,那么您的代码可以访问它。与解析器的通信将通过正常机制进行,但没有什么说你不能还有另一个变量潜伏在周围(可能是一个文件静态变量 - 但要注意多线程),它在被剖析之前存储整个输入行。

      【讨论】:

      • 我想也许我不是那么清楚,但我有类似 HEADER BLOCK1 STUFF BLOCK1END BLOCK2 STUFF BLOCK2END 其中 BLOCK1 和 BLOCK2 匹配相同的规则。我需要的是匹配 BLOCK1 时 BLOCK1 的整个文本。最简单但令人讨厌的方法是让所有规则都具有字符串值,即从我的示例中 %type xyz 然后对于每个规则,我必须输入 xyz: XYZ NUMBER NUMBER { $$ = " XYZ" + $2 + $3; } 加班会很烦人。
      【解决方案3】:

      当您使用 yylval.ival 时,您的 YACC 源中已经有 unionival 字段,如下所示:

      %union {
          int ival;
      }
      

      现在您指定令牌类型,如下所示:

      %token <ival> NUMBER
      

      所以现在您可以在规则中以$1 的形式访问ival 字段,例如

      xyz : XYZ NUMBER NUMBER { printf("XYZ %d %d", $2, $3); }
      

      对于你的第二个问题,我会这样定义联合:

      %union {
          char*   strval;
          int     ival;
      }
      

      并在您的 LEX 源中指定令牌类型

      %token <strval> STRING;
      %token <ival> NUMBER;
      

      所以现在你可以做类似的事情

      foo : STRING NUMBER { printf("%s (len %d) %d", $1, strlen($1), $2); }
      

      【讨论】:

      • 这给出了匹配字符串的段错误。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-12-08
      • 2014-04-29
      • 2015-09-24
      相关资源
      最近更新 更多