Lex / flex程序用于计算ID,语句,关键字,运算符等

时间:2016-10-08 02:11:08

标签: c compiler-construction tokenize flex-lexer

%{
#undef yywrap
#define yywrap() 1
#include<stdio.h>
  int statements = 0;
  int ids = 0;
  int assign = 0;
  int rel = 0;
  int keywords = 0;
  int integers = 0; 
%}
DIGIT [0-9]
LETTER [A-Za-z]
TYPE int|char|bool|float|void|for|do|while|if|else|return|void
%option yylineno
%option noyywrap

%%
\n {statements++;}
{TYPE} {/*printf("%s\n",yytext);*/keywords++;}
(<|>|<=|>=|==) {rel++;}
'#'/[a-zA-Z0-9]*    {;}
[a-zA-Z]+[a-zA-Z0-9]* {printf("%s\n",yytext);ids++;}
= {assign++;}
[0-9]+ {integers++;}
.      {;}

%%
void main(int argc, char **argv)
{
  FILE *fh;
  if (argc == 2 && (fh = fopen(argv[1], "r"))) {
    yyin = fh;
  }
  yylex();
  printf("statements = %d ids = %d assign = %d rel = %d keywords = %d integers = %d \n",statements,ids,assign,rel,keywords,integers);
}

//输入file.c

#include<stdio.h>
void main(){
    float a123;
    char a;
    char b123;
    char c;
    int ab[5];
    int bc[2];
    int ca[7];
    int ds[4];
    for( a = 0; a < 5 ;a++)
     printf("%d ", a);
    return 0;
}

输出:

include
stdio
h
main
a123
a
b123
c
ab
bc
ca
ds
a
a
a
printf
d
a
statements = 14 ids = 18 assign = 1 rel = 3 keywords = 11 integers = 7

我正在打印标识符。 #include<stdio.h>被视为标识符。我该如何避免这种情况?

我尝试了'#'/[a-zA-Z0-9]* {;}规则:动作对,但它仍被视为标识符。该文件如何被标记化?

%d中的printf字符串也被计为标识符。我已明确写过标识符应该只以字母开头,那么为什么%d被推断为标识符?

3 个答案:

答案 0 :(得分:2)

  1.   

    我尝试了'#'/[a-zA-Z0-9]* {;}规则:动作对,但[include]仍被视为标识符。该文件如何被标记化?

    一次识别一个代币。每个令牌都从前一个令牌结束的地方开始。

    '#'/[a-zA-Z0-9]*匹配&#39; &#39; ,前提是[a-zA-Z0-9]*。您可能意味着"#"/[a-zA-Z0-9]*(带双引号)与匹配,再次提供后跟字母或数字。请注意,只匹配; /之后的模式是&#34;尾随上下文&#34;,这基本上是一个先行断言。在这种情况下,前瞻是没有意义的,因为[a-zA-Z0-9]*可以匹配空字符串,因此任何都将匹配。无论如何,在作为令牌匹配后,扫描将继续下一个字符。所以下一个标记是include

    由于拼写错误,该模式不匹配。 (源代码中没有撇号。)所以实际匹配的是你的&#34;后备&#34; rule:规则为.的规则。 (我们将此称为后备规则,因为它匹配任何内容。实际上,它应该是.|\n,因为.匹配除换行符之外的任何内容,但只要您有一些匹配换行符的规则,它就是& #39;可以使用.。如果您没有提供备用规则,则会通过flex自动插入一个ECHO动作。)

    因此,将被忽略(就像您按照预期编写规则一样)并再次使用令牌include进行扫描。< / p>

    如果您想忽略整个预处理器指令,可以执行类似

    的操作

    ^ [[:blank:]]#。* {; }

  2.   

    (来自评论)我得到stdioh作为关键字,这与我给出的定义有什么关系?中间的.发生了什么?

    在回退规则忽略&lt; 之后,stdio匹配。由于[a-zA-Z]+[a-zA-Z0-9]*不匹配字母和数字以外的任何内容,因此不会被视为令牌的一部分。然后,被回退规则匹配并忽略,然后匹配h

  3.   

    %d中的printf字符串也被计为标识符。

    不是真的。回退规则明确忽略(与&#34; 一样),然后d作为标识符进行游行。如果要忽略字符串文字中的单词,则必须识别并忽略字符串文字。

答案 1 :(得分:0)

#include指令是一个预处理程序指令,因此由预处理程序进行预处理。预处理器包含头文件并删除#include指令因此在预处理后将程序作为输入提供给编译器时,它没有任何预处理器指令,如#include。  所以你不需要编写代码来检测#include,因为编译器都没有看到它,也没有设计为#include指令的标记。

参考文献:Is #include a token of type keyword?

答案 2 :(得分:0)

在规则部分添加以下行对我有用:

#.* ;

这里的规则是#.*,动作是;。 #.* 将捕获以 # 和 ; 开头的行什么都不做,所以基本上这将忽略以 # 开头的行。