我应该为不同类型的整数创建多少个令牌?

时间:2017-10-20 01:32:18

标签: c flex-lexer

我正在尝试为具有这些类型的整数的语言实现词法分析器:

INT32
Int64的
UINT32
UINT64
SINT32
sint64
fixed32 fixed64 sfixed32
sfixed64

我的问题是:我应该为每一个创建不同的令牌吗?我应该为每个人创建一个REGEX吗?到目前为止,这是我的代码:

%{
enum Tokens{
L_INT = 1,
L_DOUBLE,
L_FLOAT,
L_BOOL,
L_STRING,
L_BYTE,
RW_REQUIRED,
RW_OPTIONAL,
RW_REPEATED,
RW_MESSAGE,
RW_IMPORT,
RW_PUBLIC,
RW_ENUM,
RW_SERVICE,
RW_CHANNEL,
RW_CONTROLLER,
A_RPAR,
A_LPAR,
C_RPAR,
C_LPAR
};
%}
%option nodefault noyywrap
%%
"(" { return A_RPAR; }
")" { return A_LPAR; }
"{" { return C_RPAR; }
"}" { return C_LPAR; }
"required" { return RW_REQUIRED; }
"optional" { return RW_OPTIONAL; }
"repeated" { return RW_REPEATED; }
"message" { return RW_MESSAGE; }
"import" { return RW_IMPORT; }
"public" { return RW_PUBLIC; }
"enum" { return RW_ENUM; }
"service" { return RW_SERVICE; }
"channel" { return RW_CHANNEL; }
"controller" { return RW_CONTROLLER; }
"true" { return L_BOOL; }
"false" { return L_BOOL; }
[\r\n ] {}
([0-1]) { printf("[%s]", yytext); return L_BYTE; }
(0|[1-9][0-9]*) { printf("[%s]", yytext); return L_INT; }
(0|[1-9][0-9]*)?\.[0-9]+ { printf("[%s]", yytext); return L_DOUBLE; }
(0|[1-9][0-9]*)?\.[0-9]+[fF] { printf("[%s]", yytext); return L_FLOAT; }
([a-zA-Z]*[0-9]*) { printf("[%s]", yytext); return L_STRING; }
. { printf("caractere invalido [%s] \n", yytext); return 0;}
%%
extern FILE *yyin;
int main (int argc, char* argv[]) {
int token = -1;
if (argc <2){
printf("Exemplo: %s [arquivo_entradas]",argv[0]);
return 1;
}
yyin = fopen(argv[1], "r");
while(token = yylex()) {
printf("Token = %d\n", token);
}
return 0;
}

2 个答案:

答案 0 :(得分:1)

是。在词法分析器和解析器中保持它们不同。如果关于创建正则表达式的问题意味着执行您已经为其他关键字做的事情,那么答案也是肯定的。

当关键字集非常大时,例如在Cobol-85和后续版本中,如果有足够的400,您可以考虑为所有标识符设置一个规则,并在获得标识符时查找关键字的Hashtable,而不是每个关键字的规则:时空权衡,否则flex表变得巨大。但我怀疑你有这个问题。

编辑如果您只是在谈论整数文字,那么您没有任何选择。词法分析器没有将它们分类为不同类型所需的信息。你应该从你的词法规则中返回INTEGER。除非数字有前缀或后缀(如C的L),否则可以确定它。但是我认为那种糟糕的语言设计,无论是谁,也许是BCPL或B伙伴,或DR。从来没有任何真正的必要性。

答案 1 :(得分:1)

除非你要坚持使用某种类型的后缀以类似C的方式编写整数 - 就像你似乎对浮点数一样 - ,词法分析器绝对没有办法真正实现例如,判断给定的正整数是否是有符号类型的实例。所以我的想法是它不应该尝试。

当然,您可以根据整数的大小以及是否有符号进行部分分析,但最后整数可以(可能)用作适合的任何类型的值因此,12可以是您列出的10种类型中的任何一种。 (它可能也可以作为一个浮点数。)因此,部分分析确实不会告诉你语言的语法所需的任何内容,这使得它在词汇上浪费了很多精力分析器。

这留下了你如何表示整数的语义值的问题,因为所有这10种类型的可能值的并集将不适合64位。 (范围从-2 63 到2 64 -1。)如果您的语言允许使用算术表达式,则可以通过考虑-来避免此问题永远是一个运算符,永远不是文字整数的一部分。然后整数的可能合法值适合无符号64位整数(C中为uint64_t)的范围,这是一种看似合理的语义值类型。

由于您的语义值也包含浮点数,因此您需要使用某种区别的联合;您可以使用该机制来记录整数是否使用符号写入(这与签名值不同),但这对我来说似乎很笨拙。无论如何,它可能与语法无关,除非你的语法有一些只允许整数常量(没有表达式)但是常量可以为负的极端情况。我也避免使用这样的句法规则。

我注意到你的代码试图将0和1专门归类为&#34; byte&#34; (虽然看起来像#34; bit&#34;会更准确),但我建议不要这样做。您仍然需要一个语义值来区分0和1,并且这些常量中的任何一个也可以在非布尔(语法)上下文中使用,因此您并不真正购买通过生成不同的词汇标记来完成任何事情。

当您最终进行语义分析时,您需要根据派生的数据类型对语义值进行范围检查。如果你愿意,你可以让词法分析器计算每个整数的范围类别,将它存储在语义类型结构的另一个成员中。但这可能不值得这么麻烦。