我目前正在分配一个工作,以创建一个具有8个关键字(不区分大小写)和4个算术运算符的基本解释器。用这种语言编写的程序看起来像这样(实际上类似于BASIC的语法):
# (signals start of a comment line)
LET
INTEGER
STRING
PRINT
END
因此,无论如何,我目前正在尝试标记要解析的文本行。我已经将所有文本行解析为ArrayList并标记了字符串。现在我的当前问题是,StringTokenizer预先对所有字符串进行标记化(我正在使用空格作为分隔符),当我需要它来查找我的关键字时,该关键字始终是代码行开头的第一个单词,并且某些问题使这种情况不受欢迎;我认为使用String.split()也不会有太大帮助。
我打算这样做的方法是让解释器找到我的第一个标记,然后通过HashMap从那里到达适当的类(请参见我之前关于在我的解释器中使用switch语句的问题:Switch or if statements in writing an interpreter in java;其他成员建议我使用地图)删除关键字令牌并执行。设置第二个临时ArrayList或专门用于保存变量的数组是一个好主意吗?我不希望它过于复杂。
在此先感谢您的建议。
public static void main (String[]args)
{
try
{
ArrayList<String> demo= new ArrayList <String>();
FileReader fr= new FileReader("hi.tpl");
BufferedReader reader= new BufferedReader(fr);
String line;
while ((line=reader.readLine()) !=null)//read file line by line
{
//Add to ArrayList
demo.add(line);
}
reader.close();
boolean checkEnd= demo.contains("END");//check if arraylist contains END statement
if(line=null && checkEnd== false)
{
System.out.println(" Unexpected end of file: no END statement");
System.exit(0);
}
ListIterator<String>arrayListIt=demo.listIterator();
while (arrayListIt.hasNext())
for (String file: demo)// begin interpreting the program file here
{
StringTokenizer st=new StringTokenizer(file);
while(st.hasMoreTokens())
{
int firstWord=file.indexOf();
String command = file;
if (firstSpace > 0)
{
command= file.substring(0, firstSpace);
}
TokenHandler tokens= tokens.get(command.toUpperCase());
if(tokens != null)
{
tokens.execute(file);
}
}
最佳答案
因此,如果我这样做了,我将使用更多面向对象的方法。
如果为所有都实现相同接口的命令创建一个“类”怎么办?接口-称之为CommandObject将具有execute()方法。
然后,您可以使用预加载的映射,该映射将“ Let”之类的命令映射到Let类的实例。
现在您的主循环变成这样(伪):
for(line:lineList)
CommandObject commandObject=map.get(line.split()[0]) // do this more clearly
commandObject.execute(variableHash, line) // Parse and execute the line
这些命令对象必须共享一组变量-使单例可以工作,但是有点反模式,我建议您将其作为哈希映射(上面的variableHash)传递。
这种方法的好处是,添加新的“命令”非常简单,而且大多是独立的。
编辑(评论):
您要做的第一件事是创建一个哈希表并“安装”每个命令。例如:(仍然是伪代码,我想您希望自己进行分配)
map = new HashMap<String, CommandObject>
然后将每个类的实例添加到地图:
map.put("LET", new LetCommand());
map.put("INTEGER", new Integercommand());
右侧的类在其中实现了“ CommandObject”接口。
请注意,由于每个CommandObject都是一个实例,每次找到该关键字都会被重复使用,因此您可能不应该存储ANY状态(没有任何实例变量),这意味着CommandObject只需要一个方法,例如:
execute(String commandLine, HashMap variables);
这可能是最简单的方法(我从最初的建议中编辑了上面的文本以反映这一点)。
如果此解析器变得更加复杂,那么向“ CommandObject”添加更多功能将是完全有效的,只要您具有reset()方法即可保留状态变量(我的原始建议,但对于您正在做的事情来说似乎过于复杂)
请注意,关键字到命令对象的映射可以用反射代替,但不要在学校布置作业时这样做,反射的复杂性使其不值得您花费时间,并且很可能会因为老师没有将其降级而降级。不明白。我实现了这样的系统,其中每个链接到测试的关键字(允许您链接测试,循环测试,甚至定义和携带这些测试传递和操作的变量,在这种情况下,反射是值得的,因为添加一个新测试不需要更新缓存)