Atitit.antlr实现词法分析

1.1.  antlrworks-1.4.3.jar   wizard1

1.2. 词法的类型 id,int,float ,comment,str,char,white space2

1.3. 3.1词法文件的规定3

1.4. 3.2字符编码定义4

1.5. 最后需要考虑的词法的定义5

1.5.2. 文法可视化5

1.6. 或者使用antlrworks生成需要的词法分析器6

1.6.2. 查看每一个标识符的代码7

1.6.3. 表达式验证7

1.7. 获取tokens9

1.8. Token的含义and type11

1.9. 3.3终结符定义方法11

1.10. 3.11大小写敏感12

1.11. contains grammar SimpleCalc; names must be identical。 13

1.12. org.antlr.runtime.tree.CommonTree cannot be cast to org.antlr.tool.GrammarAST13

1.13. no viable alternative at character '='14

1.14. Antlr 支持多种目标语言,可以把生成的分析器生成为 Java,C#,C,Python,JavaScript 等多种语言 14

1.15. 关键字and运算符的定义14

2. 参考15

1.1.  antlrworks-1.4.3.jar   wizard

1.2. 词法的类型 id,int,float ,comment,str,char,white space

Zai antlr里面儿的keyword是所有的大写

public static final int CHAR=4;

public static final int COMMENT=5;

public static final int ESC_SEQ=6;

public static final int EXPONENT=7;

public static final int FLOAT=8;

public static final int HEX_DIGIT=9;

public static final int ID=10;

public static final int INT=11;

public static final int OCTAL_ESC=12;

public static final int STRING=13;

public static final int UNICODE_ESC=14;

public static final int WS=15;

读者可能对"单词"感到有点疑惑,不明白到底什么才是词法分析中所说的"单词"。试图回答这个问题就必须了解几个基本概念。这里,引入几个程序设计语言相关的名词。

(1)标识符:用户自定义的变量名、函数名等字符串。

(2)关键字:具有特殊含义的标识符。

(3)运算符:例如+、-、*、/ 等。

(4)常量:例如3.24、92等。

(5)界符:具有特殊含义的符号,如分号、括号等。

作者::  ★(attilax)>>>   绰号:老哇的爪子 ( 全名::Attilax Akbar Al Rapanui 阿提拉克斯 阿克巴 阿尔 拉帕努伊 ) 汉字名:艾龙,  EMAIL:1466519819@qq.com

转载请注明来源: http://www.cnblogs.com/attilax/

这里面的ID INT FLOAT什么的并不是关键字,可以自定义的..

1.3. 3.1词法文件的规定

与第二章中的例子不同,在ANTLR中词法分析定义的规则名必须以大写字母开头如“LETTER”,“NewLine”。我们在第一章示例中的词法分析部分与语法分析部分合写到一个E.g文件中,ANTLR允许把词法分析部分和语法分析写分别写到两个文件中。

T.g文件存放语法定义:

grammar T;

Options {tokenVocab = T2;}

a : B*;

T2.g文件存放词法定义:

lexer grammar T2;

B : ‘b’;

将词法分析放到单独的文件中时文法的名称也要和文件的名称相同,在grammar关键字之前要加入lexer关键字。上例中的T.g文件生成语法分析类TParser,T2.g文件生成词法分析类T2Lexer。在T.g中要加入一个设置项tokenVocab来指定语法文件所需的词法单词是来自T2.g。这样就可以按照第一章示例中的方法编译运行分析器了。

1.4. 3.2字符编码定义

词法分析与源代码直接接触,因为源代码是由字符串组成的,所以我们需要定义字符的方法。ANTLR有两种方法定义字符,第一种方法是:ANTLR可以直接使用字符本身很简单直观的定义基本符号。

CHAR : ‘a’ | ‘b’ | ‘c’;

但这种定义只限于ASCII码的字符,下面的定义是不合法的。

CHAR : ‘代码’;

定义汉字这样除ASCII码以外的字符只能用第二种方法十六进制编码定义法。使用“\u”开头加四位十六进制数定义来定义一个字符。

