antlr4

ANTLR(ANother Tool for Language Recognition)是一个ALL(*)的词法分析器, 功能和yacc类似. 应用很多, 可以解析大量语言和自定义语言, 官方也提供了不同语言的语法文件.



官方的文档非常齐全, 作者也专门出过一本电子书



看了一下官方文档, 对比goyacc, 这个库可以生成更加干净,更容易理解的代码. 并且包括



Hive, Netbeans等软件都用Antlr做解析工具. 网上关于Antlr的资料也不少



ANTLR本身用java实现, 但Runtime的库也支持Golang, Java, Python等等. Antlr提供了goyacc的一个很好的替代品.



对Golang程序员来说, 这篇文章是很好的入门, 从安装Antlr到实现支持算术符优先级的计算器都有介绍




https://zhuanlan.zhihu.com/p/47179842
https://blog.gopheracademy.com/advent-2017/parsing-with-antlr4-and-go/
https://www.antlr.org/
https://www.antlr.org/papers/allstar-techreport.pdf
https://github.com/thesues/antlr-calc-golang-example
https://github.com/antlr/antlr-php-runtime-phpstan
https://github.com/antlr/antlr4
https://github.com/antlr/intellij-plugin-v4
https://blog.gopheracademy.com/advent-2017/parsing-with-antlr4-and-go/
https://github.com/thesues/antlr-calc-golang-example



$ wget http://www.antlr.org/download/antlr-4.7-complete.jar
$ alias antlr=’java -jar $PWD/antlr-4.7-complete.jar’
$java -jar antlr-4.5.1-complete.jar
Error: Invalid or corrupt jarfile antlr-4.5.1-complete.jar



antlr -Dlanguage=Go -o parser Calc.g4



$ tree
├── Calc.g4
└── parser
├── calc_lexer.go
├── calc_parser.go
├── calc_base_listener.go
└── calc_listener.go



// example1.go
package main



import (
“fmt”
“github.com/antlr/antlr4/runtime/Go/antlr”



"./parser" )


func main() {
// Setup the input
is := antlr.NewInputStream(“1 + 2 * 3”)



// Create the Lexer
lexer := parser.NewCalcLexer(is)

// Read all tokens
for {
t := lexer.NextToken()
if t.GetTokenType() == antlr.TokenEOF {
break
}
fmt.Printf("%s (%q)\n",
lexer.SymbolicNames[t.GetTokenType()], t.GetText())
} }


// example2.go
package main



import (
“./parser”
“github.com/antlr/antlr4/runtime/Go/antlr”
)



type calcListener struct {
*parser.BaseCalcListener
}



func main() {
// Setup the input
is := antlr.NewInputStream(“1 + 2 * 3”)



// Create the Lexer
lexer := parser.NewCalcLexer(is)
stream := antlr.NewCommonTokenStream(lexer, antlr.TokenDefaultChannel)

// Create the Parser
p := parser.NewCalcParser(stream)

// Finally parse the expression
antlr.ParseTreeWalkerDefault.Walk(&calcListener{}, p.Start()) }


https://blog.gopheracademy.com/advent-2017/parsing-with-antlr4-and-go/



https://github.com/thesues/antlr-calc-golang-example
https://blog.csdn.net/RA681t58CJxsgCkJ31/article/details/102714446



https://blog.gopheracademy.com/advent-2017/parsing-with-antlr4-and-go/



https://liangshuang.name/2017/08/20/antlr/



https://abcdabcd987.com/notes-on-antlr4/



https://github.com/antlr/grammars-v4
https://blog.gopheracademy.com/advent-2017/parsing-with-antlr4-and-go/
https://github.com/antlr/grammars-v4/blob/master/basic/jvmBasic.g4



https://github.com/antlr/grammars-v4/blob/master/c/C.g4
https://github.com/antlr/grammars-v4/blob/master/graphql/GraphQL.g4



https://github.com/antlr/grammars-v4/blob/master/golang/GoParser.g4



https://studygolang.com/resources/10408
https://github.com/lightbend/config
https://stackoverflow.com/questions/53100633/antlr4-in-go-invalid-type-assertion-listener
https://www.zhihu.com/topic/20022823/hot



