Compiler construction 扫描仪(使用ANTLR词法分析关键字)

Compiler construction 扫描仪(使用ANTLR词法分析关键字),compiler-construction,antlr,antlr3,lexer,Compiler Construction,Antlr,Antlr3,Lexer,我一直在为我的程序编写一个扫描器,大多数在线教程都包括一个解析器和扫描器。似乎不可能在不同时编写解析器的情况下编写lexer。我只是试图生成标记,而不是解释它们。我想识别INT标记、float标记和一些标记,如“begin”和“end” 我对如何匹配关键字感到困惑。我尝试了以下方法,但未成功: KEYWORD : KEY1 | KEY2; KEY1 : {input.LT(1).getText().equals("BEGIN")}? LETTER+ ; KEY2 : {input.LT(1).

我一直在为我的程序编写一个扫描器,大多数在线教程都包括一个解析器和扫描器。似乎不可能在不同时编写解析器的情况下编写lexer。我只是试图生成标记,而不是解释它们。我想识别INT标记、float标记和一些标记,如“begin”和“end”

我对如何匹配关键字感到困惑。我尝试了以下方法,但未成功:

KEYWORD : KEY1 | KEY2;

KEY1 : {input.LT(1).getText().equals("BEGIN")}? LETTER+ ;
KEY2 : {input.LT(1).getText().equals("END")}? LETTER+ ;

FLOATLITERAL_INTLITERAL
  : DIGIT+ 
  ( 
    { input.LA(2) != '.' }? => '.' DIGIT* { $type = FLOATLITERAL; }
    | { $type = INTLITERAL; }
  )
  | '.'  DIGIT+ {$type = FLOATLITERAL}
;

fragment LETTER : ('a'..'z' | 'A'..'Z');
fragment DIGIT  : ('0'..'9');

IDENTIFIER 
 : LETTER 
   | LETTER DIGIT (LETTER|DIGIT)+ 
   | LETTER LETTER (LETTER|DIGIT)*
 ;

WS  //Whitespace
  : (' ' | '\t' | '\n' | '\r' | '\f')+  {$channel = HIDDEN;}
;  

如果您只需要一个lexer,请从以下内容开始编写语法:

lexer grammar FooLexer; // creates: FooLexer.java
LT(int):令牌
只能在解析器规则内使用(在上)。在lexer规则中,只能使用从中获取下一个
int
(字符)的
LA(int):int
。但是没有必要对所有的手册进行前瞻。就这样做吧:

lexer语法傻瓜;
开始
:“开始”
;
结束
:“结束”
;
浮动
:数字+'.'数字+
;
国际的
:位数+
;
标识符
:字母(字母|数字)*
;
WS
:(“”|’\t’|’\n’|’\r’|’\f’+{$channel=HIDDEN;}
; 
片段字母:('a'..'z'|'a'..'z');
片段数字:('0'..'9');
我看不出有必要创建一个名为
KEYWORD
的令牌来匹配所有关键字:您需要区分
BEGIN
END
令牌,对吗?但如果你真的想这样做,只需:

关键字
:“开始”
|“结束”
;
并删除
开始
结束
规则。只需确保在
标识符
之前定义了
关键字

编辑 使用以下类别测试lexer:

import org.antlr.runtime.*;
公共班机{
公共静态void main(字符串[]args)引发异常{
String src=“BEGIN-END 3.14159 42 FOO”;
愚人词条=新愚人词条(新AntlStringStream(src));
while(true){
Token Token=lexer.nextToken();
if(token.getType()==doublexer.EOF){
打破
}
System.out.println(token.getType()+”:“+token.getText());
}
}
}
如果生成lexer,请编译.java源文件并按如下方式运行主类:

java-cp antlr-3.3.jar org.antlr.Tool.g
javac-cp antlr-3.3.jar*.java
java-cp.:antlr-3.3.jar Main
以下输出将打印到控制台:

4::开始
11 ::  
5::结束
11 ::  
7 :: 3.14159
11 ::  
8 :: 42
11 ::  
10::富

[来自一个制作定制lexer工具的家伙,他仍在努力学习ANTLR]

枯燥的泛泛回答:

你说得对。许多书籍和课程混合了这两种工具。有时,“生成/检测令牌”和“解释令牌”可能会混合使用

有时,开发人员试图做一个扫描器,但仍然在脑海中混合了扫描和解析;-)

通常,在检测令牌时,您还必须执行一个操作(“解释”),就像将消息或找到的令牌打印到字符串一样简单。
示例:“{cout在您的示例中FLOAT和INT不能同时被识别,因为这是一个不明确的情况。我将得到以下警告:多个令牌规则可以匹配输入,例如“'0'…'9'0'…'9'”:FLOATLITERAL,结果是INTLITERAL,令牌我们为此禁用了INTLITERALinput@macneil,不,那不是真的。我猜你没有复制粘贴我的建议。我很快会添加一个小演示。正如你所看到的,令牌
3.14159
42
是不同的类型(分别是FLOAT和INT)。我正在使用类似于调试我的lexer的东西,作为一种生活质量的东西,您可以将println更改为
System.out.println(doubexer.tokenNames[token.getType()]+”:“+token.getText());
以获取令牌名称(至少在ANTLR4中)。