Lex/flex 计算 ID、语句、关键字、运算符等的程序
Lex/flex program to count ids, statements, keywords, operators etc
%{
#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]* {;}
rule:action 对,但它仍然被算作标识符。文件是如何被标记化的?
printf
中的 %d
字符串也被计为标识符。我已经明确写过标识符只能以字母开头,那么为什么 %d
被推断为标识符?
I have tried '#'/[a-zA-Z0-9]* {;}
rule:action pair but it [include
] is still being counted as identifier. How is the file being tokenized?
令牌一次识别一个。每个标记都从前一个标记结束的地方开始。
'#'/[a-zA-Z0-9]*
匹配 '#' 前提是其后跟 [a-zA-Z0-9]*
。您的意思可能是 "#"/[a-zA-Z0-9]*
(带双引号)匹配 #,前提是它后跟一个字母或数字。请注意,只有 # 被匹配; /
之后的模式是 "trailing context",这基本上是一个先行断言。在这种情况下,前瞻是没有意义的,因为 [a-zA-Z0-9]*
可以匹配空字符串,所以任何 # 都会被匹配。在任何情况下,在 # 作为标记匹配后,扫描将在下一个字符处继续。所以下一个标记将是 include
.
由于拼写错误,该模式不匹配。 (源代码中没有撇号。)所以实际匹配的是您的 "fallback" 规则:模式为 .
的规则。 (我们称其为回退规则,因为它匹配任何内容。实际上,它应该是 .|\n
,因为 .
匹配除换行符以外的任何内容,但只要您有一些匹配换行符的规则,它就是可接受使用 .
。如果您不提供后备规则,flex 将通过操作 ECHO
.)
自动插入一个
因此,# 被忽略(就像您按预期编写规则时一样)并且扫描再次继续使用令牌 include
.
如果你想忽略整个预处理器指令,你可以这样做
^[[:空白:]]#.* { ; }
(from a comment) I am getting stdio
and h
as keywords, how does that fit the definition that I have given? What happened to the .
in between?
<被回退规则忽略后,匹配stdio
。由于 [a-zA-Z]+[a-zA-Z0-9]*
不匹配字母和数字以外的任何内容,因此 . 不被视为令牌的一部分。然后.被回退规则匹配忽略,然后h
被匹配.
Also the %d
string in printf
is being counted as an identifier.
不是真的。 % 被回退规则明确忽略(" 也是如此),然后 d
作为标识符前进。如果您想忽略字符串文字中的单词,您将必须识别并忽略字符串文字。
#include 指令是预处理器指令,因此由预处理器进行预处理。预处理器包含头文件并删除#include 指令,因此在预处理之后,当程序作为输入提供给编译器时,它没有任何预处理器指令,如#include。
因此,您无需编写代码来检测 #include,因为编译器既不会看到它,也不会设计为标记化 #include 指令。
参考文献:Is #include a token of type keyword?
在规则部分添加以下行对我有用:
#.* ;
这里的规则是#.*,动作是;。 #.* 将捕获以 # 和 ; 开头的行什么都不做,所以基本上这会忽略以 #.
开头的行
%{
#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]* {;}
rule:action 对,但它仍然被算作标识符。文件是如何被标记化的?
printf
中的 %d
字符串也被计为标识符。我已经明确写过标识符只能以字母开头,那么为什么 %d
被推断为标识符?
I have tried
'#'/[a-zA-Z0-9]* {;}
rule:action pair but it [include
] is still being counted as identifier. How is the file being tokenized?令牌一次识别一个。每个标记都从前一个标记结束的地方开始。
'#'/[a-zA-Z0-9]*
匹配 '#' 前提是其后跟[a-zA-Z0-9]*
。您的意思可能是"#"/[a-zA-Z0-9]*
(带双引号)匹配 #,前提是它后跟一个字母或数字。请注意,只有 # 被匹配;/
之后的模式是 "trailing context",这基本上是一个先行断言。在这种情况下,前瞻是没有意义的,因为[a-zA-Z0-9]*
可以匹配空字符串,所以任何 # 都会被匹配。在任何情况下,在 # 作为标记匹配后,扫描将在下一个字符处继续。所以下一个标记将是include
.由于拼写错误,该模式不匹配。 (源代码中没有撇号。)所以实际匹配的是您的 "fallback" 规则:模式为
自动插入一个.
的规则。 (我们称其为回退规则,因为它匹配任何内容。实际上,它应该是.|\n
,因为.
匹配除换行符以外的任何内容,但只要您有一些匹配换行符的规则,它就是可接受使用.
。如果您不提供后备规则,flex 将通过操作ECHO
.)因此,# 被忽略(就像您按预期编写规则时一样)并且扫描再次继续使用令牌
include
.如果你想忽略整个预处理器指令,你可以这样做
^[[:空白:]]#.* { ; }
(from a comment) I am getting
stdio
andh
as keywords, how does that fit the definition that I have given? What happened to the.
in between?<被回退规则忽略后,匹配
stdio
。由于[a-zA-Z]+[a-zA-Z0-9]*
不匹配字母和数字以外的任何内容,因此 . 不被视为令牌的一部分。然后.被回退规则匹配忽略,然后h
被匹配.Also the
%d
string inprintf
is being counted as an identifier.不是真的。 % 被回退规则明确忽略(" 也是如此),然后
d
作为标识符前进。如果您想忽略字符串文字中的单词,您将必须识别并忽略字符串文字。
#include 指令是预处理器指令,因此由预处理器进行预处理。预处理器包含头文件并删除#include 指令,因此在预处理之后,当程序作为输入提供给编译器时,它没有任何预处理器指令,如#include。 因此,您无需编写代码来检测 #include,因为编译器既不会看到它,也不会设计为标记化 #include 指令。
参考文献:Is #include a token of type keyword?
在规则部分添加以下行对我有用:
#.* ;
这里的规则是#.*,动作是;。 #.* 将捕获以 # 和 ; 开头的行什么都不做,所以基本上这会忽略以 #.
开头的行