Compiler construction Lexer输出

Compiler construction Lexer输出,compiler-construction,lexer,Compiler Construction,Lexer,我目前正在编写一个编译器,我正处于Lexer阶段 我知道lexer标记了输入流 但是,考虑下面的流: int foo = 0; lexer的输出应该是:关键字字母字母字母等于数字分号?然后解析器将字母字母字母缩减为标识符 将“字母”作为中间步骤并没有真正的好处,相反,“foo”应该是一个标识符。否则,您也可以将int理解为“字母”,这没有多大意义。对于一般情况,没有简单的答案 通常,如果语言语法允许的话,让lexer识别“更高级别”的元素(比如标识符,甚至类型或变量)更容易。语法越动态,标记的

我目前正在编写一个编译器,我正处于Lexer阶段

我知道lexer标记了输入流

但是,考虑下面的流:

int foo = 0;

lexer的输出应该是:
关键字
字母字母
字母
等于
数字
分号
?然后解析器将
字母
字母
字母
缩减为标识符

将“字母”作为中间步骤并没有真正的好处,相反,“foo”应该是一个标识符。否则,您也可以将
int
理解为“字母”,这没有多大意义。

对于一般情况,没有简单的答案

通常,如果语言语法允许的话,让lexer识别“更高级别”的元素(比如标识符,甚至类型或变量)更容易。语法越动态,标记的解释就越依赖于内部状态,如果解析器这样做,那么将解释提交给解析器可能会更容易。否则,lexer和解析器之间的通信可能会变得过于复杂。(例如,考虑It是一个类型中的一个类型,另一个位置是一个有效的变量名,第三个例子中的一个语言关键字)


经验法则:让词法分析器完成所有的工作,使语法变得简单,而不会在词法分析器和解析器之间造成额外的复杂性

一般来说,你的词素分析器应该生成一个包含语言元素的结构流:操作符、标识符、关键字、注释等。这些结构应该用词素的类型来标记,并携带与它所代表的词素类型相关的内容

为了实现良好的错误报告,如果每个词素都包含有关起始行和列、结束行和列(一些词素跨越多行)以及原始源文件(有时解析器必须处理包含的文件以及主文件)的信息,那么这是很好的

对于包含可变内容(数字、标识符等)的语言元素,结构应该包含可变内容

对于编译或程序分析,lexer可以扔掉空白和注释。如果您打算解析/修改代码,则需要捕获注释

示例输出可能具有指导意义。 对于OP示例的变体:

/* My test file */

int foo
    = 0; // a declaration
。。。DMS的C前端产生以下词素(这是一个调试输出,在设计复杂的词素分析器时非常方便):

C:\DMS\Domains\C\GCC4\Tools\Lexer\Source>run../domainlexer C:\temp\test.C
Lexer流显示1.5.1
使用Unicode-UTF-8编码?ANSI+CRLF+1/^I
!! Lexer:ResetLexicalModeStack
!! 在Lexer:PushLexicalMode之后:
词法模式堆栈:
1 C
文件“C:/temp/test.C”,第1行:/*我的测试文件*/
文件“C:/temp/test.C”,第2行:
文件“C:/temp/test.C”,第3行:int foo
!! Lexer:GotoLexicalMode 2 CMain
!! Lexeme@Line 3 Col 1 ELine 3 ECol 4 Token 23:'int'[VOID]=0000
>邮政指令:
注释1类型2第4行第10列“//声明”
文件“C:/temp/test.C”,第5行:
文件“C:/temp/test.C”,第6行:
文件“C:/temp/test.C”,第7行:
!! Lexer:gotolexicalmode1c
!! Lexeme@Line 4 Col 26 ELine 7 ECol 1 Token 2:whitespace[VOID]=0000
!! Lexeme@Line 7 Col 1 ELine 7 ECol 1 Token 4:输入流的结束[VOID]=0000
!! Lexer:GotoLexicalMode 2 CMain
!! 第7行第1列第7行ECol 1标记0的词素:EndOfFile
处理了11个词素。
检测到0个词法错误。
C:\DMS\Domains\C\GCC4\Tools\Lexer\Source>
主要输出是标有的行,每个都表示lexer生成的lexeme结构的内容。每个词素包含:

  • 源文件位置信息(对于主文件,在本例中为“test.c”,未打印以使调试输出更具可读性)
  • “令牌编号”(lexeme类型)和人类可读的令牌名称(使调试更容易)
  • 令牌携带的值类型:[VOID]表示“无”,[STRING]表示令牌携带字符串值,[NATURAL]表示令牌携带整数值,等等
  • 预注释:标记前面的注释。这对于经典的lexer来说是不寻常的,但是如果一个人试图转换源代码,这是必要的。你不能丢失评论!注意,预提示附加到令牌;因为注释在语义上没有意义,人们可以争论它们应该放在哪里。这是我们的特殊选择
  • 后注释:在属于它的标记后面的注释
