在java中编写自定义语法解释器? [英] Write a custom syntax interpreter in java?

查看:193
本文介绍了在java中编写自定义语法解释器?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我即将开始为我即将举办的讲座编写一个演示程序。我想让班上的每个学生都下载这个应用程序,然后能够通过命令行以交互方式创建对象实例(及其图形表示)。我决定用java编写,不是因为它是我最熟悉的语言,而是因为它有简单的图形类,我可以非常肯定jar会在他们的计算机上运行。

I am about to begin coding a demo program for a lecture I'm about to give. I want to let each student in the class download this application, then be able to create instances of objects (and their graphical representations) interactively via a command line. I decided to write in java, not because it's the language I'm most familiar with, but because it's got easy graphics classes and I can be pretty sure that the jar is going to run on their computers.

简介。现在的问题是:

为这个程序实现一些自定义命令行语法的好方法是什么?我想使用一个简单,随意的语法,如:

What is a good way to implement some custom command line syntax for this program? I want to use a simple, arbitrary syntax like:

CREATE Monster Bob;    
Bob.jump();   
LS Bob //to list Bob's methods or something.   
LS CREATE //to list all the classes    

首先我会先说一下我想到这个问题时浮现在脑海中。

First I'll spiel about what first came to mind when I thought of this problem.

我可以想象我可以在树型链接中拥有一组地图。我可以解析每个关键词作为下一个地图的关键。因此,CREATE Monster Bob可以被评估为

I can imagine that I could have a set of maps in a tree type linkage. I could parse each key word as the key to the next map. So "CREATE Monster Bob" could be evaluated like

1)搜索关键字CREATE的关键字映射。返回值,该值是对类映射的引用。
2)搜索类映射关键怪物。返回值,这是一个实现一些接口Leaf的工厂类,它让我知道它是一个叶子值(我将使用instanceof进行检查)。

3)也许Leaf接口将包含一个名为execute的方法()将做任何想做的事情。在这种情况下,它将创建一个Monster对象,将此对象添加到名为Objects的名为Bob的地图中。 (这个Leaf业务听起来很难看,但可以清理。)

1) Search keyword map for key "CREATE". Return the value, which is a reference to the map of classes. 2) Search classes map for key "Monster". Return the value, which is a factory class implementing some interface Leaf that lets me know it is a leaf value (I'll check using instanceof).
3) Maybe the Leaf interface will contain a method called execute() that will do whatever it wants. In this case it would create an object of Monster, adding this object to a map called Objects with the name Bob. (This Leaf business sounds ugly but it could be cleaned up.)

很酷。但是这个陈述对我来说有点困难:
Bob.jump();

Cool. But this statement is a little harder for me: Bob.jump();

1)搜索一些对象的地图为Bob。返回一些使用类似evaluate(String s)的方法实现接口的对象,并将字符串jump()传递给它:
2)Bob搜索方法的某些内部地图jump(),然后...?在c ++中,我将把键作为指向将被执行的成员函数Monster.jump()的指针。但是我不相信java中没有函数指针这样的东西。我已经读过你可以使用匿名类来完成这个,虽然我没有尝试过。看起来它会起作用。

1)Search some map of objects for "Bob". Return some object implementing an interface with a method like "evaluate(String s)" and pass it the string "jump()"
2)Bob searches some internal map of methods for "jump()", then...? In c++ I would have the key be a pointer to the member function Monster.jump() which would be executed. But there is no such thing as a function pointer in java I don't believe. I have read you can use an anonymous class to accomplish this, though I haven't tried. Looks like it would work.

所以,这会有效,但有更优雅的方法吗?我以前从未写过任何类型的翻译。如果有人提供一些提示,我想以一种很好的方式做一些事情并在这个过程中学到一些东西。如果我不是很结构化的话,这似乎是一种可能容易出错的方法,特别是当Bob和其他所有对象开始解析自己的指令和使用匿名函数时。此外,看起来除了普通代码之外,每个类都需要一个运行时就绪的接口。

