网络上的ANTLR:为什么?
我开始在MS-DOS上编写我的第一个程序。 因此,我非常习惯在计算机上安装工具。 但是在2016年,网络无处不在,因此那里也可能需要我们的语言。
可能的情况:
- ANTLR 也在网络上:
- 用户可能还希望从网络访问DSL编写的较小更改文件,并可能对其进行细微更改,同时继续使用胖客户端执行复杂任务。
- ANTLR 仅在网络上:
- 您正在与不愿安装IDE的领域专家打交道,因此他们更喜欢使用一些Web应用程序编写DSL程序。
在第一种情况下,您可以使用Java目标和 Javascript目标来生成ANTLR解析器,而在第二种情况下,您可以仅以JavaScript为目标
一个简单的例子:待办事项清单
在此示例中,我们将使用的DSL非常简单:它将表示一个待办事项列表,其中每个待办事项都包含在单独的行中,并以星号开头。
有效输入的示例:
* do this
* do that
* do something else after an empty line
这是我们的语法:
grammar todo;
elements
: (element|emptyLine)* EOF
;
element
: '*' ( ' ' | '\t' )* CONTENT NL+
;
emptyLine
: NL
;
NL
: '\r' | '\n'
;
CONTENT
: [a-zA-Z0-9_][a-zA-Z0-9_ \t]*
;
使用ANTLR Javascript目标
您将需要安装ANTLR工具来为我们的解析器生成Javascript代码。 您可以使用简单的Gradle脚本来代替手动下载ANTLR及其依赖项。 更新所使用的ANTLR版本也非常简单。
apply plugin: 'java'
repositories {
jcenter()
}
dependencies {
runtime 'org.antlr:antlr4:4.5.2'
}
task generateParser(type:JavaExec) {
main = 'org.antlr.v4.Tool'
classpath = sourceSets.main.runtimeClasspath
args = ['-Dlanguage=JavaScript', 'todo.g4', '-o', 'static/generated-parser']
}
您现在可以通过运行以下命令来生成解析器:
gradle generateParser
好的,这很简单。
调用解析器
不幸的是,仅打开本地文件时,我们使用的JS库无法正常工作:这意味着对于我们的小示例,我们也需要使用HTTP。 我们的Web服务器只需要提供大量静态文件即可。 为此,我选择在flask中编写一个超级简单的应用程序。 提供静态文件的替代方案有数百万种,因此请选择您喜欢的一种。 我不会在这里详细说明如何通过flask提供静态文件,但是GitHub上提供了代码,如果您对此有疑问,可以在此帖子中添加评论以告知我。
我们的静态文件将包括:
- 通过运行gradle generateParser得到的生成的解析器
- Antlr4 JS运行时
- JS库require.js
- HTML和CSS
您可以从此处获取Antlr4 JS运行时。 为了避免必须手动导入数十个文件,我们将使用require.js。 您可以从此处获取我们需要的口味或require.js。
我们将添加一个文本区域和一个按钮。 当用户单击按钮时,我们将解析文本区域的内容。 简单吧?
这是此设计杰作HTML代码:
<div id="inputs">
<textarea id="code">
* play with antlr4
* write a tutorial
</textarea>
<br/>
<button id="parse">Parse</button>
</div>
首先,导入require.js:
<script type="text/javascript" src="lib/require.js"></script>
顺便说一句,我们没有使用jQuery,我知道这可能令人震惊。
好,现在我们必须调用解析器
<script type="text/javascript">
var antlr4 = require('antlr4/index');
var TodoLexer = require('generated-parser/todoLexer');
var TodoParser = require('generated-parser/todoParser');
document.getElementById("parse").addEventListener("click", function(){
var input = document.getElementById("code").value;
var chars = new antlr4.InputStream(input);
var lexer = new TodoLexer.todoLexer(chars);
var tokens = new antlr4.CommonTokenStream(lexer);
var parser = new TodoParser.todoParser(tokens);
parser.buildParseTrees = true;
var tree = parser.elements();
console.log("Parsed: "+ tree);
});
</script>
太好了,现在我们的代码已解析,但是我们不对其执行任何操作。 当然,我们可以在浏览器中启动开发者控制台,并打印有关树的一些信息,以验证树是否正常工作并熟悉ANTLR返回的树的结构。
显示结果
如果我们正在构建某种TODO应用程序,我们可能希望以某种方式表示用户通过DSL插入的信息。
让我们得到这样的东西:
为此,我们基本上需要添加函数updateTree来导航由ANTLR返回的树,并构建一些DOM节点来表示其内容
<script type="text/javascript">
var updateTree = function(tree, ruleNames) {
var container = document.getElementById("tree");
while (container.hasChildNodes()) {
container.removeChild(container.lastChild);
}
for (var i = 0; i < tree.children.length; i++) {
var child = tree.children[i];
var nodeType = ruleNames[child.ruleIndex];
if (nodeType == "element") {
var newElement = document.createElement("div");
newElement.className = "todoElement";
var newElementText = document.createTextNode(child.children[2].getText());
newElement.appendChild(newElementText);
container.appendChild(newElement);
}
}
};
var antlr4 = require('antlr4/index');
var TodoLexer = require('generated-parser/todoLexer');
var TodoParser = require('generated-parser/todoParser');
document.getElementById("parse").addEventListener("click", function(){
var input = document.getElementById("code").value;
var chars = new antlr4.InputStream(input);
var lexer = new TodoLexer.todoLexer(chars);
var tokens = new antlr4.CommonTokenStream(lexer);
var parser = new TodoParser.todoParser(tokens);
parser.buildParseTrees = true;
var tree = parser.elements();
console.log("Parsed: "+ tree);
updateTree(tree, parser.ruleNames);
});
</script>
干得好!
码
如果这不是您第一次阅读此博客,则可能会怀疑某些代码即将到来。 和往常一样,代码在GitHub上: https : //github.com/ftomassetti/antlr-web-example
下一步
下一步是执行错误处理:我们要捕获错误并将其指向用户。 然后,我们可能想通过使用ACE来添加语法突出显示。 这似乎是一个很好的起点:
我真的认为简单的文本DSL可以帮助使多个应用程序更加强大。 但是,在网络上创建良好的编辑体验并非易事。 我想花更多时间玩这个。
翻译自: https://www.javacodegeeks.com/2016/05/antlr-web-simple-example.html