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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/353258.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Matlab回归分析regress和polyfit

在matlab中regress()函数和polyfit()函数都可以进行回归分析。 (1)regress()函数主要用于线性回归,一元以及多元的。它可以提供更多的信息,残差之类的。 (2)polyfit()函数是利用多项式拟合。可以是线性也可以是非线性的。 (1)regress()函数详解 [b,bint,r,…

ACM计算几何题目推荐

一。基础题目 1.1 有固定算法的题目 A&#xff0c; 最近点对问题 最近点对问题的算法基于扫描线算法。 ZOJ 2107 Quoit Design 典型最近点对问题 POJ 3714 Raid 变种最近点对问题 B&#xff0c;最小包围圆 最小包围圆的算法是一种增量算法&#xff0c;期望…

洛谷 P1027 Car的旅行路线

P1027 Car的旅行路线 题目描述 又到暑假了&#xff0c;住在城市 AA 的 CarCar 想和朋友一起去城市 BB 旅游。她知道每个城市都有 44 个飞机场&#xff0c;分别位于一个矩形的 44 个顶点上&#xff0c;同一个城市中 22 个机场之间有 11 条笔直的高速铁路&#xff0c;第 II 个城市…

Matlab各种拟合

线性拟合见上一篇《回归分析》 非线性拟合: cftool %curve fitting toolbox非线性函数拟合工具箱。要确定系数的初始值和上下限(sftool用于三维的) %该函数可以生成m文件函数,方便在编程中使用,但是生成的m文件函数拟合的结果会有很大的误差和图形界面的结果不一样 1 comman…

Matlab线性规划(Linear Programming)

bintprog&#xff1a;0-1规划linprog:线性规划quadprogoptimtool整数规划第三方工具箱&#xff1a;YALMIP http://users.isy.liu.se/johanl/yalmip/pmwiki.php?nMain.Download

java(IO)读写文件乱码转换UTF-8问题

java(IO)读写文件乱码转换UTF-8问题 读取文件String Content  ""; // 文件很长的话建议使用StringBuffertry {FileInputStream fsnew FileInputStream("文件录取");InputStreamReader isr  new InputStreamReader(fis, "UTF-8");Buff…

类固醇上的Java:5种超级有用的JIT优化技术

Java开发人员&#xff1f; 优化您的生产监控。 请在所有已记录的错误&#xff0c;警告和异常之后查看源代码&#xff0c;调用堆栈和变量状态- 尝试Takipi 。 最有用的JVM JIT优化有哪些&#xff1f;如何使用它们&#xff1f; 即使您没有积极计划&#xff0c;JVM也有很多技巧可…

poj3714 最近点对

最近点对&#xff0c;采用分治方法。过程&#xff1a; 1对原数组依据x左标从小到大排序。 2二分数组&#xff0c;左边求出最小值&#xff0c;右边求出最小值&#xff0c;我们求最小的。 3找出对于左右两边的可能小于当前最小值的最近点对&#xff0c;更新最小值。 这题目需要区…

Matlab 格式化字符串sscanf

sscanf 是按一定的格式从字符串中读取出字符,它有以下几种用法: A = sscanf(str, format) A = sscanf(str, format, sizeA) [A, count] = sscanf(...) [A, count, errmsg] = sscanf(...) [A, count, errmsg, nextindex] = sscanf(...) Description A = sscanf(str, forma…

2018牛客暑假多校二 D(贪心)

题目描述&#xff1a; 你要按照顺序以此经过n个商店&#xff0c;每到达一个商店你可以购买一件物品&#xff0c;也可以出售你手中的商品。 同一时刻你手上最多拿一件商品。在第i个商店购买和出售的代价都是a[i]。 问你经过完n个商店后的最大收益。 同时&#xff0c;在最大化收…

ZOJ1450 Minimal Circle 最小圆覆盖

包含点集所有点的最小圆的算法 http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemId450 平面上有n个点&#xff0c;给定n个点的坐标&#xff0c;试找一个半径最小的圆&#xff0c;将n 个点全部包围&#xff0c;点可以在圆上。 1. 在点集中任取3点A,B,C。 2. 作一个包…

遗传算法各Matlab工具箱简介

关于matlab遗传算法工具箱主要有三种&#xff1a;1、gaot工具箱&#xff1a;这是网上流传的免费的工具箱&#xff0c;网上对它介绍的资料也挺多&#xff0c;它不是Matlab软件自带的&#xff0c;但可以自己配置使用。飞思科技产品研发中心编著《Matlab 6.X辅助优化计算与设计》第…

独眼巨人反应组织了Java 8库的寒武纪爆发

什么是独眼巨人反应&#xff1f; Lambda表达式和默认方法在Java 8中的出现预示了Java语言十年来最大的结构性变化。 在此基础上构建了一些新的很酷的API&#xff0c;例如Stream, Optional, CompletableFuture最终Java开发人员可以以更实用的样式进行编码。 尽管这是非常受欢迎的…

C语言中文件定位函数总结

C语言中文件定位函数主要是&#xff1a;fseek, ftell, fsetpos, fgetpos。 先来讲前两个函数&#xff0c;这是最基本的定位函数&#xff1a; fseek函数&#xff1a;能把文件指针移动到文件任何位置&#xff0c;其原型是&#xff1a;int fseek(FILE *fp, long offset, int fromw…

API

api 百科名片 API&#xff08;Application Programming Interface,应用程序编程接口&#xff09;是一些预先定义的函数&#xff0c;目的是提供应用程序与开发人员基于某软件或硬件的以访问一组例程的能力&#xff0c;而又无需访问源码&#xff0c;或理解内部工作机制的细节。目…

Matlab gatool使用方法

可以通过输入gatool或者optimtool(ga)打开图形界面或者用ga()运行命令行函数设置Fitnessfunction 和对应的Number of variables,为了提高效率最好向量化适应度函数,然后设置Vectorize参数为On可以选择相应参数进行设置Population种群参数Fitness scalling适应度比例参数Selecti…

系统模块 OS

os.system("系统命令") 调用系统命令 os.system("task kill /f /im 系统的进程") 关闭系统进程 os.listdir(地址) 扫描目录里面的文件。默认的是当前文件夹 返回一个列表 import os # os.listdir(地址) 扫描目录里面的文件。默认的是当前文件夹 print(os.…

Matlab非线性拟合工具箱cftool

一、 单一变量的曲线逼近 Matlab有一个功能强大的曲线拟合工具箱 cftool &#xff0c;使用方便&#xff0c;能实现多种类型的线性、非线性曲线拟合。下面结合我使用的 Matlab R2007b 来简单介绍如何使用这个工具箱。 假设我们要拟合的函数形式是 yA*x*x B*x, 且A>0,B>0…

jsf标签p:ajax_JSF简单Ajax示例

jsf标签<p:ajax>今天&#xff0c;我们将看到一些使用JSF的Ajax简单样本。 如果要查看有关JSF / Web应用程序的其他文章&#xff0c;请单击以下链接&#xff1a; 重定向后的JSF持久化对象和消息 &#xff0c; 使用JAAS和JSF进行用户登录验证 &#xff0c; JSF&#xff1a;…

C#中数据库事务、存储过程基本用法

SQL 事务 public bool UpdateQsRegisterSql(List<string> ids, int newQueueId, string newQueueName){using (SqlConnection con new SqlConnection(DBHelper.Instance.ConStr)){SqlTransaction tran null;try{con.Open();SqlCommand cmd con.CreateCommand();tran …