So, this will work, but is there a more elegant way to go about this? I've never written any type of interpreter before. I'd like to do it a nice way and learn something in the process if somebody has some tips. This seems like a potentially error prone way to do things if I'm not very structured, especially when Bob and every other object start parsing their own instructions and using anonymous functions. In addition, it looks like every class will need a runtime-ready interface besides its normal code.

我也不太了解Java,所以如果有的话我可能会碰到砖墙的一些地方,然后我也想知道。

I also don't know Java all that well, so if there are some spots where I might hit a brick wall, then I'd like to know too.

先谢谢你的帮助。

推荐答案

我实际上建议使用Python - 除非有非常好的理由不这样做。

I would actually suggest using Python -- unless there is a really good reason not to.

这是因为:


  1. Python有一个非常好 IDE / REPL称为IDLE 。我不能说使用好的 Read-Eval-Print-Loop 反馈周期非常适合学习/玩耍。喜欢冒险的学生甚至可以直接进入!

  2. 图形支持是跨平台的,并通过 TkInter

  3. 对于初学者和/或非程序员而言,我发现它比Java更好。 (Python实际上是不是我最喜欢的语言,但它非常适合初学者,并且还有非常很好的IDE / REPL。)

  4. 更少为你工作; - )

  1. Python has a really nice IDE/REPL called IDLE. I can't say enough about using a good Read-Eval-Print-Loop: the short feedback cycle is very good for learning/playing. Adventurous students might even jump right in!
  2. Graphics support is cross-platform and well-supported via TkInter.
  3. I find it a better language for beginners and/or non-programmers than Java. (Python actually is not my favorite language, but it is very beginner-friendly and again, has a very nice IDE/REPL.)
  4. It is much less work for you ;-)

这是Python代码的用法该演示可能看起来:

This is how the Python code for the demo might look:

Bob = BigMonster()
Bob.jump()
dir(Bob)
dir(Monters)

因为所有这些只是常规Python语法没有解析 - 只需创建几个类,也许实现 __ dir __ 协议,一切准备就绪。如果需要Java集成,还有 Jython ,虽然我从未尝试过IDLE(或者知道它是否支持)。

Since all of this is just regular Python syntax there is no parsing -- just create a few classes, perhaps implement the __dir__ protocol, and everything is ready to go. If Java integration is a requirement there is also Jython, although I have never tried that with IDLE (or know if it's supported as such).

快乐编码。

基于图像的< a href =http://en.wikipedia.org/wiki/Smalltalk =noreferrer> SmallTalk ,例如 Sqeak 比Python更具交互性,因为代码 是持久运行环境的一部分。但是,找到一个好的图像需要一些时间 - 吱吱声不是最好的实现,但它是免费的 - 并且学习特定的SmallTalk环境。因此,虽然整合最终可能有很大的支出,但它确实需要更多的适应性:)

An Image-based SmallTalk such as Sqeak is far more interactive than Python as the code is part of the persistent running environment. However, it takes some time to find a good image -- Squeak is hardly the best implementation, but it is free -- and learn the particular SmallTalk environment. Thus, while the integration can ultimately have big payouts it does take more acclimatization :)

但是,唉,追求Java中的简单解析器,这些将是有意义的:

But, alas, to pursue a simple parser in Java, these will be of interest:


  1. A 词法分析器将输入文本转换为标记符号,并且;

  2. 并且递归下降解析器(这是一种非常简单的解析方法),
  1. A lexer which turns the input text into a steam of tokens, and;
  2. And a recursive descent parser (this is a really easy parsing approach) which either

  1. 构建一个< a href =http://en.wikipedia.org/wiki/Abstract_syntax_tree =noreferrer> AST(抽象语法树)可以在以后走路(读取:运行),或者;

  2. 或现在做东西(立即评估)

  1. Builds an AST (Abstract Syntax Tree) which can be walked (read: "run") later, or;
  2. Or "does stuff" right now (immediate evaluation)