CHAR : ‘\u0040’;

C#中使用String.Format("{0:x} {1:x}", Convert.ToInt32('代'), Convert.ToInt32('码'));可以获得汉字的编码。如上面的CHAR : ‘代码’;我们可以定义为:

CHAR : '\u4ee3' '\u7801';

编码有很多种GB2312的编码范围是A1A1 ~ FEFE,去掉未定义的区域之后可以理解为实际编码范围是A1A1 ~ F7FE。GBK的整体编码范围是为8140 ~ FEFE。 BIG5字符编码范围是A140 ~ F97E。

字符集

编码范围

GB2312

A1A1 ~ 7E7E

GBK

8140 ~ FEFE

BIG5

A140 ~ F97E

Unicode

000000 ~ 10FFFF

UTF-8

000000 ~ 10FFFF

其中汉字在GB2312中的编码范围为:‘\uB0A1' .. '\uF7FE',汉字在Unicode编码范围为:’\u4E00’ .. ‘\u9FA5’ | ‘\uF900’ .. ‘\uFA2D’。

1.5. 最后需要考虑的词法的定义

,在 Antlr 中语法定义和词法定义通过规则的第一个字符来区别, 规定语法定义符号的第一个字母小写,而词法定义符号的第一个字母大写。算术表达式中用到了 4 类记号 ( 在 Antlr 中被称为 Token),分别是标识符 ID,表示一个变量;常量 INT,表示一个常数;换行符 NEWLINE 和空格 WS,空格字符在语言处理时将被跳过,skip() 是词法分析器类的一个方法。如清单 3 所示:

1.5.1.1.1. 清单 3. 记号定义

ID : ('a'..'z' |'A'..'Z')+ ;

INT : '0'..'9' + ;

NEWLINE:'\r' ? '\n' ;

WS : (' ' |'\t' |'\n' |'\r' )+ {skip();} ;

1.5.1. 文法可视化

使用 Antlrworks 打开 Expr.g,Antlrworks 对每一个文法定义都做了可视化显示。整体的文法定义如图 3:

1.5.1.1.1. 图 3. 文法定义的可视化

其中语法规则和词法记号的定义都有对应的图形表示方式。比如语法规则 atom 的图示形式如图 4 所示:

1.5.1.1.2. 图 4. 语法规则 atom 的可视化

词法记号 ID 的图示形式如图 5 所示:

1.5.1.1.3. 图 5. 词法记号 ID 的可视化

使用 Antlrworks 还可以对语法分析树可视化,在 Antlrworks 的 GUI 窗口中,点击 Run ->Debug, 在 Input Text 窗口中输入 a+(2 + b),Start Rule 选择 prog, 然后完成调试,可以看到 a+(2 + b) 时的语法分析树,如图 6 所示:

1.6. 或者使用antlrworks生成需要的词法分析器

>>menubar >gene  。。  到个g文件../output目录下面

Or use antlr tool..

运行 Antlr  生成需要的词法分析器

完成文法定义之后,即可以运行 Antlr,为我们生成需要的词法分析器和语法分析器。在命令行运行以下下命令,如清单 4 所示:

1.6.0.1.1. 清单 4. 运行 Antlr

java  org.antlr.Tool  c:/

antlr_intro\src\expr\Expr.g

成功运行Antlr之后,将为我们生成 3 个文件,Expr.tokens、ExprLexer.java和ExprParser.java。其中Expr.tokens为文法中用到的各种符号做了数字化编号,我们可以不关注这个文件。ExprLexer是Antlr生成的词法分析器,ExprParser是Antlr 生成的语法分析器,如图 1 所示。

1.6.0.1.2. 图 1. Antlr 生成结果

1.6.1. 查看每一个标识符的代码

Antlrwork hto select left menu symb..then menubar >gene>show rule coe

Then show the code form lexelParser...java..

1.6.2. 表达式验证

基于 Antlr 生成的词法分析器和语法分析器后,可以基于它们来验证我们的输入的表达式是否合法。我们需要调用 Antlr 的 API 完成以下 Java 程序,如清单 5 所示:

