ANTLR和网络:一个简单的例子

网络上的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。

我们将添加一个文本区域和一个按钮。 当用户单击按钮时,我们将解析文本区域的内容。 简单吧?

Selection_052

这是此设计杰作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返回的树的结构。

Selection_054

显示结果

如果我们正在构建某种TODO应用程序,我们可能希望以某种方式表示用户通过DSL插入的信息。

让我们得到这样的东西:

Selection_053

为此,我们基本上需要添加函数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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值