编译原理 实验二 简单计算器的设计与实现
Posted _DiMinisH
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了编译原理 实验二 简单计算器的设计与实现相关的知识,希望对你有一定的参考价值。
实验二 简单计算器的设计与实现
一、实验目的
综合运行词法分析器、语法分析器等原理实现一个具有加、乘功能的简单计算器,该计算器满足乘法优先级高于加法优先级,且仅处理非负整数。
二、实验内容
1. 对输入的符号串首先进行词法分析,提取操作数及操作符,以输出的单词符号为输入进行语法分析。
2. 要求以算符优先分析的方法完成语法分析工作,识别输入串是否是文法描述语言的句子。
3. 对句子进行求值,求值方式可以是遍历语法树或者是建立一个逆波兰式,对逆波兰式进行求值。
三、实验要求
1. 从文件读入算术表达式/或者从终端输入;
2. 词法分析,用二元组表示输出结果;
3. 语法分析,算符优先分析方法进行自下而上的语法分析并构造语法树;
4. 识别出的句子进行求值,遍历语法树求值或者先建立逆波兰式再求值;
四、代码
词法分析器代码链接:词法分析器
下面是算符优先分析法代码
代码在更新中…
目前实现计算FirstVt和LastVt集合
package main.experiment2;
import lombok.Getter;
import java.util.*;
import java.util.function.BiFunction;
import java.util.stream.Collectors;
/**
* @author Diminish
* @version 1.0
* @since 17
*/
@Getter
public class TGrammar
/**
* firstVt 集合
* Key : 非终结符
* Value : 集合内容
* */
private final Map<String, List<String>> firstTerminators = new TreeMap<>();
/**
* lastVt 集合
* Key : 非终结符
* Value : 集合内容
* */
private final Map<String, List<String>> lastTerminators = new TreeMap<>();
/**
* 非终结符集合
* */
private List<String> nonTerminators = new ArrayList<>();
/**
* 终结符集合
* */
private List<String> terminators = new ArrayList<>();
/**
* <p>语法</p>
* */
private final Map<String, List<String>> grammar = new HashMap<>();
/**
* 语法开始符号
* */
private String startTerminator = null;
/**
* <p>默认语法:</p>
* <p>A -> A+B | B</p>
* <p>B -> B*C | C</p>
* <p>C -> i</p>
* */
TGrammar()
grammar.put("A", List.of("A+B", "B"));
grammar.put("B", List.of("C*C", "C"));
grammar.put("C", List.of("i"));
startTerminator = "A";
initializeGrammar();
/**
* <p>构造指定语法</p>
* @param start 每个句型的开始符号
* @param generateExpression 每个开始符号对应的表达式
* */
TGrammar(List<String> start, List<List<String>> generateExpression)
for (int i = 0; i < start.size(); i++)
grammar.put(start.get(i), generateExpression.get(i));
if (startTerminator == null)
startTerminator = start.get(i);
initializeGrammar();
/**
* 构造终结符 非终结符 firstVt lastVt集合
* */
private void initializeGrammar ()
constructNonTerminator(this);
constructTerminator(this);
constructFirstTerminator();
constructLastTerminator();
/**
* 打印输出语法
* */
public void showGrammar ()
for (var i : grammar.entrySet())
System.out.print(i.getKey() + " -> ");
for (var v = 0 ; v < i.getValue().size(); v++)
if (v + 1 == i.getValue().size())
System.out.println(i.getValue().get(v));
else
System.out.print(i.getValue().get(v) + " | ");
/**
* 打印输出非终结符
* */
public void showNonTerminator ()
System.out.print("非终结符: ");
for (var v : nonTerminators)
System.out.print(v + " ");
System.out.println();
/**
* 打印输出终结符
* */
public void showTerminator ()
System.out.print("终结符: ");
for (var v : terminators)
System.out.print(v + " ");
System.out.println();
/**
* 打印输出 firstVt集合
* */
public void showFirstTerminators ()
var entryArrayList = sort(firstTerminators);
for (var firstTerminator : entryArrayList)
System.out.print("firstVt(" + firstTerminator.getKey() + ")" + " : ");
show(firstTerminator);
/**
* 打印输出 lastVt集合
* */
public void showLastTerminators ()
var entryArrayList = sort(lastTerminators);
for (var lastTerminator : entryArrayList)
System.out.print("lastVt(" + lastTerminator.getKey() + ")" + " : ");
show(lastTerminator);
private void show (Map.Entry<String, List<String>> lastTerminator)
int length = lastTerminator.getValue().size();
for (int i = 0; i < length; i++)
if (i + 1 >= length)
System.out.print(lastTerminator.getValue().get(i));
else
System.out.print(lastTerminator.getValue().get(i) + " , ");
System.out.println();
/**
* 排序, 根据值的长度排序, 按照值的长度从大到小排序
* @return 排好序的链表
*/
private List<Map.Entry<String, List<String>>> sort (Map<String, List<String>> firstOrLastTerminators)
var entryArrayList = new ArrayList<>(firstOrLastTerminators.entrySet());
entryArrayList.sort((o1, o2) -> o2.getValue().size() - o1.getValue().size());
return entryArrayList;
/**
* 判断是不是终结符
* @param c 需要判断的符号
* @return 判断结果
* */
private boolean isTerminator (String c)
return terminators.stream().anyMatch(terminator -> terminator.equals(c));
/**
* 判断是不是非终结符
* @param c 需要判断的符号
* @return 判断结果
* */
private boolean isNonTerminator (String c)
return nonTerminators.stream().anyMatch(nonTerminator -> nonTerminator.equals(c));
/**
* 构造非终结符
* */
private void constructNonTerminator(TGrammar grammar)
for (var i : grammar.grammar.entrySet())
nonTerminators.add(i.getKey());
nonTerminators = nonTerminators.stream().distinct().collect(Collectors.toList());
/**
* 构造终结符, 除大写字母以外的字符都是终结符
* */
private void constructTerminator(TGrammar grammar)
for (var i : grammar.grammar.entrySet())
for (var v : i.getValue())
for (int index = 0; index < v.length(); index++)
if (v.substring(index, index + 1).matches("[^A-Z]|"))
terminators.add(v.substring(index, index + 1));
terminators = terminators.stream().distinct().collect(Collectors.toList());
/**
* 构造 firstVt 集合
* */
private void constructFirstTerminator()
// 求出来的firstVt集合
Map<String, List<String>> firstTerminators = this.firstTerminators;
List<String> nonTerminators = this.nonTerminators;
// 初始化firstVt集合
for (var i : nonTerminators)
firstTerminators.put(i, new ArrayList<>());
// 记录是否完成
boolean isFinished = false;
// 集合表示对应的非终结符是否求出了firstVt集合, 求出后对应的元素置为true
Map<String, Boolean> flags = new HashMap<>(8);
// 初始化集合, 表示开始时所有的非终结符的firstVt集合没有求出, 所有默认是false
for (var i : firstTerminators.entrySet())
flags.put(i.getKey(), false);
int index = 0;
while (!isFinished)
// 记录一个产生式是否计算完了firstVt
boolean isBreak = false;
// index循环
if (index > nonTerminators.size() - 1)
index = 0;
// 获取index位置上的非终结符Vn
String Vn = nonTerminators.get(index);
// 判断Vn对应的flag值, 不为true进行计算, 为true表示计算出来了
if (!flags.get(Vn))
// 获取Vn的产生式
List<String> generateExpressions = grammar.get(Vn);
// 逐一进行判断
for (String generateExpression : generateExpressions)
// P -> a...
// 判断文法产生式是不是以终结符开头,是的话就把该终结符加入 firstVt集合
// a是第一个位置的元素
String a = generateExpression.substring(0, 1);
// 判断 a是不是终结符
if (isTerminator(a))
// 是, 即 P 的产生式以终结符开头
// 满足 P -> a.. 把 a 加入 firstVt(P)集合
firstTerminators.get(Vn).add(a);
// 如果产生式不是以终结符开头
// 判断 P -> Qa... 成立
// 即 判断文法产生式是不是以 非终结符 终结符 开头,是的话就把该终结符加入 firstVt(P)集合
else
// Q 是产生式第一个元素
String Q = generateExpression.substring(0, 1);
// a 是产生式第二个元素
// 判断一下是否有第二个元素, 即判断是否越界
try
a = generateExpression.substring(1, 2);
catch (Exception e)
a = "";
// 判读 P -> Qa... 成立
boolean pCanGetQa = isNonTerminator(Q) && isTerminator(a);
// 如果 P 的产生式以 Qa开头
if (pCanGetQa)
// 将 a加入到firstVt(P)中
firstTerminators.get(Vn).add(a);
// 匹配第二条件
// 若 a ∈ firstVt(Q) 且 P -> Q... 则 a ∈ firstVt(P)
// 判断 P != Q
if (!Q.equals(Vn))
// 判断 P -> Q... 中, Q是非终结符
boolean QisNotTerminator = isNonTerminator(Q);
// 判读 Q 的 firstVt(Q) 是否已经算出来
boolean qFirstVtIsDone = flags.get(Q);
// Q 是 非终结符
if (QisNotTerminator)
// Q 的 firstVt(Q) 是否已经算出来
if (qFirstVtIsDone)
// 算出来了
// 将 firstVt(Q) 中的元素加入 firstVt(P)
List<String> firstVtQ = firstTerminators.get(Q);
List<String> firstVtP = firstTerminators.get(Vn);
firstVtP.addAll(firstVtQ);
// 没有算出来直接到下一个进行计算
else
isBreak = true;
break;
// 没有计算出来就会调到这里
// index++ 后直接下一个产生式扫描
index++;
if (isBreak)
continue;
// 计算出了 firstVt
flags.put(Vn, true);
else
index++;
// 判断是不是都计算完了firstVt集合
boolean result = true;
for (var flag : flags.entrySet())
result = result && flag.getValue();
isFinished = result;
// 去重
for (var i : firstTerminators.entrySet())
i.setValue(i.getValue().stream().distinct().collect(Collectors.toList()));
/**
* 构造 lastVt 集以上是关于编译原理 实验二 简单计算器的设计与实现的主要内容,如果未能解决你的问题,请参考以下文章