根据具有lex / yacc的上下文,不同地分析相同的模式

时间:2016-05-04 20:33:16

标签: yacc lex ambiguous

我的问题是我有一个相同的字符模式,我希望根据它们的上下文进行不同的解析。在文件的一部分中,我需要解析“#。#”形式的版本号。显然,这与浮点数相同。词法分析器总是选择返回浮点数。我想我可以切换规则序列来给出版本#precedence(?),但是当我需要稍后解析浮点数时,这对我没有任何帮助。

我想我可以忘记要求解析器单独返回每个版本并将浮点数分成几部分,但我希望能为我完成它。

版本#的上下文实际上还有更多内容。它的完整形式是“ABC#。#XYZ”,其中“ABC”和“XYZ”永远不会改变。我已经尝试了一些方法来利用版本#的上下文,但还没有使它工作。

有没有办法为词法分析器提供一些上下文来解析版本的组件?我是否坚持接收浮点数并自行解析?

1 个答案:

答案 0 :(得分:0)

你有几种可能性。

最简单的方法是在解析器而不是扫描器中进行字符串到数字的转换。这需要将数字副本作为字符串,但开销不应该太高:短字符串的malloc在几乎所有平台上都得到了很好的优化。而且好处是代码非常简单和强大:

分析器

%union {
      char*  string;
      double number;
      // other types, including version
}

%token <string> DOTTED
%token <number> NUMBER
%type <number> number
%type <version> version
%%
number : NUMBER
       | DOTTED { $$ = atod($1); free($1); }
version: DOTTED { $$ = make_version($1); free($1); }

扫描仪

[[:digit:]]+\.[[:digit:]]+     { yylval.string = strdup(yytext); return DOTTED; }
[[:digit:]]+\.?|\.[[:digit:]]+ { yylval.number = atod(yytext); }

以上假设版本号始终为单点,如OP中所示。在版本号可以有多个点或非数字字符的应用程序中,最终会有三种可能的令牌类型:明确的数字,明确的版本字符串和单点数字字符串,它们也可以是。除了将VERSION令牌类型和明确版本字符串的模式添加到扫描程序之外,唯一的变化是将| VERSION添加到解析器中的version作品中。

另一种可能性是,如果您可以轻松地在扫描仪中弄清楚是否需要数字或版本,则使用开始条件。您也可以从解析器更改条件,但它更复杂,您需要了解解析算法,以确保正确地传达状态更改。

最后,您可以在扫描程序中执行两个转换,并在减少解析器中的令牌时选择正确的转换。如果版本是一个小而简单的数据结构,那么这可能是最佳的。