【问题标题】:Lexical analysis using lex使用 lex 进行词法分析
【发布时间】:2017-08-22 16:07:43
【问题描述】:

在我将在这里展示我所做的之前是我尝试做的任务(我是新手,所以我不确定我是否做得很好)。

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();
}

如您所见,我已经定义了我所支持的所有类型,我不明白如何实现 next 和 back,一些指导应该很棒,我还保存了行号,但我猜他们的意思不是什么我写, 我也不明白他们写的定义部分。

我知道这个问题看起来很奇怪,但是我之前没有任何指导或解释就得到了这个作业,所以我是自己学习的,我并不完全理解(虽然我知道这个理论,谢谢!)。

【问题讨论】:

    标签: c flex-lexer lex lexical-analysis lexical


    【解决方案1】:

    我在我们公司的项目中做了非常相似的事情。

    关于令牌

    我为他们做枚举,然后……

    关于 next_token()

    我的意图是将整个令牌相关信息存储到一个对象中:

    • 实际令牌(枚举值)
    • 词位(一个 std::string)
    • 文件位置(由文件名指针、行和列组成)。

    另外,我想对这些生成的对象使用智能指针,更不用说,它们应该是 C++ 对象。

    这是我意识到的:

    1. 重新定义yylex() 函数很容易。因此,您甚至可以重命名它并更改其签名。

    2. 很难(如果不是不可能的话)将它与 yacc/bison 放在一起。主要问题是使用 C 联合(%union,如果我没记错的话)将数据从 lex(生成的代码)传递到 yacc/bison(生成的代码)。 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()。

    注意事项:

    1. 在我的例子中,我重命名了yylex(),甚至使它成为我的解析器类的一个方法。 (我这样做是为了简化词法分析器对私有解析器变量的访问。)

    2. 我提供了全范围运算符,因为生成的 lex 代码不考虑我在 C++ 代码中使用的任何命名空间。

    3. yyscan_t yyscanner 参数必须存在,因为我生成可重入扫描器。你必须决定它是否应该在那里。 (相反,您也可以提供其他参数。)

    4. 返回的RefToken 是指向生成令牌的智能指针。 (智能指针可以很容易地在不同的“地方”生成和使用令牌,而不会有内存泄漏的危险。)

    如果生成的词法分析器应该与野牛生成的解析器相结合,那可能就没有那么容易了。在这种情况下,我将使用静态变量并组织队列将值从词法分析器传递到解析器。这可行,但当然不如上述方法优雅和节省。

    关于 back_token()

    一旦你有了一个解析器,它可以使用令牌,你可以随心所欲地处理它们。就我而言,其中一个要求是回溯的选项。因此,有时我不得不将令牌推回输入。为此,我只是将它们堆叠在解析器中。如果需要新令牌,我首先检查此堆栈是否为空。如果没有弹出最上面的令牌,则调用lex() 方法来获取一个真正的新令牌。我想在您的情况下,可以使用类似的解决方案来实现 back_token()。

    关于空白

    在我的词法分析器中实际上有两种类型的规则(即规则操作):

    1. 以return new Token(...); 结尾的操作

    2. 以break; 结尾的操作

    我使用后者来消耗分隔符(即空白等)甚至 cmets(解析器甚至看不到它们)。这是有效的,因为词法分析器实际上只不过是包裹在for() 循环中的switch()。 (我从 flex 文档中学到了这个“技巧”。它在某处明确提到。)

    还有什么...

    除了YY_DECL,我还重新定义了YY_INPUT。我这样做是为了将词法分析器与 C++ std::stream(而不是 yyin)一起使用。

    恕我直言,flex 确实提供了非常全面的手册。但是,每当我有疑问时,我都会查看 flex 生成的 C 文件。对于有限自动机,我通常会忽略这些可怕的int 数组。其余的是围绕它们的基础结构,您会发现您的 C 操作(以 lex 规则编写)嵌入某处。检查周围的代码可能会使事情更清楚。

    【讨论】:

      猜你喜欢
      • 2011-06-15
      • 1970-01-01
      • 2012-05-14
      • 1970-01-01
      • 2011-02-25
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多