创建您自己的编程语言






4.87/5 (49投票s)
我出于好玩,并为了更好地理解以下问题,创建了自己的编程语言 Alef++:编程语言是什么?它是如何工作的?我能否创建自己的编程语言?
目录
- 什么是编程语言?
- 为什么我们需要另一种编程语言
- JavaCC
- Java 反射
- Eclipse 配置
- 编程语言示例(名称:St4tic)
- 6.0 - 语法
- 6.1 - 代码生成
- 6.2 - 使用反射
- 6.3 - 核心创建
- 6.4 - 构建解释器
- System:out:println(1 + var)
- 摘要
- 参考
1 - 什么是编程语言?
编程语言是一种人工语言,旨在表达计算机能够执行的计算。为什么?编程语言可用于创建控制机器行为的程序、精确表达算法,或者作为人机通信的一种方式,因为对于人类来说,输入一串串数字(如“1001011001...”)来创建像操作系统这样庞大复杂的算法或程序是非常困难的。
实际上,编程语言只是一套用于指示计算机执行特定任务的词汇和语法规则。术语“编程语言”通常指高级语言,如 C/C++、Perl、Java 和 Pascal 等。理论上,每种语言都有独特的关键字集(它能识别的词)和用于组织程序指令的特殊语法,但我们可以创建许多具有相同词汇和语法(如“Ruby”和“JRuby”或其他)的语言。
无论我们使用哪种语言,最终都需要将我们的程序转换为机器语言,以便计算机能够理解它。这有两种方法:
- 编译程序(如 C/C++)
- 解释程序(如 Perl)
在本文中,我们将使用第二种方法——“解释型语言”,例如 Perl 或 Ruby,并以“St4tic”为例进行演示。
2 - 为什么我们需要另一种编程语言
真的,我们还需要另一种吗?正如我们在维基百科列表中所见,我们已经有很多编程语言了。
但是,如何创建自己的编程语言呢?即使你有了这个想法,你可能会说:“创建编程语言对我来说是不可能的。我不是疯子,因为它非常困难!”是的,从头开始创建编程语言确实很难。你没有任何库或源代码可以参考。就像你在 M.U.G.E.N 中设置配置“Level : hard 8”和“Speed : fast 6”一样困难。
但是现在,我们有了 Yacc、JavaCC 等许多工具,可以为我们生成源代码。
我个人出于好玩,并为了更好地理解以下问题,创建了自己的编程语言 Alef++ [ http://alefpp.sourceforge.net/ ]:编程语言是什么?它是如何工作的?我能否创建自己的编程语言?我的语言与其他语言有什么区别?
如果你还没有气馁,那就继续阅读吧!
3 - JavaCC
“JavaCC (Java Compiler) 是 Java 编程语言的开源解析器生成器。JavaCC 类似于 Yacc,它为 EBNF 格式的正式语法生成解析器,但输出是 Java 源代码。然而,与 Yacc 不同的是,JavaCC 生成自顶向下的解析器,这将其限制在 LL(k) 类语法中(特别是,不能使用左递归)。与之配套的树构建器 JJTree 从底部向上构建树。”
简而言之,JavaCC 是一个用于转换和生成带有 Java 源代码的解析器的工具(类似于正则表达式),用于根据你定义的语法规则来检查源代码的语法。别担心,JavaCC 的语法类似于 Java 源代码,所以你可能需要熟悉 Java。
4 - Java 反射
Java 反射并不完全准确,但也许“镜像反射”更接近真相。我将解释原因。
实际上,Java 或 Ruby 的反射,.NET 的反射只不过是黑客行为,是在打破面向对象(OOP)的规则,就像镜像反射一样。
- 如果 Java 中我们无法访问其他类中的
private
成员和方法,那么使用 Java 反射,我们可以轻松做到。 - 如果我们想使用未导入到已编译代码中的外部库(“import something.*”),我们可以动态导入它。
- 如果我们想使用未在已编译代码中声明的类实例,我们可以动态创建类实例。
- 等等。
现在你知道为什么了吧!如果你了解 Java 持久化,它就可以从数据库读取并返回一个对象列表,每个对象都是数据库中的一行,而你只在一个类中定义了表结构,Java 持久化就完成了所有工作!所以你不会有“这是怎么工作的?”这样的疑问。
回到我们的游戏类比,现在团队已经组建完毕,我们的第二个玩家是 Java 反射,我们只需要选择一个战场,然后开始战斗!
5 - Eclipse 配置
Eclipse、Eclipse 和 Eclipse……为什么?如果你像我一样懒惰,创建一个文本文件并编写语法而没有任何语法高亮会令人沮丧,人们只希望它能像向导/安装程序一样完成——“下一步、下一步、完成!”
好的,让我们配置一个战场。如果你还没有 Eclipse,请在此处下载:这里。
接下来,请遵循 SourceForge 上的此设置,以在 Eclipse 中配置 JavaCC:SourceForge。
6 - 编程语言示例(名称:St4tic)
准备好了吗!?St4tic 是一个非常小的编程语言(微型编程语言),旨在让初学者易于理解,并且任何人都可以毫不费力地修改它,因为我创建它只是为了演示。
St4tic 可以执行算术运算(+、-、/、*)来处理整数。数学运算中有“IF”和“WHILE”两种条件,可以导入 Java 包,声明变量,并且仅执行公共静态方法,如 System.out.println
。这不算差吧?
在查看 St4tic 语法之前,请记住 St4tic 是一种解释型语言,如 Perl 或 Python,它可以从文件读取文本(源代码)并进行解析,然后创建对象树来解释它们(执行指令)。
开战!
示例文件文本
require java lang.
“I'm comment
def var = 13.
while var > 0 do
System:out:println( var ).
var = var – 1.
stop
6.0 - 语法
睁大你的眼睛,跟着我的步骤。还记得我怎么说我懒惰,我宁愿使用 JTB(Java Tree Builder)来毫不费力地构建或生成所有必需的源代码吗?这就是让这个向导如此不错的原因。
首先,我们创建一个 JTB 文件。你知道怎么做吗?理论上,你已经通过遵循这些步骤在 Eclipse 中安装了 JavaCC,所以应该没问题。如果你弄丢了,没关系,你还有 98 个积分,可以回去重新开始。
好了,现在我们将语法分为三大组。
- 选项
- 令牌
- 规则
如果你的 JDK 版本不支持模板(泛型),请尝试将你的项目 Java 编译兼容性设置为 1.5(Java 5)。
选项
options {
JDK_VERSION = "1.5";
STATIC = false;
}
我们使用 Java Development Kit 1.5(也称为 Java5,JDK_VERSION = “1.5”;)来进行 Java 5 的编译兼容性,以及用于解析器(STATIC=false;)的实例方法。
令牌
SKIP :
{
" "
| "\t"
| "\n"
| "\r"
| <"\"" (~["\n","\r"])* ("\n"|"\r"|"\r\n")>
}
用于跳过关键字、制表符和换行符或回车符之间的空格,最后一个是用于跳过注释,就像在 Java 中一样。
//comment here...
in St4tic comment for one line we use a (“) double quot:
[Code Block]
“Comment here...
TOKEN : /*
KEYWORDS */
{
< REQUERE: "require" >
| < IF: "if" >
| < WHILE: "while" >
| < DO: "do" >
| < STOP: "stop" >
| < DEF : "def" >
}
从初步的粗略观察可以推断,这是 St4tic 的保留关键字!St4tic 只有六个保留关键字。
“require
”关键字用于导入 Java 库,类似于 Java 中的“import
”。
require java lang.
这会导入所有“java.lang
”类。
def
关键字,类似于 Perl 中的 my
用于变量声明,我们必须使用 def
才能声明变量。
def myVar = 1.
def num13 = 13.
“if
”和“while
”是经典的 if
条件和 while
循环。
if 1 > 0 do
“do something …
stop
while 1 > 0 do
“repeat in infinite loop …
stop
TOKEN : /*
SYMBOLS */
{
< DOT: "." >
| < COLON: ":" >
| < EQ: "==" >
| < GT: ">" >
| < LT: "<" >
| < GE: ">=" >
| < LE: "<=" >
| < NE: "!=" >
| < PLUS: "+">
| < MINUS: "-" >
| < MUL: "*" >
| < DIV: "/" >
| < MOD: "%" >
| < ASSIGN: "=" >
}
这里,我们可以将符号分组为“数学运算符符号”(+,-,*,/,%)和“数学关系符号”(>,<,==,>=,<=,!=)。
TOKEN : /* LITERALS */
{
< INTEGER_LITERAL: ["1"-"9"] (["0"-"9"])* | "0" >
}
文字量,也许我们可以称之为“值”或“数据”(在 St4tic 中),例如。
def myAge = 24.
def var = 666.
if 11 > 10 do
…
stop
a values “24, 666, 11, 10” is checked or parsed as literals.
TOKEN : /* IDENTIFIERS */
{
< IDENTIFIER: <LETTER> (<LETTER>|<DIGIT>)* >
| < #LETTER: ["_","a"-"z","A"-"Z"] >
| < #DIGIT: ["0"-"9"] >
}
标识符与文字量一样,只是变量名的标识符,例如“myAge
”、“var
”等。现在我们已经完成了这些并不难的标记(=)),我们只需要想象一下关键字和符号,但我们可以使用其他编程语言中已有的关键字。
规则
这是一个巨大的挑战,因为我们需要一种新的编程语言,它具有不同的或革命性的组织结构,适用于解析,嗯……如果使用硬组织(语法)可能很难理解?我更喜欢使用简单的东西,比如 Pascal 或 Visual Basic。
开始之前
“如果规则是写‘1 + 1’,而你写了‘1 – 1’,JavaCC 就会抛出异常,因为解析器找不到‘1’后面跟着‘+’和‘1’,而是找到了‘-’代替‘+’,无法继续。”
这能理解吗?
void Start():{}
{
(
Require() "."
)+
(
StatementExpression()
)*
}
这是 St4tic 解析的入口点,没有它,解析器就无法启动。对于这个规则,必须指定一个“require”(如果你注意到“+”,表示一个或多个),之后是程序指令(注意“*”,表示零个或多个)。
void Require():{}
{
"require"
(
< IDENTIFIER >
)+
}
这里,包导入可以是“require
”后面的一个词,也可以是多个词,例如。
require java .
require java lang .
...
导入之后,我们可以写一个 St4tic 脚本,“语句表达式”。
void StatementExpression():{}
{
VariableDeclaration()
| LOOKAHEAD(2) VariableAssign()
| JavaStaticMethods()
| IfExpression()
| WhileExpression()
}
“语句表达式”是程序体或算法,可以包含许多变量声明、变量赋值、逻辑测试(if;while)或 Java 方法调用(记住在 St4tic 中只允许 public static
方法)。
void VariableDeclaration():{}
{
"def" VariableName() "=" MathExpression() "."
}
void VariableAssign():
{}
{
VariableName() "=" MathExpression() "."
}
正如你所看到的,变量声明和变量赋值是相同的,只是在声明时我们需要以“def
”开头来定义变量。
void JavaStaticMethods():{}
{
< IDENTIFIER > /* Class Name */
(
":" < IDENTIFIER > /* Member or Method */
)+
"(" MathExpression() ( "," MathExpression() )* ")" "."
}
就像它的名字一样,=) 调用的是静态方法,如下面的规则。
ClassName:[Method|Members]( number ) 例如“System:out:println(1)”,像 Java 吗?
是的,只需将“点[.]”更改为“冒号[:]”。
void IfExpression():{}
{
"if" RelationalExprssion() "do"
(
StatementExpression()
) *
"stop"
}
void WhileExpression():{}
{
"while" RelationalExprssion() "do"
(
StatementExpression()
) *
"stop"
}
简单易懂的“IF
”和“WHILE
”规则。最后,你可以看到完整的语法源代码,目前它只是一个空的解析器,用于检查语法而不解释它(没有结果)。在接下来的章节中,我们将为其添加解释器。
/*
using a Java Development Kit 1.5 or called Java5 (JDK_VERSION= "1.5")
for compilation compatibility with Java 5, and also an instance methods
for parser (STATIC=false).
*/
options {
JDK_VERSION = "1.5";
STATIC = false;
}
PARSER_BEGIN(St4tic)
package st4tic;
import st4tic.syntaxtree.*;
import st4tic.visitor.*;
public class St4tic
{
public static void main(String args[]) {
try {
Start start = new St4tic(new java.io.StringReader(
"require java lang.\n" +
"def var = 13.\n" +
"while var > 0 do\n" +
"System:out:println( var ).\n" +
"var = var - 1.\n" +
"stop.\n"
) ).Start();
start.accept( new DepthFirstVisitor () );
System.out.println("Right! no errors founded! =)");
} catch (Exception e) {
System.out.println("Oops.");
System.out.println(e.getMessage());
}
}
}
PARSER_END(St4tic)
/*
for skipping a space between keyword, tab and new lines
or returns, but last is for skipping comments, like in Java
//comment here...
in St4tic comment is :
"Comment here...
*/
SKIP :
{
" "
| "\t"
| "\n"
| "\r"
| <"\"" (~["\n","\r"])* ("\n"|"\r"|"\r\n")>
}
/*
This can resume from first look, this a St4tic reserved keyword!
Right St4tic has only six reserved keywords.
“require” keyword used for Java library importation like “import” in Java :
require java lang.
This import all “java.lang” class.
“def” keyword this like “my” in Perl for
variable declaration, and can't declare any variable without using “def”.
def myVar = 1.
def num13 = 13.
“if” and “while” this is a classical if-condition and while-loop.
if 1 > 0 do
“do something …
stop
while 1 > 0 do
“repeat in infinite loop …
stop
*/
TOKEN : /*
KEYWORDS */
{
< REQUERE: "require" >
| < IF: "if" >
| < WHILE: "while" >
| < DO: "do" >
| < STOP: "stop" >
| < DEF : "def" >
}
/*
Here, we can grouping symbols to “Math Operation Symbols” (+,-,*,/,%)
and “Math Relational Symbols”
(>,<,==,>=,<=,!=).
*/
TOKEN : /* SYMBOLS */
{
< DOT: "." >
| < COLON: ":" >
| < EQ: "==" >
| < GT: ">" >
| < LT: "<" >
| < GE: ">=" >
| < LE: "<=" >
| < NE: "!=" >
| < PLUS: "+">
| < MINUS: "-" >
| < MUL: "*" >
| < DIV: "/" >
| < MOD: "%" >
| < ASSIGN: "=" >
}
/*
Literals, maybe can said “value” or “data” (in St4tic) example:
def myAge = 24.
def var = 666.
if 11 > 10 do
…
stop
a values “24, 666, 11, 10” is checked or parsed as literals.
*/
TOKEN : /* LITERALS */
{
< INTEGER_LITERAL: ["1"-"9"] (["0"-"9"])* | "0" >
}
TOKEN : /* IDENTIFIERS */
{
< IDENTIFIER: <LETTER> (<LETTER>|<DIGIT>)* >
| < #LETTER: ["_","a"-"z","A"-"Z"] >
| < #DIGIT: ["0"-"9"] >
}
/* GRAMMAR start here */
/*
This is an enter point for St4tic parsing
without it, a parser can't started,
for this rule we need mandatory to specifying
a “require” (if you notice “+”, one or many)
and after it a program instructions (notice
“*”, no-one or many):
*/
void Start():{}
{
(
Require() "."
)+
(
StatementExpression()
)*
}
/*
Here for packages importation can be one word after “require” or many like :
require java .
require java lang .
...
*/
void Require():{}
{
"require"
(
< IDENTIFIER >
)+
}
/* Simple Math Operations */
void MathExpression():{ }
{
AdditiveExpression()
}
void AdditiveExpression():{}
{
MultiplicativeExpression() ( ( "+" | "-" )
MultiplicativeExpression() )*
}
void MultiplicativeExpression():{}
{
UnaryExpression() ( ( "*" | "/" | "%" ) UnaryExpression() )*
}
void UnaryExpression():{}
{
"(" MathExpression() ")" | < INTEGER_LITERAL > | VariableName()
}
/* Start Simple Relational Test */
void RelationalExprssion():{}
{
RelationalEqualityExpression()
}
void RelationalEqualityExpression():{}
{
RelationalGreaterExpression()
(
(
"==" | "!="
)
RelationalGreaterExpression()
)*
}
void RelationalGreaterExpression():{}
{
RelationalLessExpression()
(
(
">" | ">="
)
RelationalLessExpression()
)*
}
void RelationalLessExpression():{}
{
UnaryRelational()
(
(
"<" | "<="
)
UnaryRelational()
)*
}
void UnaryRelational():{}
{
< INTEGER_LITERAL > |
VariableName()
}
/* End Simple Relational Test */
/*
"if" expression is a classical test if true do something
like in :
-----------------------------------------------
Java | VB
-----------------------------------------------
if( 1 > 0 ) | If 1 > 0
Then
{ | ...
... | End If
} |
|
Here is :
if 1 > 0 do
...
stop
"stop" is end of if block
*/
void IfExpression():{}
{
"if" RelationalExprssion() "do"
(
StatementExpression()
) *
"stop"
}
/*
"while" expression is a classical test while true repeat something
like in :
-----------------------------------------------
Java | VB
-----------------------------------------------
while( 1 > 0 ) | While 1 > 0
{ | ...
... | End While
} |
|
Here is :
while 1 > 0 do
...
stop
"stop" is end of while block
*/
void WhileExpression():{}
{
"while" RelationalExprssion() "do"
(
StatementExpression()
) *
"stop"
}
/*
Variable declaration expression is a syntax of variables
declaration in St4tic
in Perl we declare variables by using keyword
"my"
or VB by using "dim", St4tic use "def" for definition
or define it.
like def var = 1.
*/
void VariableDeclaration():{}
{
"def" VariableName() "=" MathExpression() "."
}
void VariableAssign():
{
}
{
VariableName() "=" MathExpression() "."
}
void VariableName():{}
{
< IDENTIFIER >
}
void JavaStaticMethods():{}
{
< IDENTIFIER > /* Class Name */
(
":" < IDENTIFIER > /* Member or Method */
)+
"(" MathExpression() ( "," MathExpression() )* ")" "."
}
/*
“statement expression” is program body oralgorithm can content
a many variables declaration, variables assign, logical tests (if;while)
or Java methods calling (remember in St4tic just public static methods).
*/
void StatementExpression():{}
{
VariableDeclaration()
| LOOKAHEAD(2) VariableAssign()
| JavaStaticMethods()
| IfExpression()
| WhileExpression()
}
6.1 – 代码生成
这很简单。你只需在上下文菜单中点击“Compile with JavaCC”,或者直接保存文件(如果你启用了自动编译)。结果如下。
也许如果你复制粘贴它,你会因为 JTB 文件位于不同的包中而遇到一些小错误。
如果必须这样做,尝试更改 JTB 文件中的包名,并在秘密地方。
“Project-Properties > JavaCC Options > Tab JTB Option > in p (default) = your new package name”,我希望现在我不用为你的错误负责了,我给了你一个秘密解决方案。
如果你在这里迷路了,别担心。你还有很多积分可以重新开始,也许现在是 97 个积分了!
要尝试解析器,你只需运行 St4tic.java 文件,结果是:
“正确!没有发现错误!”
要编辑或测试其他代码,请在此处自行编辑。
Start start = new St4tic(new java.io.StringReader(
"require java lang.\n" +
"def var = 13.\n" +
"while var > 0 do\n" +
"System:out:println( var ).\n" +
"var = var - 1.\n" +
"stop.\n"
) ).Start();
6.2 – 使用反射
为了使用 Java 反射,我们需要创建一个小类来完成它。
- static method full-identifier : parameters (string : class-name ) : return string
- static method exists-field : parameters ( object : class-instance, string : field-name) : return boolean
- static method get-field-object : parameters ( object : class-instance, string : field-name) : return object
- static method exists-method : parameters( object : class-instance, string : method-name, st4tic-value[] : args) : return boolean
- static method invoke-static-method : parameters ( object : class-instance, string : method-name, st4tic-value[] : args ) : return object
- static method push-package : parameters( string : package-name) : return void
- static method make-object : parameters( string : class-name) :return class
最复杂的方法是调用 static
方法(或所有方法),因为在这一步我们需要选择正确的参数类型,而编译器可以自动转换 Java 原生对象(integer
到 double
或 long
到 float
等)。
也许你没有看到真正的问题,但想象一下如果你有
- class X;
- 和 class Z extends X;
- 并且你有一个方法
myMethod
( X x );
如果你在方法 myMethod
中传递一个类 Z 的实例并进行编译,你的代码将毫无错误地通过。
但是,如果你使用反射来做到这一点,那么所有神圣的错误就会显现出来。例如,“方法不存在”或“对象类型错误”,因为反射中没有自动类型转换。你需要自己进行。
好的,在我们的例子中,不用担心,因为我们有一个简单的方法。
@SuppressWarnings("unchecked")
public static Object invokeStaticSubroutine(
Object classInstance, String methodName, St4ticValue ... args){
//~ Public Invocation
try{
Class clazz = classInstance instanceof Class ?
(Class)classInstance : classInstance.getClass();
// Invoke Subroutine with parameters
if( args != null ){
//~ Get Static Method
LinkedList<Class> params = new LinkedList<Class>();
for( St4ticValue arg : args ){
params.add( arg.getType() );
}
Method method = clazz.getMethod(methodName,
params.toArray(new Class[]{}));
//~ Invoke Static Method
LinkedList<Object> values = new LinkedList<Object>();
for( St4ticValue arg : args ){
values.add(arg.getValue());
}
return method.invoke(classInstance,
values.toArray(new Object[]{}));
}
// Invoke Subroutine without parameters
else{
Method method = clazz.getMethod(methodName, new Class[]{});
return method.invoke(classInstance, new Object[]{});
}
} catch (SecurityException se) {
} catch (NoSuchMethodException nsme) {
} catch (IllegalArgumentException iae) {
} catch (IllegalAccessException iae) {
} catch (InvocationTargetException ate) {
}
return null;
}
6.3 - 核心创建
Core 包是 St4tic 数据操作的核心,我们只有四个类。
这是一个非常简单的类,你可以在源代码中看到它们。只有 getter、setter 和查找子节点。
6.4 - 构建解释器
为了使解释器更简单,我将其分到一个名为“interpreter”的单独包中,并创建一个包含所有必需方法的接口,称为“Interpret
”,最后我在一个名为“Interpreter
”的类中实现了它。
接口“Interpret
”中的方法是从接口 st4tic.visitor.Visitor
复制的,并改变了它的签名,就像 Alef++ 一样。
从 public void visit(Require n);
到 public Object visit(Require node, St4ticScope scope, Object ... objects);
只有 visit(Start node)
没有改变,因为这个方法是 St4tic 解释器的入口或起点。
public Object visit(Start node) throws Exception {
/*
* first setup of imported packages and add it to St4ticReflection
* class for using it with reflection full class identifier like :
* "java.lang.System"
* the elements f0 ... fn has generated automatically by JTB =)
*/
Enumeration importedPackagesEnum = node.f0.elements();
while( importedPackagesEnum.hasMoreElements() )
{
// adding required packages
NodeSequence ns = (NodeSequence) importedPackagesEnum.nextElement();
St4ticReflection.pushPackage( this.visit
( (Require) ns.elementAt( 0 ), null).toString() );
}
/*
*~ Now! press start to play, maybe if you not lost all your credits
*~ in article and configurations, you lost them all here =)
*
* okay, after importation we start interpreting a source code
*
* testing if exists a code after "require
* require java lang.
* System:ou:println( 1 ). "first statement
* System:ou:println( 2 ). "second statement
*/
if( node.f1.size() > 0 )
{
//~ creating of parent scope
St4ticScope parent = new St4ticScope( null );
Enumeration statement = node.f1.elements();
while( statement.hasMoreElements() )
{
this.visit
( (StatementExpression)statement.nextElement() , parent);
}
}
return null;
}
第二个重要方法是变量声明及其生命周期,如果作用域被销毁,所有子节点也将丢失,而无需使用 GC。
public Object visit(VariableDeclaration node, St4ticScope scope,
Object... objects) throws Exception {
/*
* we ignore "def", "=" and "." keywords
*/
St4ticVariable var = new St4ticVariable();
var.setVariableName( this.visit( node.f1 , scope, objects).toString() ) ;
var.setVariableValue( (St4ticValue) this.visit(node.f3, scope, objects) );
/*
* we add a variable to current scopefor variable life cycle
* and visibility.
*/
scope.pushChild( var.getVariableName() , var );
return null;
}
最后,还有一个用于调用 Java static
方法的方法。
public Object visit(JavaStaticMethods node, St4ticScope scope,
Object... objects) throws Exception {
/*
* Okay, firstly we need to test existence of class and fields or method
* after, we get a value for arguments, finally we invoke a static Java Method
*/
//f0 is class name
String identifier = St4ticReflection.fullIdentifier( node.f0.tokenImage ) ;
if( identifier != null )
{
// making a class object
Object currentObject = St4ticReflection.makeObject ( identifier );
if( currentObject != null ){
Enumeration e = node.f1.elements();
//~ getting a last field object
while( e.hasMoreElements() )
{
NodeSequence ns = (NodeSequence) e.nextElement();
if( St4ticReflection.existsField
( currentObject , ns.elementAt( 1 ).toString() ) )
{
currentObject = St4ticReflection.getFieldObject(
currentObject , ns.elementAt( 1 ).toString() );
}
else
{
LinkedList<St4ticValue> params =
new LinkedList<St4ticValue>();
params.add( (St4ticValue) this.visit
(node.f3, scope, objects) );
Enumeration eVal = node.f4.elements();
while( eVal.hasMoreElements() )
{
NodeSequence nsVal =
(NodeSequence) eVal.nextElement();
params.add( (St4ticValue) this.visit(
(MathExpression) nsVal.elementAt(1) ,
scope,
objects) );
}
//~ test and invoking
if( St4ticReflection.existsSubroutine( currentObject ,
ns.elementAt( 1 ).toString() , params.toArray(
new St4ticValue[]{}
)) )
{
return St4ticReflection.invokeStaticSubroutine(
currentObject ,
ns.elementAt( 1 ).toString() ,
params.toArray( new St4ticValue[]{}
)) ;
}
break;
}
}
}
}
return null;
}
7 - System:out:println( 1 + var ).
现在是检验真理的时刻了。去 Eclipse 或你最喜欢的文本编辑器,创建一个名为“my-first-programming-language.st4”的文本文件,然后在第一行输入:
require java lang .
第二行:
def var = 2 .
最后一行:
System:out:println( 1 + var ) .
转到 Eclipse 的“Run...”属性,然后在参数中添加“my-first-programming-language.st4”,最后按“Run”;或者,如果你使用二进制文件(JAR 文件),你可以在控制台中输入:
$: java -jar st4tic.jar my-first-programming-language.st4
然后你会得到一个非常不错的输出:
3
恭喜!你赢了,感谢你的参与,本文结束。
8 - 总结
我想写一篇有趣且具有教育意义的文章,因为这个话题非常广泛和庞大。如果你阅读经典的学术文章,它们可能会令人气馁,变得非常困难。所以现在我希望你对 JavaCC 和 Java 反射有所了解。
- JavaCC:一个类似于 Yacc 的工具,用于从语法生成 Java 源代码的解析器。
- Java 反射:一个用于动态访问和操作 Java 对象的库。
- 关键字:你可以使用任何语言作为关键字(阿拉伯语、俄语等...)。
希望你喜欢这篇文章。请提出你的建议和反馈,以便进一步改进。再次感谢阅读。