ANTLR入门:构建一种简单的表达语言
這是該系列的第一篇文章。 本系列的目的是描述如何創建有用的語言和所有支持工具。
在本文中,我們將開始研究一種非常簡單的表達語言。 我們將在語言沙箱中構建它,因此我們將其稱為語言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入门:构建一种简单的表达语言的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 危险的英文(危险的ddos)
- 下一篇: 类固醇上的Java:5种超级有用的JIT