https://blog.csdn.net/diefen3773/article/details/101746629



https://www.jianshu.com/p/4bedad8dd70a
前面介绍LLVM的第一篇中,我们介绍过,编译器的后端基本都可以通过LLVM来解决。
那么,前端我们如何处理呢?我们选择ANTLR。



例子超丰富的ANTLR
ANTLR是用Java写的词法和语法分析工具。它比lex/flex/yacc/bison是更现代的工具。
最方便的一点是,ANTLR已经替我们写好了常用语言的语法规则,我们已经拥有了常见语言的分析器,可以在其基础上直接做我们想做的事情。网址在[https://github.com/antlr/grammars-v4/]



我们看一些例子吧。曾经火遍大江南北的谭浩强老师的《BASIC语言》还有人记得吗?DOS时代,GW-BASIC和QBasic是系统默认自带的语言,如同Unix上的cc编译器一样。



10 FOR I = 1 TO 10 STEP 1
20 PRINT I
30 NEXT I
40 END
我们来看一下ANTLR中对BASIC语言FOR循环的语法:




// for stmt 2 puts the for, the statment, and the next on 3 lines. It needs “nextstmt”

forstmt2

FOR vardecl EQ expression TO expression (STEP expression)?
;

nextstmt

NEXT (vardecl (‘,’ vardecl)*)?
;
完整的语法在:https://github.com/antlr/grammars-v4/blob/master/basic/jvmBasic.g4



还有更简单的么?有啊,汇编语言:https://github.com/antlr/grammars-v4/blob/master/masm/MASM.g4



言归正题,我们来看第一种大型的语言,C语言2011版的:https://github.com/antlr/grammars-v4/blob/master/c/C.g4



看个类型的吧,C11的还真不少:



typeSpecifier
: (‘void’
| ‘char’
| ‘short’
| ‘int’
| ‘long’
| ‘float’
| ‘double’
| ‘signed’
| ‘unsigned’
| ‘_Bool’
| ‘_Complex’
| ‘m128’
| ‘__m128d’
| ‘__m128i’)
| ‘__extension
’ ‘(‘ (‘m128’ | ‘__m128d’ | ‘__m128i’) ‘)’
| atomicTypeSpecifier
| structOrUnionSpecifier
| enumSpecifier
| typedefName
| ‘__typeof
’ ‘(‘ constantExpression ‘)’ // GCC extension
;
我们通过语法规则,大致可以估算一下语言的复杂度:



语言 语法行数 地址
C11 926 https://github.com/antlr/grammars-v4/blob/master/c/C.g4
C++14 2353 https://github.com/antlr/grammars-v4/blob/master/cpp/CPP14.g4
Go 1170 https://github.com/antlr/grammars-v4/blob/master/golang/Golang.g4
Java7 1017 https://github.com/antlr/grammars-v4/blob/master/java/Java.g4
Java8 1780 https://github.com/antlr/grammars-v4/blob/master/java8/Java8.g4
Lua 336 https://github.com/antlr/grammars-v4/blob/master/lua/Lua.g4
Pascal 972 https://github.com/antlr/grammars-v4/blob/master/pascal/pascal.g4
Python3 1558 https://github.com/antlr/grammars-v4/blob/master/python3/Python3.g4
Swift 1163 https://github.com/antlr/grammars-v4/blob/master/swift/Swift.g4
ECMA Script 5 1504 https://github.com/antlr/grammars-v4/blob/master/ecmascript/ECMAScript.g4
Erlang 391 https://github.com/antlr/grammars-v4/blob/master/erlang/Erlang.g4
Fortran 77 1363 https://github.com/antlr/grammars-v4/blob/master/fortran77/fortran77.g4
Scala 704 https://github.com/antlr/grammars-v4/blob/master/scala/Scala.g4
SQLite 905 https://github.com/antlr/grammars-v4/blob/master/sqlite/SQLite.g4
Clojure 262 https://github.com/antlr/grammars-v4/blob/master/clojure/Clojure.g4
从词法复杂度上看:



C,Java7,Swift,Go这几门语法的复杂度是比较适中的
C++和Java 8确实是比较复杂的,比起它们的前辈C和Java 7都变复杂了不少
JavaScript和Python3已经比较复杂了
Clojure,Lua和Erlang是惊喜,规模小,表现力强
装上玩玩吧
既然ANTLR有这么丰富的例子供我们参考,我们就装一个玩玩吧。
在macOS上,通过Homebrew就可以安装。



在Linux上,通过下面的步骤来安装:



wget http://www.antlr.org/download/antlr-4.6-complete.jar
export CLASSPATH=”.:/path/to/antlr-4.6-complete.jar:$CLASSPATH”
alias antlr4=’java -jar /path/to/antlr-4.6-complete.jar’
alias grun=’java org.antlr.v4.gui.TestRig’
照抄个Hello,World的例子试一下吧:



grammar Hello ;
r : ‘hello’ ID ;
ID: [a-z]+ ;
WS : [ \t\r\n]+ -> skip ;
都是正则表达式,很容易理解,ID是小写字母组成的,WS是空格制表符回车换行符,空白符过滤掉。



输入antlr4 Hello.g4,就生成了好几个.java文件,调用javac编译一下。成功!



antlr4 Hello.g4
javac *.java
生成的文件,我们快速浏览一下:
第一个,HelloListener.java:



// Generated from Hello.g4 by ANTLR 4.6
import org.antlr.v4.runtime.tree.ParseTreeListener;



/**



  • This interface defines a complete listener for a parse tree produced by

  • {@link HelloParser}.
    */
    public interface HelloListener extends ParseTreeListener {
    /**

    • Enter a parse tree produced by {@link HelloParser#r}.

    • @param ctx the parse tree
      */
      void enterR(HelloParser.RContext ctx);
      /**

    • Exit a parse tree produced by {@link HelloParser#r}.

    • @param ctx the parse tree
      */
      void exitR(HelloParser.RContext ctx);
      }
      R是我们刚才定义的语法规则,在进入和退出时,这个接口是提供回调的接口。





Hello.tokens:



T__0=1
ID=2
WS=3
‘hello’=1
HelloParser.java是解析器。



打包一个可以直接利用java -jar



jar cvfm lottery.jar MANIFEST.MF jdbc.properties com
如果出现:
java.io.IOException: invalid header field
这样的错误的话,就说明MANIFEST.MF文件有问题,比如写成了这样:
Manifest-Version: 1.0
Main-Class:com.feishan.lottery.view.Index



Class-Path: jar/jdbc_feishan.jar jar/mysql5.0.3.jar



或者如果觉得打的可运行jar包那里都是对的,但执行java -jar lottery.jar 或者 java -cp lottery.jar com.test.Test



怎么运行都是 Invalid or corrupt jarfile 要么就是 Could not find or load main class 那么99%绝对是MANIFEST.MF文件有问题



注意:
Main-Class:后面应该有一个空格
Manifest-Version: 1.0
Main-Class: com.feishan.lottery.view.Index
Class-Path: jar/jdbc_feishan.jar jar/mysql5.0.3.jar
这样写就对了注意:最后一行也要有一个回车键。否则后面那一行是不能打包进去的



最后用java -jar lottery.jar就可以运行了
这个 manifest.mf 可以放在任何位置,也可以是其它的文件名,
只需要有 Main-Class: test.Test 一行,且该行以一个回车符结束即可



最后Manifest 技巧说明:
总是以Manifest-Version属性开头
每行最长72个字符,如果超过的化,采用续行
确认每行都以回车结束,否则改行将会被忽略
如果Class-Path 中的存在路径,使用”/”分隔目录,与平台无关
使用空行分隔主属性和package属性
使用”/”而不是”.”来分隔package 和class ,比如 com/example/myapp/
class 要以.class结尾,package 要以 / 结尾



Error: Invalid or corrupt jarfile jar
遇到的问题:IDEA打包可执行jar包,报错Error: Invalid or corrupt jarfile jar
检索问题,看到各种千奇百怪的方法,比如:修改文件后使用jar命令重新打包,还有说要把MANIFEST.MF 大写修改为小写的manifest等,这里谈一种有效的解决方法。



解决方案适用性:IDEA(其它IDE尚未测试)



原因:IDEA中,在File\Project Structure\Artifacts\添加artifacts的时候,默认会在src/main/java/META_INF/下创建目录,但是此目录(src/main/java/)已标记为Sources Root,只编译;



解决方案:将src/main/java/META_INF剪切到目录src/main/resources/META_INF/,src/main/resources/是Resources Root,最后文件会拷贝到out目录。
https://www.jianshu.com/p/18396dce6263



打jar包



1.jar -cvf hello.jar hello.class 



2.这时java -jar hello.jar 是运行不了的



3.解压刚打的Jar包到新的目录,会发现里边多了一个META-INF文件夹里边有一个MANIFEST.MF文件



4.用记事本打开MANIFEST.MF文件,修改为



Manifest-Version: 1.0



Main-Class: Hello



Created-By: aaa



5.将MANIFEST.MF复制到和Hello.class 放在一起



然后打包:



jar cvfm abc.jarMANIFEST.MFHello.class



得到可运行的jar



 



java -jar  *   就可以运行的jar包[ 其中*为jar包名] 



  打 Java 包的时候可以有一个清单文件:MANIFEST.MF,它是打包的关键性文件,主要是设置执行入口类和支持库的路径,在运行 Java应用程序时会根据此文件中给出的信息来查找入口类和支持库。
它的内容一般包括:



Manifest-Version: 1.0



Created-By: 1.6.0 (Sun Microsystems Inc.)



Main-Class: HelloWorld



 
 
其中比较容易忽略的是还可以有一个Class-Path属性的设置,Class-Path:用来指定支持库的路径,程序运行时依据 Class-Path项的设置路径来查找支持库,每一个支持库之间用空格分开。比如这样写清单文件:



Manifest-Version: 1.0



Class-Path: ./lib/msbase.jar ./lib/mssqlserver.jar ./lib/msutil.jar



Created-By: yourName



Main-Class: org.qiujy.test.TestDB



如果出现:



java.io.IOException: invalid header field



这样的错误的话,就说明MANIFEST.MF文件有问题,比如写成了这样:



Manifest-Version: 1.0



Main-Class:com.feishan.lottery.view.Index
Class-Path: jar/jdbc_feishan.jar jar/mysql5.0.3.jar



注意:



Main-Class:后面应该有一个空格:
Manifest-Version: 1.0
Main-Class: com.feishan.lottery.view.Index
Class-Path: jar/jdbc_feishan.jar jar/mysql5.0.3.jar
这样写就对了注意:最后一行也要有一个回车键。否则后面那一行是不能打包进去的



最后用java -jar lottery.jar就可以运行了



这个 manifest.mf (证明)可以放在任何位置,也可以是其它的文件名,



只需要有 Main-Class: test.Test 一行,且该行以一个回车符结束



https://blog.csdn.net/master_yao/article/details/51089745



mkdir -p src/main/resources
vi src/main/resources/META_INF
Manifest-Version: 1.0
Implementation-Vendor: ANTLR
Implementation-Title: ANTLR 4 Tool
Implementation-Version: 4.8
Implementation-Vendor-Id: org.antlr
Built-By: parrt
Build-Jdk: 1.7.0_65
Created-By: Apache Maven 3.6.3
Implementation-URL: http://www.antlr.org
Main-Class: org.antlr.v4.Tool
Archiver-Version: Plexus Archiver



jar cvfm antlr-4.5.1-complete.jar src/main/resources/META_INF



$java -jar antlr-4.5.1-complete.jar
错误: 找不到或无法加载主类 org.antlr.v4.Tool



https://blog.csdn.net/master_yao/article/details/51089745
https://tomassetti.me/category/language-engineering/antlr/#setup-antlr



$export CLASSPATH=”.:/Users/didi/PhpstormProjects/c/json-parser/antlr/antlr-4.5.1-complete.jar:$CLASSPATH”



$java -Xmx500M -cp “/Users/didi/PhpstormProjects/c/json-parser/antlr/antlr-4.5.1-complete.jar:$CLASSPATH” org.antlr.v4.Tool
错误: 找不到或无法加载主类 org.antlr.v4.Tool
https://www.jianshu.com/p/b4714b98389d



https://www.cnblogs.com/chunzhulovefeiyue/p/7577199.html



https://blog.csdn.net/cl2010abc/article/details/104944662


Category golang