如何用BufferedReader将行存入ArrayList并执行文件中的简化编程语句?
实现简化编程语言解释器的分步指南
我来一步步帮你拆解这个需求的实现细节——从读取文件到解析执行,每个环节都给你具体的代码和思路。
一、先把文件行存入ArrayList
首先要做的是用BufferedReader把文件里的代码行读取到ArrayList中,这样后续执行时可以方便地通过行号跳转。这里要注意自动关闭流,还要过滤空行避免干扰:
import java.io.BufferedReader; import java.io.FileReader; import java.io.IOException; import java.util.ArrayList; public class SimpleInterpreter { private ArrayList<String> programLines = new ArrayList<>(); // 加载文件到ArrayList public void loadProgram(String filePath) throws IOException { try (BufferedReader br = new BufferedReader(new FileReader(filePath))) { String line; while ((line = br.readLine()) != null) { String trimmedLine = line.trim(); // 跳过空行,保留有效代码行 if (!trimmedLine.isEmpty()) { programLines.add(trimmedLine); } } } } }
二、分词处理:正确拆分语句
因为你的语句用空格分隔,但像GOTO 'x line'这种带单引号的内容不能被空格拆碎,所以需要写一个智能分词方法,处理引号内的内容:
import java.util.List; import java.util.ArrayList; // 分词方法:处理带引号的完整token private List<String> tokenizeLine(String line) { List<String> tokens = new ArrayList<>(); StringBuilder currentToken = new StringBuilder(); boolean inQuotes = false; for (char c : line.toCharArray()) { if (c == '\'') { // 切换引号状态,同时把引号加入token inQuotes = !inQuotes; currentToken.append(c); } else if (Character.isWhitespace(c) && !inQuotes) { // 非引号内的空格才作为分隔符 if (currentToken.length() > 0) { tokens.add(currentToken.toString()); currentToken.setLength(0); } } else { currentToken.append(c); } } // 加入最后一个token if (currentToken.length() > 0) { tokens.add(currentToken.toString()); } return tokens; }
比如输入IF count IS 0 THEN GOTO '5',会被拆成["IF", "count", "IS", "0", "THEN", "GOTO", "'5'"],完美保留引号内的行号。
三、核心执行逻辑
接下来要维护程序的执行状态:变量存储、当前行号,然后循环解析每行命令。这里用HashMap存变量,用switch处理不同命令:
import java.util.Map; import java.util.HashMap; private Map<String, Integer> variables = new HashMap<>(); private int currentLine = 0; // 执行加载好的程序 public void executeProgram() { while (currentLine < programLines.size()) { String line = programLines.get(currentLine); List<String> tokens = tokenizeLine(line); if (tokens.isEmpty()) { currentLine++; continue; } String command = tokens.get(0).toUpperCase(); switch (command) { case "PRINT": handlePrint(tokens); currentLine++; break; case "IF": boolean conditionMet = handleIf(tokens); if (conditionMet) { // 处理THEN后的命令(比如GOTO) List<String> thenTokens = tokens.subList(5, tokens.size()); handleThenCommand(thenTokens); } else { currentLine++; } break; case "GOTO": handleGoto(tokens); // GOTO后直接跳转,不用自增行号 break; case "END": return; // 终止程序 default: // 处理变量赋值 handleAssignment(tokens); currentLine++; break; } } }
各命令的具体实现
1. 变量赋值
处理variable = expression格式,这里简化支持数值和变量引用,复杂表达式可以后续扩展:
private void handleAssignment(List<String> tokens) { if (tokens.size() < 3 || !tokens.get(1).equals("=")) { System.err.println("语法错误:无效赋值,行号 " + (currentLine + 1)); currentLine++; return; } String varName = tokens.get(0); String expression = String.join(" ", tokens.subList(2, tokens.size())); try { // 先尝试解析为数字 int value = Integer.parseInt(expression); variables.put(varName, value); } catch (NumberFormatException e) { // 数字解析失败,尝试读取已有变量 if (variables.containsKey(expression)) { variables.put(varName, variables.get(expression)); } else { System.err.println("语法错误:无效表达式,行号 " + (currentLine + 1)); } } }
2. PRINT命令
打印指定变量的值:
private void handlePrint(List<String> tokens) { if (tokens.size() < 2) { System.err.println("语法错误:PRINT缺少变量,行号 " + (currentLine + 1)); return; } String varName = tokens.get(1); if (variables.containsKey(varName)) { System.out.println(variables.get(varName)); } else { System.err.println("错误:变量 " + varName + " 未定义,行号 " + (currentLine + 1)); } }
3. GOTO命令
跳转到指定行(注意文件行号是从1开始,ArrayList是0索引,要转成索引):
private void handleGoto(List<String> tokens) { if (tokens.size() < 2) { System.err.println("语法错误:GOTO缺少行号,行号 " + (currentLine + 1)); currentLine++; return; } String lineStr = tokens.get(1).replaceAll("'", ""); // 去掉单引号 try { int targetLine = Integer.parseInt(lineStr) - 1; // 转成ArrayList索引 if (targetLine >= 0 && targetLine < programLines.size()) { currentLine = targetLine; } else { System.err.println("错误:行号超出范围,行号 " + (currentLine + 1)); currentLine++; } } catch (NumberFormatException e) { System.err.println("语法错误:无效行号格式,行号 " + (currentLine + 1)); currentLine++; } }
4. IF命令
处理IF variable IS value THEN ...的条件判断:
private boolean handleIf(List<String> tokens) { if (tokens.size() < 5 || !tokens.get(2).equals("IS") || !tokens.get(4).equals("THEN")) { System.err.println("语法错误:无效IF语句,行号 " + (currentLine + 1)); return false; } String varName = tokens.get(1); String valueStr = tokens.get(3); if (!variables.containsKey(varName)) { System.err.println("错误:变量 " + varName + " 未定义,行号 " + (currentLine + 1)); return false; } try { int targetValue = Integer.parseInt(valueStr); return variables.get(varName) == targetValue; } catch (NumberFormatException e) { System.err.println("语法错误:无效数值,行号 " + (currentLine + 1)); return false; } } // 处理THEN后的命令 private void handleThenCommand(List<String> thenTokens) { String command = thenTokens.get(0).toUpperCase(); switch (command) { case "GOTO": handleGoto(thenTokens); break; default: System.err.println("错误:不支持的THEN命令,行号 " + (currentLine + 1)); currentLine++; break; } }
四、测试示例
假设你的测试文件program.txt内容如下:
count = 0 PRINT count IF count IS 0 THEN GOTO '4' count = 2 PRINT count count = 1 PRINT count END
在main方法中调用执行:
public static void main(String[] args) { SimpleInterpreter interpreter = new SimpleInterpreter(); try { interpreter.loadProgram("program.txt"); interpreter.executeProgram(); } catch (IOException e) { System.err.println("加载程序失败:" + e.getMessage()); } }
执行后会依次输出0、2、1,然后终止。
五、扩展建议
- 支持复杂表达式:可以用递归下降解析器实现加减乘除,或者借助Java的
ScriptEngineManager来计算表达式。 - 支持字符串变量:把
variables改成Map<String, Object>,处理字符串赋值和打印。 - 增强错误处理:添加更详细的语法错误提示,比如指出错误位置。
- 支持注释:读取文件时跳过以
//或#开头的行。
内容的提问来源于stack exchange,提问作者Daria Jones
相关产品推荐
相关产品推荐