简单的递归下降解析器是一个Java崩溃课程公司简介上面的内容。 这是一些代码用于中微子语法的递归下降解析器,无论是什么 - 查看注释以及递归下降解析器能够匹配 EBNF语法的程度。

A Simple Recursive Descent Parser is a Java crash-course introduction to the concepts above. Here is some code for a recursive-descent parser for "neutrino syntax", whatever that is -- look at the comments and how well a recursive-descent parser can match the EBNF grammar.

现在,它只是定义这种伪/迷你语言的语义规则并实现它的问题; - )

Now, it's "just" a matter of defining the semantic rules of this pseudo/mini-language and implementing it ;-)

更多地探索语义/ Java方法(部分只是原始帖子的简化/重新声明):

Exploring the semantics/Java approach a little bit more (parts are just a simplification/re-statement of the original post):

CREATE Monster Bob

会创建一个新的MonsterObject。一些方法可能是:

Would create a new MonsterObject. Some approaches might be:


  1. 使用反射创建对象,或者;

  2. 一个Factory类的地图(来自String - > FactoryObject),如上所述,或者;

  3. 一个简单的静态if-else分支。

  1. Create the object with reflection, or;
  2. a map of Factory classes (from String -> FactoryObject) as talked about, or;
  3. a simple static if-else-branch.

结果将存储在变量散列映射名称 - > MonsterObject。

The result would be stored in in a "variable hash" which maps Name -> MonsterObject.

Bob.jump()

将此解析为 [对象Bob] [方法跳转] [p1],[p2],...,[pn] ,在变量哈希中查找对象,然后:

Parse this to [object Bob] [method jump] [p1], [p2], ..., [pn], look up the object in the "variable hash" and then:


  1. 使用反射来调用方法,或者;

  2. 有一个地图(通过MonsterObject的方法检索)Name - > MethodEvaluatorObject(例如有 eval(Object ... params)方法),或者;

  3. c所有形式的方法 eval(String action,String [] ... parameters)并让它使用if-else-branch来做东西(注意在解析期间,参数(如果有的话)已经分离出来。)

  1. Use reflection to invoke a method, or;
  2. have a map (retrieved via a method of the MonsterObject) of Name -> MethodEvaluatorObject (e.g. has eval(Object ... params) method), or;
  3. call a method of the form eval(String action, String[] ... parameters) and have it use an if-else-branch to "do stuff" (note that the parameters, if any, are already separated out during the parsing).

LS Bob LS Monster 对如何实现前两个有很好的了解。

LS Bob and LS Monster rely a good bit on how the previous two are implemented.

虽然Java没有有了函数指针,可以通过使用具有给定接口的对象来模拟它们(也就是说,对象本身就像指针一样)。 Functional Java F / F2 /.../ F8 类试图统一处理泛型。但是,在Java中,通常会创建一个单独的一次性接口(或类),如 Runnable ,带有一个action方法,该方法被修改为接受适当的参数并返回适当的结果(例如MethodEvaluatorObjects或FactoryObjects)。

While Java does not have "function pointers", they can be emulated through the use of objects with a given interface (that is, the objects themselves function as the pointers). Functional Java has F/F2/.../F8 classes to attempt to handle this uniformly with generics. However, in Java there is usually a separate one-off interface (or class) created like Runnable with a single "action" method that is modified to accept the appropriate parameters and return the appropriate result (such as the MethodEvaluatorObjects or FactoryObjects).

如果有关于其中一个主题(反射,递归下降,匿名类型,[模拟]闭包等)的特定问题,请随时询问另一个具有特定焦点的问题。 (并且,与往常一样,研究中的尽职调查得到回报; - )

If there are any specific questions about one of the topics (reflection, recursive descent, anonymous types, [emulated] closures, etc.), then feel free to ask another SO question with a specific focus. (And, as always, due-diligence in research pays off ;-)

这篇关于在java中编写自定义语法解释器?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