繁体   English   中英

如何用 Bison 和 C++ 解析两种数字?

[英]How do I parse two kinds of numbers with Bison and C++?

我正在编写一个 flownake 数字计算器,并且只是存根解析器。 该程序位于 C++ 中,通过查看生成的代码,我必须弄清楚 Bison 与 C++ 一起使用的一些细节。 (calc++ 示例使用了 Flex,但我没有使用 Flex。)我是 Bison 的新手。 到目前为止,这是解析器:

%require "3.2"
%language "c++"

%{
#include "flowsnake.h"
#include "parser.h"
int yylex(yy::parser::semantic_type *val);
%}

%token
  PLUS  "+"
  MINUS "-"
  TIMES "*"
  OVER  "/"
  LPAR  "("
  RPAR  ")"
  PREC "prec"
  INT
  FLOWNUM
;

%%

input:
  %empty
| line input
;

line:
  '\n'
| cmd '\n'
| exp '\n'
;

cmd:
  PREC INT
;

exp:
  FLOWNUM
| exp PLUS exp
;

%%

这里是存根 yylex 和错误函数:

int yylex(yy::parser::semantic_type *val)
{
  *val=0;
  return 0;
}

void yy::parser::error(const string &msg)
{
  cerr<<msg<<endl;
}

我必须解析两种数字(最终是三种,第三种是具有实部和虚部的复数):有理整数,使用数字 0-9 并且可以有符号但没有小数点,以及使用数字的流蛇数0-6 可以有小数点但没有符号。 如果我说261+34 ,那么261是一个等于 8 的流蛇数,我正在向它添加另一个流蛇数。 但是如果我说prec 261 ,那么 261 是十进制的,我将精度设置为 261 位。 28+34prec 26.1都无效,但26.1+34prec 28都有效。 如何编写词法分析器来对这些数字进行词法分析?

代码在https://github.com/phma/flowbound中。

根据您对目标语言的不太详细的描述,扫描仪似乎不需要知道它正在查看的数字类型即可识别令牌。 (标志可能会影响这一点,但见下文。)它可能无法明确识别错误,但这对于标记化无关紧要。 (这是基于281+34是错误的想法。如果存在您可能希望将其分解为单独标记的上下文 - 例如281+34 - 那么以下内容将不适用. 但这似乎不太可能。)

在这种情况下,最好的解决方案通常是词法扫描器简单地识别字符串并将其传递给解析器。 然后解析器可以进行任何必要的转换,或者如果字符串无法转换,则发出错误消息。

确实,如果扫描器知道预期需要哪种类型的数字标记,它确实可以识别错误,并且我建议的体系结构的最终结果是错误的标记被有效地扫描两次以查找错误(尽管第二次扫描实际上并不花费很多,因为它将来自转换失败)。 因此可以更快地检测到错误。 但是针对错误进行优化实际上从来都不是一种有效的优化策略(除非您正在编写 linter)。 常见的情况是正确的输入,并且在代码中引入复杂性以“更有效地”处理错误几乎总是一种错误的经济。

正如您在评论中所说,您还可以让扫描仪进行两种转换,指示哪些是有效的。 再一次,这似乎是虚假的经济。 实际上只需要一次转换,所以在两种可能的情况下,其中一种是浪费时间。 如果转换成本很高,则尤其如此。

在解析器中,转换将由单位生产表示,它很好地封装了过程:

cmd:
  "prec" integer

exp:
  flownum
| exp "+" exp

integer:
  INT     { $$ = convert_to_int($1); }

flownum:
  FLOWNUM { $$ = convert_to_flownum($1); }

上面遗漏的是错误报告。 在实践中, convert_to_intconvert_to_flownum可能有一些机制来返回错误条件,解析器会检查该返回。

正如上面所提到的,符号可能是一个问题,因为您希望整数可选地被签名。 一个简单的扫描器总是将一个标志扫描为一个单独的令牌,这主要是你想要的。 然而, integer的上述定义可以很容易地扩展为允许有符号整数:

integer:
  INT     { $$ = convert_to_int($1); }
| "+" INT { $$ = convert_to_int($2); }
| "-" INT { $$ = -convert_to_int($2); }

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM