c - 使用词法进行词法分析

标签 c flex-lexer lex lexical-analysis lexical

在我展示我在这里所做的之前,我要做的是我尝试过的作业(我是新来的,所以我不确定我是否做得对)。

1.  Implement lexical analyzer (using FLEX), as follows:
- Lexical analyzer supplies services next_token(), back_token()
- Lexical analyzer reads text from the input file and identifies tokens. This 
   happens when function   next_token() is called. 
- When a token is identified in the input text, it should be stored in a data 
   structure. For each token, the following attributes are saved:
   * token type
   * token lexeme
   * number of the line in the input text in which this token was found.
- Blanks, tabs, new lines – are not tokens, and should be ignored
- For each token, print (on a separate line) its type (e.g. rel_op , number , etc.) 
   and lexeme 
- Each operation, keyword, separation sign and each type of number should be 
   implemented as a token of a different kind
- Kinds of tokens are coded with integer numbers, for example:
        # define  ID_tok  1
        # define COMMA_tok  2

使用Flex,我已经写下了:
%{
#include<stdio.h>
int line=1;
# define  ID_tok  1
# define COMMA_tok  2
#define REL_OP_tok 3
#define NUMBER_tok 4
#define KEYWORDS_tok 5
%}
binary_ar_op "*"|"/"|"+"|"-"
rel_op "=="|"!="|">"|"<"|"<="|">="
id      [a-z][a-z0-9]*
number    ["+"|"-"]?[0-9]*("."[0-9]+)?
keywords "prabegin"|"parend"|"task"|"begin"|"end"|"integer"|"real"|"do"|"until"|"od"|"send"|"accept"

%%
\n   {line++;  printf("\n%d:",line);}

{binary_ar_op}+ {printf( "An binary_ar_op: %s (%d) at line(%d)\n", yytext,
                   atoi( yytext ),line);}

{rel_op}+ {printf( "An rel_op: %s (%d) at line(%d)\n", yytext,
                   atoi( yytext ),line);}

{id}+ {printf( "An id: %s (%d) at line(%d)\n", yytext,
                   atoi( yytext ),line);}


{number}+ {printf( "An number: %s (%d) at line(%d)\n", yytext,
                   atoi( yytext ),line);}
%%
int yywrap()
{
return 1;
}
main()
{
printf("Enter a string of data\n");
yylex();
}

正如你所看到的,我已经定义了我支持的所有类型,我不知道如何实现下一个和后一个,一些指南谁会是伟大的,我也保存了行号,但我想他们意味着其他,然后我写的,
我也不明白他们写的定义部分。
我知道这个问题看起来很奇怪,但我之前没有任何指导和解释就完成了这个作业,所以我是自己学习的,我并不完全理解(虽然我知道这个理论,谢谢!).

最佳答案

我在我们公司的项目中做了类似的事情。
关于令牌
我给他们做了个统计。。。
关于下一个令牌()
我的目的是将所有与令牌相关的信息存储到一个对象中:
acutal令牌(枚举值)
词素(std::string)
文件位置(由文件名指针、行和列组成)。
此外,我想使用这些生成的对象的智能指针,更不用说,它们应该是C++对象。
这就是我意识到的:
很容易重新定义yylex()函数因此,您甚至可以重命名它并更改其签名。
很难(如果不是不可能的话)把这个和yacc/bison结合起来主要的问题是,数据是使用C联合从lex(生成代码)传递到yacc/bison(生成代码)的(如果我没记错的话,%union)一个C组合和C++对象——不太好用。(C union中的一个对象可以工作,但多个对象肯定不行。)
对于我的运气来说,第二个问题实际上是不存在的,因为我使用Flex,但是写(同时生成)递归下降分析器(直接在C++中)。
那么,如何解决第一个问题呢这是我的代码:

/// redefines proto for generated yylex function.
#define YY_DECL \
  RF::YAMS::Sim::ActionScript::RefToken \
  RF::YAMS::Sim::ActionScript::Compiler::lex(yyscan_t yyscanner)

这里是flex man page您可以找到文档的地方要了解如何重新定义yylex函数的说明,请在本网站上搜索“YY_DECL”。
每当需要新的标记时,我的解析器都会调用lex()
笔记:
在我的例子中,我重命名了yylex(),甚至把它作为我的解析器类的一个方法(我这样做是为了简化lexer对私有解析器变量的访问。)
我提供了丰富的范围运算符,因为生成的LeX代码不考虑我在C++代码中使用的任何命名空间。
必须有yyscan_t yyscanner参数,因为我生成了重新进入的扫描仪你必须决定它是否应该在那里(相反,您也可以提供其他参数。)
返回的RefToken是指向生成的令牌的智能指针(智能指针使在不同的“位置”生成和使用令牌变得非常容易,而不存在内存泄漏的危险。)
如果生成的lexer与bison生成的解析器相结合,可能就不那么容易了在本例中,我将使用静态变量并组织队列以将值从lexer传递到解析器这是可行的,但是,当然,并不像上面的方法那样优雅和省钱。
关于back_token()
一旦有了一个使用标记的解析器,您可以随心所欲地使用它们在我的案例中,其中一个要求是可以选择回溯因此,我必须不时地将令牌推回输入为此,我只需将它们堆栈到解析器中如果需要一个新的令牌,我首先检查这个堆栈是否为空如果没有弹出最上面的标记,则调用lex()方法以获取真正新的标记我想在您的案例中,可以使用类似的解决方案来实现back_token()
关于空白
实际上,在我的lexer中有两种类型的规则(即规则操作):
return new Token(...);结尾的操作
break;结尾的操作
后者我用来使用分隔符(即空白等)甚至注释(解析器甚至看不到它们)这是因为lexer实际上只是一个封装在switch()循环中的for()(我从flex医生那里学到了这个“诀窍”在某处被明确提及。)
还有什么。。。
除了YY_DECL,我还重新定义了YY_INPUT我这样做是为了用C++CX>(而不是std::stream)使用Listor。
IMHO flex提供了非常全面的手册然而,每当我有疑问时,我都会查看flex生成的C文件对于有限自动机有这些可怕的yyin数组,我通常忽略它们剩下的是它们周围的基础结构,你会发现你的C操作(写在lex规则中)嵌入在某个地方检查周围的代码可以使事情更清楚。

关于c - 使用词法进行词法分析,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43088952/

相关文章:

c++ - 关于在 Linux 中使用管道和守护进程编写聊天室 C 程序有什么建议吗?

数组指针不能作为参数在其他函数中分配一些空间吗

bison - 为什么 yylval 为空?

parsing - lex & yacc 多重定义错误

Bison 不创建 tab.h 文件

android - 如何在android中获取.so文件的源代码

c - 检测到堆栈粉碎

error-handling - 如何在Bison中防止默认 “syntax error”

c++ - 应用程序参数的正则表达式

c - 在 yacc 中解析赋值语句时出现语法错误