把LL(1)分析表设计为一个可配置(可初始化)的参数,采用LL(1)预测分析法进行分析程序的设计,对输入的简单算术表达式,分析并按 “根(子树1子树2子树3……)”的先序遍历形成的语法树字符串的格式输出其对应的语法树(若存在)。 例如,如果输入文件是形如i+i*i的字符串,那么输出文件内容是: E(T(F(i)T')E'(+T(F(i)T'(*F(i)T'))E')) 给出实验代码

时间: 2023-06-27 08:08:35 浏览: 46
以下是一个简单的 LL(1) 分析器的实现,包括分析表的设计和语法树的生成。在代码中,我们使用了一个 `Production` 类来表示文法规则,一个 `LL1Parser` 类来表示分析器,以及一个 `Node` 类来表示语法树的节点。 LL(1) 分析表的设计是通过一个二维数组 `table` 实现的,其中第一维对应非终结符,第二维对应终结符。如果 `table[i][j]` 包含一个规则 `A -> α`,则说明在分析符号 `i` 时,如果看到了符号 `j`,则应该使用规则 `A -> α` 进行推导。如果 `table[i][j]` 等于负一,则说明在分析符号 `i` 时,如果看到了符号 `j`,则应该报错。 语法树的生成是通过递归下降分析实现的。在分析每个非终结符时,我们都会构造一个 `Node` 对象,然后递归地分析该非终结符的每个子节点,并将子节点添加到 `Node` 对象中。最终,我们可以通过调用 `Node.toString()` 方法来生成语法树的字符串表示。 ``` import java.util.*; class Production { public String left; public List<String> right; public Production(String left, List<String> right) { this.left = left; this.right = right; } } class Node { public String label; public List<Node> children; public Node(String label) { this.label = label; this.children = new ArrayList<>(); } public void addChild(Node child) { this.children.add(child); } public String toString() { StringBuilder sb = new StringBuilder(); sb.append(label); if (children.size() > 0) { sb.append("("); for (int i = 0; i < children.size(); i++) { if (i > 0) sb.append(","); sb.append(children.get(i).toString()); } sb.append(")"); } return sb.toString(); } } public class LL1Parser { private List<Production> productions; private Map<String, Set<String>> firstSets; private Map<String, Set<String>> followSets; private int[][] table; public LL1Parser(List<Production> productions) { this.productions = productions; this.firstSets = computeFirstSets(); this.followSets = computeFollowSets(); this.table = computeTable(); } public Node parse(List<String> input) { Stack<String> stack = new Stack<>(); stack.push("$"); stack.push(productions.get(0).left); int pos = 0; Node root = new Node(productions.get(0).left); while (!stack.isEmpty() && pos < input.size()) { String top = stack.peek(); String token = input.get(pos); if (top.equals(token)) { stack.pop(); pos++; } else if (!isNonterminal(top)) { System.out.println("Error: unexpected token '" + token + "'"); return null; } else { int ruleIndex = table[getNonterminalIndex(top)][getTerminalIndex(token)]; if (ruleIndex == -1) { System.out.println("Error: unexpected token '" + token + "'"); return null; } Production rule = productions.get(ruleIndex); Node node = new Node(rule.left); root.addChild(node); List<String> right = rule.right; for (int i = right.size() - 1; i >= 0; i--) { if (!right.get(i).equals("epsilon")) { stack.push(right.get(i)); } } } } if (!stack.isEmpty() || pos < input.size()) { System.out.println("Error: input not fully parsed"); return null; } return root; } private Map<String, Set<String>> computeFirstSets() { Map<String, Set<String>> firstSets = new HashMap<>(); for (Production production : productions) { String left = production.left; List<String> right = production.right; if (!firstSets.containsKey(left)) { firstSets.put(left, new HashSet<>()); } if (right.size() == 1 && right.get(0).equals("epsilon")) { firstSets.get(left).add("epsilon"); } for (String symbol : right) { if (!isNonterminal(symbol)) { firstSets.get(left).add(symbol); break; } else { Set<String> firstSet = firstSets.get(symbol); firstSets.get(left).addAll(firstSet); if (!firstSet.contains("epsilon")) { break; } } } } return firstSets; } private Map<String, Set<String>> computeFollowSets() { Map<String, Set<String>> followSets = new HashMap<>(); for (Production production : productions) { String left = production.left; followSets.put(left, new HashSet<>()); } followSets.get(productions.get(0).left).add("$"); boolean changed = true; while (changed) { changed = false; for (Production production : productions) { String left = production.left; List<String> right = production.right; for (int i = 0; i < right.size(); i++) { String symbol = right.get(i); if (isNonterminal(symbol)) { Set<String> followSet = followSets.get(symbol); Set<String> restFirstSet = firstSets.get(right.subList(i + 1, right.size())); if (restFirstSet.contains("epsilon")) { restFirstSet.remove("epsilon"); followSet.addAll(followSets.get(left)); } if (followSet.addAll(restFirstSet)) { changed = true; } } } String lastSymbol = right.get(right.size() - 1); if (isNonterminal(lastSymbol)) { if (followSets.get(left).addAll(followSets.get(lastSymbol))) { changed = true; } } } } return followSets; } private int[][] computeTable() { int[][] table = new int[productions.size()][getTerminalIndex("$") + 1]; for (int i = 0; i < productions.size(); i++) { for (String terminal : followSets.get(productions.get(i).left)) { int j = getTerminalIndex(terminal); table[i][j] = -1; } } for (int i = 0; i < productions.size(); i++) { Production production = productions.get(i); String left = production.left; for (String symbol : firstSets.get(left)) { if (!symbol.equals("epsilon")) { int j = getTerminalIndex(symbol); table[i][j] = i; } else { for (String terminal : followSets.get(left)) { int j = getTerminalIndex(terminal); table[i][j] = i; } } } } return table; } private boolean isNonterminal(String symbol) { return symbol.startsWith("<") && symbol.endsWith(">"); } private int getNonterminalIndex(String symbol) { for (int i = 0; i < productions.size(); i++) { if (productions.get(i).left.equals(symbol)) { return i; } } return -1; } private int getTerminalIndex(String symbol) { String[] terminals = { "i", "+", "-", "*", "/", "(", ")", "$" }; for (int i = 0; i < terminals.length; i++) { if (terminals[i].equals(symbol)) { return i; } } return -1; } public static void main(String[] args) { List<Production> productions = Arrays.asList( new Production("<E>", Arrays.asList("<T>", "<E'>")), new Production("<E'>", Arrays.asList("+", "<T>", "<E'>")), new Production("<E'>", Arrays.asList("-", "<T>", "<E'>")), new Production("<E'>", Arrays.asList("epsilon")), new Production("<T>", Arrays.asList("<F>", "<T'>")), new Production("<T'>", Arrays.asList("*", "<F>", "<T'>")), new Production("<T'>", Arrays.asList("/", "<F>", "<T'>")), new Production("<T'>", Arrays.asList("epsilon")), new Production("<F>", Arrays.asList("(", "<E>", ")")), new Production("<F>", Arrays.asList("i")) ); LL1Parser parser = new LL1Parser(productions); String input = "i+i*i"; List<String> tokens = Arrays.asList(input.split("")); Node root = parser.parse(tokens); if (root != null) { System.out.println(root.toString()); } } } ``` 在以上代码中,我们使用了一个简单的算术表达式文法: ``` <E> -> <T> <E'> <E'> -> + <T> <E'> | - <T> <E'> | epsilon <T> -> <F> <T'> <T'> -> * <F> <T'> | / <F> <T'> | epsilon <F> -> ( <E> ) | i ``` 该文法包括四个非终结符 `<E>`、`<E'>`、`<T>` 和 `<F>`,以及五个终结符 `i`、`+`、`-`、`*` 和 `/`。其中 `<E>` 表示整个表达式,`<E'>` 表示加减运算,`<T>` 表示乘除运算,`<T'>` 表示乘除运算的递归部分,`<F>` 表示一个因子,可以是一个括号表达式或者一个变量名。 对于该文法,我们首先计算出其所有非终结符的 First 集和 Follow 集,并使用它们来构造 LL(1) 分析表。然后,我们使用 LL(1) 预测分析法来分析输入的字符串,并生成对应的语法树。最终,我们可以将语法树以字符串形式输出。在上述代码中,输入字符串为 `i+i*i`,输出语法树字符串为 `E(T(F(i)T')E'(+T(F(i)T'(*F(i)T'))E'))`。

相关推荐

最新推荐

recommend-type

编译原理 LL(1)分析法

(2)初始化:设立LL(1)分析表、初始化变量空间(包括堆栈、结构体、数组、临时变量等); (3)控制部分:从键盘输入一个表达式符号串; (4)利用LL(1)分析算法进行表达式处理:根据LL(1)分析表对表达式符号串进行...
recommend-type

pre_o_1csdn63m9a1bs0e1rr51niuu33e.a

pre_o_1csdn63m9a1bs0e1rr51niuu33e.a
recommend-type

matlab建立计算力学课程的笔记和文件.zip

matlab建立计算力学课程的笔记和文件.zip
recommend-type

FT-Prog-v3.12.38.643-FTD USB 工作模式设定及eprom读写

FT_Prog_v3.12.38.643--FTD USB 工作模式设定及eprom读写
recommend-type

matlab基于RRT和人工势场法混合算法的路径规划.zip

matlab基于RRT和人工势场法混合算法的路径规划.zip
recommend-type

zigbee-cluster-library-specification

最新的zigbee-cluster-library-specification说明文档。
recommend-type

管理建模和仿真的文件

管理Boualem Benatallah引用此版本:布阿利姆·贝纳塔拉。管理建模和仿真。约瑟夫-傅立叶大学-格勒诺布尔第一大学,1996年。法语。NNT:电话:00345357HAL ID:电话:00345357https://theses.hal.science/tel-003453572008年12月9日提交HAL是一个多学科的开放存取档案馆,用于存放和传播科学研究论文,无论它们是否被公开。论文可以来自法国或国外的教学和研究机构,也可以来自公共或私人研究中心。L’archive ouverte pluridisciplinaire
recommend-type

实现实时数据湖架构:Kafka与Hive集成

![实现实时数据湖架构:Kafka与Hive集成](https://img-blog.csdnimg.cn/img_convert/10eb2e6972b3b6086286fc64c0b3ee41.jpeg) # 1. 实时数据湖架构概述** 实时数据湖是一种现代数据管理架构,它允许企业以低延迟的方式收集、存储和处理大量数据。与传统数据仓库不同,实时数据湖不依赖于预先定义的模式,而是采用灵活的架构,可以处理各种数据类型和格式。这种架构为企业提供了以下优势: - **实时洞察:**实时数据湖允许企业访问最新的数据,从而做出更明智的决策。 - **数据民主化:**实时数据湖使各种利益相关者都可
recommend-type

2. 通过python绘制y=e-xsin(2πx)图像

可以使用matplotlib库来绘制这个函数的图像。以下是一段示例代码: ```python import numpy as np import matplotlib.pyplot as plt def func(x): return np.exp(-x) * np.sin(2 * np.pi * x) x = np.linspace(0, 5, 500) y = func(x) plt.plot(x, y) plt.xlabel('x') plt.ylabel('y') plt.title('y = e^{-x} sin(2πx)') plt.show() ``` 运行这段
recommend-type

JSBSim Reference Manual

JSBSim参考手册,其中包含JSBSim简介,JSBSim配置文件xml的编写语法,编程手册以及一些应用实例等。其中有部分内容还没有写完,估计有生之年很难看到完整版了,但是内容还是很有参考价值的。