最后一个“token”EndOfFile在每个DMS lexer中都是隐式定义的


这个调试跟踪还记录了lexer在词法模式之间的转换(许多lexer生成器有多种模式,在这些模式中,它们对语言的各个部分进行了lex)。它显示了读到的源代码行。

我只是喜欢那些下层选民。肇事逃逸,没有说明为什么这不能准确回答OP的问题。
C:\DMS\Domains\C\GCC4\Tools\Lexer\Source>run ../domainlexer C:\temp\test.c
Lexer Stream Display 1.5.1
Using encoding Unicode-UTF-8?ANSI +CRLF +1 /^I
!! Lexer:ResetLexicalModeStack
!! after Lexer:PushLexicalMode:
Lexical Mode Stack:
1 C
File "C:/temp/test.c", line 1: /* My test file */
File "C:/temp/test.c", line 2:
File "C:/temp/test.c", line 3: int foo
!! Lexer:GotoLexicalMode 2 CMain
!! Lexeme @ Line 3 Col 1 ELine 3 ECol 4 Token 23: 'int' [VOID]=0000
  <<< PreComments:
Comment 1 Type 1 Line 1 Column 1 `/* My test file */'
!! Lexeme @ Line 3 Col 4 ELine 3 ECol 5 Token 2: whitespace [VOID]=0000
!! Lexeme @ Line 3 Col 5 ELine 3 ECol 8 Token 210: IDENTIFIER [STRING]=`foo'
File "C:/temp/test.c", line 4:     = 0; // a declaration
!! Lexer:GotoLexicalMode 1 C
!! Lexeme @ Line 3 Col 8 ELine 4 ECol 5 Token 2: whitespace [VOID]=0000
!! Lexer:GotoLexicalMode 2 CMain
!! Lexeme @ Line 4 Col 5 ELine 4 ECol 6 Token 113: '=' [VOID]=0000
!! Lexeme @ Line 4 Col 6 ELine 4 ECol 7 Token 2: whitespace [VOID]=0000
!! Lexeme @ Line 4 Col 7 ELine 4 ECol 8 Token 138: INT_LITERAL [NATURAL]=0
File "C:/temp/test.c", line 5:
!! Lexeme @ Line 4 Col 8 ELine 4 ECol 9 Token 98: ';' [VOID]=0000
  >>> PostComments:
Comment 1 Type 2 Line 4 Column 10 `// a declaration'
File "C:/temp/test.c", line 5:
File "C:/temp/test.c", line 6:
File "C:/temp/test.c", line 7:
!! Lexer:GotoLexicalMode 1 C
!! Lexeme @ Line 4 Col 26 ELine 7 ECol 1 Token 2: whitespace [VOID]=0000
!! Lexeme @ Line 7 Col 1 ELine 7 ECol 1 Token 4: end_of_input_stream [VOID]=0000
!! Lexer:GotoLexicalMode 2 CMain
!! Lexeme @ Line 7 Col 1 ELine 7 ECol 1 Token 0: EndOfFile
11 lexemes processed.
0 lexical errors detected.

C:\DMS\Domains\C\GCC4\Tools\Lexer\Source>