antlr idea 入门
这是该系列的第一篇文章。 本系列的目的是描述如何创建有用的语言和所有支持工具。
在本文中,我们将开始研究一种非常简单的表达语言。 我们将在语言沙箱中构建它,因此我们将其称为语言Sandy 。
我认为工具支持对于一种语言至关重要:因此,我们将从一种非常简单的语言开始,但是我们将为此提供丰富的工具支持。 要从一种语言中受益,我们需要解析器,解释器和编译器,编辑器等。 在我看来,构建简单的解析器的材料很多,但是构建使用语言的实用和有效所需的其余基础结构的材料却很少。
我想专注于这些方面,使语言小巧但完全有用。 然后,您将能够有机地增长语言。
该代码可在GitHub上找到: https : //github.com/ftomassetti/LangSandbox 。 本文中提供的代码对应于标签01_lexer。
语言
该语言将允许定义变量和表达式。 我们将支持:
- 整数和十进制文字
- 变量定义和赋值
- 基本数学运算(加,减,乘,除)
- 括号的用法
有效文件的示例:
var a = 10 / 3
var b = (5 + 3) * 2
var c = a / b
我们将使用的工具
我们将使用:
- ANTLR生成词法分析器和解析器
- 使用Gradle作为我们的构建系统
- 用Kotlin编写代码。 鉴于我刚开始学习它,这将是非常基本的Kotlin。
设置项目
我们的构建。 gradle文件将如下所示
buildscript {ext.kotlin_version = '1.0.3'repositories {mavenCentral()maven {name 'JFrog OSS snapshot repo'url 'https://oss.jfrog.org/oss-snapshot-local/'}jcenter()}dependencies {classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"}
}apply plugin: 'kotlin'
apply plugin: 'java'
apply plugin: 'idea'
apply plugin: 'antlr'repositories {mavenLocal()mavenCentral()jcenter()
}dependencies {antlr "org.antlr:antlr4:4.5.1"compile "org.antlr:antlr4-runtime:4.5.1"compile "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"compile "org.jetbrains.kotlin:kotlin-reflect:$kotlin_version"testCompile "org.jetbrains.kotlin:kotlin-test:$kotlin_version"testCompile "org.jetbrains.kotlin:kotlin-test-junit:$kotlin_version"testCompile 'junit:junit:4.12'
}generateGrammarSource {maxHeapSize = "64m"arguments += ['-package', 'me.tomassetti.langsandbox']outputDirectory = new File("generated-src/antlr/main/me/tomassetti/langsandbox".toString())
}
compileJava.dependsOn generateGrammarSource
sourceSets {generated {java.srcDir 'generated-src/antlr/main/'}
}
compileJava.source sourceSets.generated.java, sourceSets.main.javaclean{delete "generated-src"
}idea {module {sourceDirs += file("generated-src/antlr/main")}
}
我们可以运行:
- ./gradlew想法来生成IDEA项目文件
- ./gradlew generateGrammarSource生成ANTLR词法分析器和解析器
实施词法分析器
我们将在两个单独的文件中构建词法分析器和解析器。 这是词法分析器:
lexer grammar SandyLexer;// Whitespace
NEWLINE : '\r\n' | 'r' | '\n' ;
WS : [\t ]+ ;// Keywords
VAR : 'var' ;// Literals
INTLIT : '0'|[1-9][0-9]* ;
DECLIT : '0'|[1-9][0-9]* '.' [0-9]+ ;// Operators
PLUS : '+' ;
MINUS : '-' ;
ASTERISK : '*' ;
DIVISION : '/' ;
ASSIGN : '=' ;
LPAREN : '(' ;
RPAREN : ')' ;// Identifiers
ID : [_]*[a-z][A-Za-z0-9_]* ;
现在,我们可以简单地运行./ gradlew generateGrammarSource,并且将根据先前的定义为我们生成词法分析器。
测试词法分析器
测试始终很重要,但是在构建语言时绝对至关重要:如果支持您的语言的工具不正确,这可能会影响您将为其构建的所有程序。 因此,让我们开始测试词法分析器:我们只需要验证词法分析器产生的标记序列就是我们所关注的。
package me.tomassetti.sandyimport me.tomassetti.langsandbox.SandyLexer
import org.antlr.v4.runtime.ANTLRInputStream
import java.io.*
import java.util.*
import org.junit.Test as test
import kotlin.test.*class SandyLexerTest {fun lexerForCode(code: String) = SandyLexer(ANTLRInputStream(StringReader(code)))fun lexerForResource(resourceName: String) = SandyLexer(ANTLRInputStream(this.javaClass.getResourceAsStream("/${resourceName}.sandy")))fun tokens(lexer: SandyLexer): List<String> {val tokens = LinkedList<String>()do {val t = lexer.nextToken()when (t.type) {-1 -> tokens.add("EOF")else -> if (t.type != SandyLexer.WS) tokens.add(lexer.ruleNames[t.type - 1])}} while (t.type != -1)return tokens}@test fun parseVarDeclarationAssignedAnIntegerLiteral() {assertEquals(listOf("VAR", "ID", "ASSIGN", "INTLIT", "EOF"),tokens(lexerForCode("var a = 1")))}@test fun parseVarDeclarationAssignedADecimalLiteral() {assertEquals(listOf("VAR", "ID", "ASSIGN", "DECLIT", "EOF"),tokens(lexerForCode("var a = 1.23")))}@test fun parseVarDeclarationAssignedASum() {assertEquals(listOf("VAR", "ID", "ASSIGN", "INTLIT", "PLUS", "INTLIT", "EOF"),tokens(lexerForCode("var a = 1 + 2")))}@test fun parseMathematicalExpression() {assertEquals(listOf("INTLIT", "PLUS", "ID", "ASTERISK", "INTLIT", "DIVISION", "INTLIT", "MINUS", "INTLIT", "EOF"),tokens(lexerForCode("1 + a * 3 / 4 - 5")))}@test fun parseMathematicalExpressionWithParenthesis() {assertEquals(listOf("INTLIT", "PLUS", "LPAREN", "ID", "ASTERISK", "INTLIT", "RPAREN", "MINUS", "DECLIT", "EOF"),tokens(lexerForCode("1 + (a * 3) - 5.12")))}
}
结论和下一步
我们从第一步开始:设置项目并构建词法分析器。
使这种语言在实践中可用之前,我们还有很长的路要走,但我们还是开始了。 接下来,我们将使用相同的方法来处理解析器:构建一些简单的东西,以便我们可以通过命令行进行测试和编译。
翻译自: https://www.javacodegeeks.com/2016/07/getting-started-antlr-building-simple-expression-language.html
antlr idea 入门