1.6.2.1.1. 清单 5. 调用分析器

public static void run(String expr) throws Exception {

ANTLRStringStream in = new ANTLRStringStream(expr);

ExprLexer lexer = new ExprLexer(in);

CommonTokenStream tokens = new CommonTokenStream(lexer);

ExprParser parser = new ExprParser(tokens);

parser.prog();

}

对每一个输入的字符串,我们构造一个 ANTLRStringStream 流 in,用 in 构造词法分析器 lexer,词法分析的作用是产生记号,用词法分析器 lexer 构造一个记号流 tokens,然后再使用 tokens 构造语法分析器 parser,至此已经完成词法分析和语法分析的准备工作。最终调用语法分析器的规则 prog,完成对表达式的验证。详细的 Java 程序参考样例代码中的 Test.java。

当输入合法的的表达式时,分析器没有任何输出,表示语言被分析器接受;当输入的表达式违反文法规则时,比如“a + (b * 3”,分析器输出 line 0:-1 mismatched input '<EOF>' expecting ')';提示期待一个右括号却遇到了结束符号。如图 2 所示:

1.6.2.1.2. 图 2. 表达式验证结果

1.7. 获取tokens

public static void main(String[] args) {

run(" where=\"atiq422\"   ");

System.out.println("--f");

}

public static void run(String expr) {

ANTLRStringStream in = new ANTLRStringStream(expr);

grm1 lexer = new grm1(in);

CommonTokenStream tokens = new CommonTokenStream(lexer);

System.out.println(AtiJson.toJson(tokens));

// ExprParser parser = new ExprParser(tokens);

// parser.prog();

}

line 1:5 no viable alternative at character '='

{

"numberOfOnChannelTokens":3,

"tokenSource":{

"backtrackingLevel":0,

"charIndex":15,

"charPositionInLine":15,

"charStream":{

"charPositionInLine":15,

"line":1

},

"delegates":[],

"eOFToken":{

"channel":0,

"charPositionInLine":15,

"inputStream":{"$ref":"$.tokenSource.charStream"},

"line":1,

"startIndex":15,

"stopIndex":15,

"text":"<EOF>",

"tokenIndex":-1,

"type":-1

},

"grammarFileName":"C:\\Users\\Administrator\\Documents\\antrl1\\grm1.g",

"line":1,

"numberOfSyntaxErrors":0,

"ruleInvocationStack":[],

"ruleMemoizationCacheSize":0,

"text":""

},

"tokens":[

{

"channel":0,

"charPositionInLine":0,

"inputStream":{"$ref":"$.tokenSource.charStream"},

"line":1,

"startIndex":0,

"stopIndex":4,

"text":"where",

"tokenIndex":0,

"type":10

},

{

"channel":0,

"charPositionInLine":6,

"inputStream":{"$ref":"$.tokenSource.charStream"},

"line":1,

"startIndex":6,

"stopIndex":14,

"text":"\"atiq422\"",

"tokenIndex":1,

"type":13

},

{

"channel":0,

"charPositionInLine":15,

"inputStream":{"$ref":"$.tokenSource.charStream"},

"line":1,

"startIndex":15,

"stopIndex":15,

"text":"<EOF>",

"tokenIndex":2,

"type":-1

}

]

}

--f

--f

1.8. Token的含义and type

"type":13

public class grm1 extends Lexer {

public static final int EOF=-1;

public static final int CHAR=4;

public static final int COMMENT=5;

public static final int ESC_SEQ=6;

public static final int EXPONENT=7;

public static final int FLOAT=8;

public static final int HEX_DIGIT=9;

public static final int ID=10;

public static final int INT=11;

public static final int OCTAL_ESC=12;

public static final int STRING=13;

public static final int UNICODE_ESC=14;

public static final int WS=15;

1.9. 3.3终结符定义方法

LETTER : ‘A’ | ‘B’ | ‘C’ | ‘D’ | ‘E’ | ‘F’ | ‘G’ | ‘H’ | ‘I’ | ‘J’ | ‘K’ | ‘L’ | ‘M’ | ‘N’ | ‘O’ | ‘P’ | ‘Q’ | ‘R’ | ‘S’ | ‘T’ | ‘U’ | ‘V’ | ‘W’ | ‘X’ | ‘Y’ | ‘Z’ | ‘a’ | ‘b’ | ‘c’ | ‘d’ | ‘e’ | ‘f’ | ‘g’ | ‘h’ | ‘i’ | ‘j’ | ‘k’ | ‘l’ | ‘m’ | ‘n’ | ‘o’ | ‘p’ | ‘q’ | ‘r’ | ‘s’ | ‘t’ | ‘u’ | ‘v’ | ‘w’ | ‘x’ | ‘y’ | ‘z’;

“..”符号,从上面的LETTER示例可以看出,定义一个表示英文字母的符号写起来非常繁琐。为了让定义变得简单ANTLR加入“..”符号通过指定首尾的字符可以很方便的定义一定范围内的字符。

LETTER : ‘A’ .. ‘Z’ | ‘a’ .. ‘z’;

“~”符号,如果我们想表示除某些符号以外的符号时,可以使用“~”符号。“~”代表取反的意思。

: ~ ‘B’;

符号A匹配除字符“B”以外的所有字符。

: ~ (‘A’ | ‘B’); B : ~(‘A’ .. ‘B’); C ~‘\u00FF';

上面的例子中定义三个符号。符号A匹配除字符“A”和“B”以外的所有字符,符号B匹配除大写字符母以外的所有字符。符号C匹配除编码为“u00FF”的字符以外的所有字符。

“.”符号,ANTLR中可以用“.”表示单个任意字符,起通配符的作用。

A : .; B : .*; C : .* ‘C’; D : ~ .;//error

上面的例子中符号A匹配一个任意字符,符号B符号匹配0到多个任意字符,符号C匹配0到多个任意字符直到遇到字符“C”为止。D的定义是错误的,不能定义任意字符以外的字符。

3.4 skip()方法

有些字符是不属于源程序范畴内的,这些字符在分析过程中应该忽略掉。在ANTLR中可以在词法定义中加入skip();,(如果是C#为目标语言为Skip();)。在规则的定义的之后与表示定义结束的分号之前加入“{skip();}”。例如下面定义了一个跳过空白的词法定义。

WS : ( ' ' | '\t' | '\n' | '\r' ) + {skip();} ;

空白符号WS中有空格符、制表符、回车和换行符,当遇到这些字符时词法分析程序会调用skip()方法跳过这些字符。

: 'A' | 'B' {Skip();} | 'C' ;

上面的例子中符号B只在匹配字符“B”时跳过,从这个例子可以看出{Skip();}要写在忽略内容的后面,如果它处于某选择分支中那么它只对某分支起作用。下面我们定义一些实际中经常出现的词法定义。

INT : DIGIT+;

DIGIT : ‘0’ .. ‘9’;

INT 定义了整型数,整型数是由1个或多0到9的数字组成的。下面我们来定义浮点数,浮点数的整数部分至少要有一位数字,小数部分是可有可无的,如要有小数部分则至少要有1位小数位。

FLOAT : DIGIT+ (‘.’ DIGIT+)?;

下面是一个对于java语言中注释的定义。

COMMENT : '/*' . * '*/' {skip();} ;

LINE_COMMENT : '//' ~ ('\n' | '\r') * '\r'? '\n' {skip();} ;

/* */ 和 // 代表的注释部分被忽略掉,下面我们给出完全的示例并运行它。

1.10. 3.11大小写敏感

ANTLR中没有大小写是否敏感的设置项,所以只能象下面的词法规则这样定义大小写不敏感的单词。

SELECT : ('S'|'s')('E'|'e')('L'|'l')('E'|'e')('C'|'c')('T'|'t') ;

FROM : ('F'|'f')('R'|'r')('O'|'o')('M'|'m');

下面是运行分析器的代码。

TestSkipLexer lex = new TestSkipLexer(new ANTLRFileStream("f1.txt"));

CommonTokenStream tokenStream = new CommonTokenStream(lex);

TestSkipParser parser = new TestSkipParser(tokenStream);

TestSkipParser.a_return aReturn = parser.a();

1.11. contains grammar SimpleCalc; names must be identical。

注意: 语法文件名必须跟grammar指定的名称一致,否则ANTLR生成时会报错error(8):  file *** contains grammar SimpleCalc; names must be identical。

1.12. org.antlr.runtime.tree.CommonTree cannot be cast to org.antlr.tool.GrammarAST

G文件错误。格式。  要加个 prog才ok了。。

或者使用lexer关键字显示是个lexel文件...

----err code

grammar grm1;

ID  :('a'..'z'|'A'..'Z'|'_') ('a'..'z'|'A'..'Z'|'0'..'9'|'_')*

;

INT :'0'..'9'+

;

----ok code

lexer  grammar grm1;

ID  :('a'..'z'|'A'..'Z'|'_') ('a'..'z'|'A'..'Z'|'0'..'9'|'_')*

;

完整code

grammar grm1;

prog: stat

;

stat: expr

|NEWLINE

;

expr : multExpr (('+'|'-') multExpr)*

;

multExpr : atom (('*'|'/') atom)*

;

atom:  '(' expr ')'

| INT

| ID

;

ID  :('a'..'z'|'A'..'Z'|'_') ('a'..'z'|'A'..'Z'|'0'..'9'|'_')*

;

INT :'0'..'9'+

;

1.13.  no viable alternative at character '='

1.14. Antlr 支持多种目标语言,可以把生成的分析器生成为 Java,C#,C,Python,JavaScript 等多种语言

,默认目标语言为 Java,通过 options {language=?;} 来改变目标语言。我们的例子中目标语言为 Java。

3.11本章小结

本章讲述了ANTLR如何定义词法规则,包括:定义各种编码的字符,通配符“.”和“..”、“~”、“.”符号的用法,skip()方法的用法,$channel = HIDDEN输入频道,greedy=false的用法和注意事项,fragment词法规则的用法。这些内容为ANTLR中词法分析中基础,后面章节还会讲述词法规则中潜入代码和词法中的二义性的内容。学完本章后读者应该可以定义一种语言的基本词法规则,下一章我们讲述如何在词法规则的基础上定义语法规则的内容。

1.15. 关键字and运算符的定义

可以自定义Select ,from ......  ,最好还是,统统的opchar

Opchar : '='|’+’;

2. 参考

[转载] ANTLR——词法分析 - 6DAN_HUST - 博客园.html

使用 Antlr 开发领域语言.html

【整理】antlr语法中的fragment _ 在路上.html

Atitit.antlr实现词法分析的更多相关文章

  1. Atitit..状态机与词法分析  通用分词器 分词引擎的设计与实现 attilax总结

    Atitit..状态机与词法分析  通用分词器 分词引擎的设计与实现 attilax总结 1. 状态机 理论参考1 2. 词法分析理论1 3. 词法分析实例2 4. ---code fsm 状态机通用 ...

  2. Atitit 发帖机系列(8)  词法分析器v5 版本新特性说明)

    Atitit 发帖机系列(8)  词法分析器v5 版本新特性说明) v5  增加对sql单引号的内部支持.可以作为string 结构调整,使用递归法重构循环发..放弃循环发. V4 java dsl词 ...

  3. Antlr学习

    参加工作之后,接触DSL领域语言,了解了编译原理. 比如Hibernate.Hive等的HQL都是基于antlr编写的 所以,如果想自己实现一套DSL语言,我们可以基于antlr做词法分析与语法分析 ...

  4. 编译原理---antlr实践+编译过程理解+课程理解知识点

    0.其他说明 0.0编译器分为前.中.后端,课上主要学的是前端.前端又分为词法分析(lexical analysis).语法分析(syntax analysis).语义分析(semantic anal ...

  5. ANTLR4权威指南 - 第5章 设计语法

    在第I部分,我们熟悉了ANTLR,并在一个比较高的层次上了解了语法以及语言程序.现在,我们将要放慢速度来学习下实现更实用任务的一些细节上的技巧,例如建立内部数据结构,提取信息,生成输入对应的翻译内容等 ...

  6. Atitit.词法分析的原理 理论

    Atitit.词法分析的原理 理论 1. 分词 .词法分析lexical analysis 1 1.1. 分词主要流程 1 1.2. 分词的属性如下表token 1 1.3. 词法分析器主要包括:构造 ...

  7. atitit.词法分析的实现token attilax总结

    atitit.词法分析的实现token attilax总结 1. 词法分析(英语:lexical analysis)跟token 1 1.1. 扫描器 2 2. 单词流必须识别为保留字,标识符(变量) ...

  8. Atitit.注解解析(1)---------词法分析 attilax总结 java .net

    Atitit.注解解析(1)---------词法分析 attilax总结  java .net 1. 应用场景:::因为要使用ui化的注解 1 2. 流程如下::: 词法分析(生成token流) & ...

  9. atitit.词法分析原理 词法分析器 (Lexer)

    atitit.词法分析原理 词法分析器 (Lexer) 1. 词法分析(英语:lexical analysis)1 2. :实现词法分析程序的常用途径:自动生成,手工生成.[1] 2 2.1. 词法分 ...

随机推荐

  1. WPF中的动画——(五)关键帧动画

    与 From/To/By 动画类似,关键帧动画以也可以以动画形式显示目标属性值. 和From/To/By 动画不同的是, From/To/By 动画只能控制在两个状态之间变化,而关键帧动画则可以在多个 ...

  2. Inno Setup入门(二十)——Inno Setup类参考(6)

    http://379910987.blog.163.com/blog/static/3352379720112515819485/ 存储框 存储框也是典型的窗口可视化组件,同编辑框类似,可以输入.显示 ...

  3. pcap报文格式

    pcap报文格式 pcap报文整体格式 pcap 报文头格式 pcap报文格式,黄色部分为报文头 pcapng报文格式 PCAPNG: PCAP Next Generation Dump File F ...

  4. [转]双TOP二分法生成分页SQL类(支持MSSQL、ACCESS)

    本文转自:http://www.cnblogs.com/jitian/archive/2011/03/22/1991961.html 博客开张,先发以前的几个老物件儿,以前写下来的,现在发上来权当记录 ...

  5. LINUX之内网渗透提权

    在渗透测试过程中,经常遇到如下情形,内部网络主机通过路由器或者安全设备做了访问控制,无法通过互联网直接访问本地开放的服务,Windows方 面,国内通常选择Lcx.exe来进行端口转发,在应用方面大多 ...

  6. axios踩坑记录+拦截器使用+vue cli代理跨域proxy+webpack打包部署到服务器

    1.小小的提一下vue cli脚手架前端调后端数据接口时候的本地代理跨域问题,如我在本地localhost访问接口http://40.00.100.100:3002/是要跨域的,相当于浏览器设置了一道 ...

  7. yaha分词

    yaha分词:https://github.com/jannson/yaha

  8. [OpenCV]实验1.1:图像加载、显示

    实验要求:利用图像库的功能,实现从文件加载图像,并在窗口中进行显示的功能:利用常见的图像文件格式(.jpg;.png;.bmp; .gif)进行测试 实验原理:图片读取到程序中是以Mat结构存储的,在 ...

  9. NDK下IPC问题

    由于AllJoyn的join session timeout问题一直无法解决,我们怀疑AllJoyn有些内部变量没有清理干净,因此考虑将AllJoyn相关功能放到一个单独的进程中,一旦join ses ...

  10. bottle+cherrypy快速开发web服务

    我目前用得最顺手的python web框架是bottle,简单方便. bottle有一个开发用的http服务器,效率不高,单线程,阻塞. 所以,得找个别的服务器来部署. 根据bottle官方的文档,发 ...