在我展示我做了什么之前,这里是我尝试过的任务(我是新来的,所以我不太确定我是否做得还好)。
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();
}正如你所看到的,我已经定义了我所需要的所有类型,我不知道如何实现下一个和后一个,一些指导是很好的,我也保存了行号,但是我想它们是其他的意思--我写的是什么,我也不明白他们写的定义部分。
我知道这个问题听起来很奇怪,但是我以前是在没有任何指导和解释的情况下完成这个任务的,所以我自己正在学习它,我并不完全理解(尽管我知道这个理论,谢谢!)
发布于 2017-03-31 09:36:31
我在我们公司的项目中做了一些类似的事情。
关于令牌的
我为他们做了列举..。
关于next_token()
我的目的是将所有与令牌相关的信息存储到以下对象中:
此外,我想对这些生成的对象使用智能指针,更不用说,它们应该是C++对象。
这就是我意识到的:
yylex()函数很容易。因此,您甚至可以重命名它并更改它的签名。%union)从lex (生成的代码)传递到yacc/bison (生成的代码)。C联合和C++对象--这不太好。(C联合中的一个对象可能工作,但多个对象肯定不起作用。)幸运的是,第二个问题实际上并不存在于我身上,因为我使用了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)这是您找到文档的柔性手册页。要找到如何重新定义yylex函数的解释,请在这个网站上搜索"YY_DECL“。
每当我的解析器需要一个新的令牌时,它就调用lex()。
备注:
yylex(),甚至使它成为解析器类的一个方法。(我这样做是为了简化lexer对私有解析器变量的访问。)yyscan_t yyscanner参数必须存在,因为我生成可重入的扫描器。你必须决定它是否应该在那里。(相反,您也可以提供其他参数。)RefToken是指向所产生的令牌的智能指针。(智能指针可以非常容易地在不同的“地方”生成和使用令牌,而不会造成内存泄漏的危险。)如果生成的lexer与野牛生成的解析器相结合,那么它可能就不那么容易了。在本例中,我将使用静态变量并组织队列将值从lexer传递到解析器。这是可行的,但是,当然,不像上面的方法那样优雅和节省。
关于back_token()
一旦您有了一个使用令牌的解析器,您可以随意使用它们。在我的例子中,其中一个要求是回溯跟踪的选项。因此,我不得不不时地将令牌推回输入。为此,我简单地将它们堆在解析器中。如果需要一个新的令牌,我首先检查这个堆栈是否为空。如果没有,则会弹出最上面的令牌,否则将调用lex()方法以获得真正的新令牌。在您的情况下,我想可以使用类似的解决方案来实现back_token()。
关于空白
实际上,我的lexer中有两种类型的规则(即规则操作):
return new Token(...);结束的操作break;结束的操作后者我用来消耗分离器(如空格等)。甚至注释(解析器甚至看不到它们)。这是因为lexer实际上只不过是包装在switch()循环中的一个for()。(我从柔性医生那里学到了这个“技巧”。在某个地方明确提到)。
还有.
除了YY_DECL之外,我还重新定义了YY_INPUT。我这样做是为了在C++ std::stream中使用lexer (而不是yyin)。
IMHO flex确实提供了一个非常全面的手册。但是,每当我有疑问时,我都会查看flex生成的C文件。对于有限自动机,有一些可怕的int数组,我通常会忽略它。其余的是围绕在它们周围的底层结构,您会发现您的C操作(写在lex规则中)在某个地方嵌入。检查周围的代码可能会使事情变得更清楚。
https://stackoverflow.com/questions/43088952
复制相似问题