如何在Lex和Yacc中获取整个输入字符串?

时间:2009-08-05 23:25:46

标签: c parsing yacc lex

好的,这就是交易。

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

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实际上有一个令牌,根据长度返回不同的令牌?

3 个答案:

答案 0 :(得分:1)

如果我已正确理解您的第一个问题,您可以使用

等语义操作
{ $$ = makeXYZ($2, $3); }

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

对于你的第二个问题,词汇分析和语法分析之间以及语法分析和语义分析之间的界限并不难,也很难修复。移动它们是诸如描述的容易性,错误消息的清晰度和存在错误的鲁棒性等因素之间的权衡。考虑到字符串长度的验证,发生错误的可能性非常高,并且如果通过返回不同长度的不同长度来处理错误消息则可能不清楚。因此,如果可能 - 这取决于语法 - 我会在语义分析阶段处理它,在那里可以轻松地定制消息。

答案 1 :(得分:1)

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

答案 2 :(得分:0)

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

%union {
    int ival;
}

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

%token <ival> NUMBER

现在,您可以在规则中仅将ival字段作为$1用于访问xyz : XYZ NUMBER NUMBER { printf("XYZ %d %d", $2, $3); } 字段,例如

%union {
    char*   strval;
    int     ival;
}

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

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

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

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

所以现在你可以做像

这样的事情
{{1}}