java - 使用多个数组列表或带有 stringtokenizer 的数组在 java 中编写解释器

标签 java arrays arraylist stringtokenizer

我目前正在做一项作业,创建一个带有 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 ;其他成员建议我使用 Map) 来删除关键字标记并执行。设置第二个临时 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);
                            }

                        }

最佳答案

因此,如果我这样做,我会使用更多面向对象的方法。

如果您为所有实现相同接口(interface)的每个命令创建一个“类”怎么办?该接口(interface)(我们称之为 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

这些命令对象必须共享一组变量——创建一个单例可以工作,但有点反模式,我建议您将它们作为 HashMap (上面的variableHash)传递。

这种方法的好处是添加新的“命令”非常简单并且大部分是独立的。

编辑(回复评论):

您要做的第一件事是创建一个 HashMap 并“安装”每个命令。例如:(仍然是伪代码,我假设您更喜欢自己完成作业)

map = new HashMap<String, CommandObject>

然后将每个类的实例添加到 map 中:

map.put("LET", new LetCommand());
map.put("INTEGER", new Integercommand());

其中右侧类实现“CommandObject”接口(interface)。

请注意,由于每个 CommandObject 都是一个实例,每次找到该关键字时都会重复使用,因此您可能不应该存储任何状态(不要有任何实例变量),这意味着您的 CommandObject 将只需要一个方法,类似:

execute(String commandLine, HashMap variables);

这可能是最简单的方法(我根据最初的建议编辑了上面的文本以反射(reflect)这一点)。

如果这个解析器变得更复杂,那么向“CommandObject”添加更多功能是完全有效的,只要您有一个 Reset() 方法,您就可以保留状态变量(我最初的建议,但对于什么来说似乎过于复杂)你正在做的事)

请注意,关键字到命令对象的映射可以用反射代替,但不要尝试在学校作业中这样做,反射的复杂性使其不值得您花时间,并且您可能会被降级,因为老师不明白。我实现了一个这样的系统,其中每个关键字都链接到一个测试(允许您链接测试、循环测试,甚至定义和携带传递到这些测试并由这些测试操作的变量——在这种情况下,反射是值得的,因为添加一个新测试不需要更新缓存)

关于java - 使用多个数组列表或带有 stringtokenizer 的数组在 java 中编写解释器,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8807778/

相关文章:

java - 如何在Java中为ArrayList添加大小

Java : Object access with private fields

java - 查找 map 中每个键的平均对象字段

java - arraylist get 方法有问题

java - 循环不捕获重复项并在 Android(Java) 中删除它们

java - 使用 Swing 组件作为内容的自定义 Java 工具提示未显示

php - 将日期数组拆分为连续的日期数组

c# - ToArray() 方法将所有实例克隆为最后一个

javascript - Googlemaps v3 地面覆盖循环

java - 为什么 FileChannel.tryLock 不阻止跨多个进程的访问?