语法分析器的设计与实现-LR

teardrop

发布日期: 2019-02-20 08:27:36 浏览量: 2570
评分:
star star star star star star star star star star_border
*转载请注明来自write-bug.com

语法分析器的设计与实现-LR

环境

  • 使用语言 - C++

  • 开发环境 - Qt Creator 5.8.0 + MinGW

  • 运行环境 - Windows 10

虽然使用Qt Creator开发,程序仍为console application,只是使用了Qt提供的容器库。

概述

  • 能够自动生成LR(0) DFA与SLR(1)分析表

  • 程序内含翻译方案,能够计算输入表达式的结果

要求

实验内容

编写语法分析程序,实现对算术表达式的语法分析。要求所分析算术表达式由如下文法产生:

  1. E -> E+T | E-T | T
  2. T -> T*F | T/F | F
  3. F -> (E) | num

实验要求

  • 在对输入的算术表达式进行分析的过程中,依次输出所采用的产生式

  • 构造识别该文法所有活前缀的DFA

  • 构造文法的LR分析表

  • 编程实现算法4.3,构造LR分析程序

算法4.3

  • 输入 - 文法G的一张分析表和一个输入符号串ω

  • 输出 - 如果ω∈L(G),得到ω自底向上的分析,否则报错

方法:

  1. 初始化 {
  2. 初始状态S0压栈
  3. ω$存入输入缓冲区
  4. ip指向ω$的第一个符号
  5. }
  6. do {
  7. S是栈顶状态,aip指向的符号;
  8. if (action[S, a] = shift S'){
  9. 把a和S'分别压入符号栈和状态栈的栈顶;
  10. 推进ip,使它进入下一个输入符号;
  11. } else if (action[S, a] = reduce by A -> β){
  12. 从栈顶弹出|β|个符号;
  13. S'是栈顶状态,把A和goto[S', A]分别压入符号栈和状态栈的栈顶;
  14. 输出产生式A -> β;
  15. } else if (action[S, a] = accept) return;
  16. else error();
  17. } while (1);

设计

文法存储

符号的存储

  1. struct Symbol
  2. {
  3. enum SymbolType
  4. {
  5. T, // terminator
  6. NT // non-terminator
  7. };
  8. SymbolType type;
  9. int index; // index in SymbolTable
  10. };

定义了枚举常量T(终结符)和NT(非终结符)作为符号类型。定义结构Symbol,包含一个符号类型type和一个在符号表中的索引index

定义以下两个特殊的终结符:

  1. const Symbol EPSILON = {Symbol::SymbolType::T, 0}; // ε
  2. const Symbol END = {Symbol::SymbolType::T, 1}; // $

严格来说空串ε和输入结束符$不算是终结符。此处视为终结符方便管理

符号表

  1. template <bool isTerminatorTable>
  2. class SymbolTable
  3. {
  4. private:
  5. Symbol::SymbolType type;
  6. QVector<QString> symbols;
  7. public:
  8. SymbolTable();
  9. int getIndex(const QString &str); // if str not exist, push it into symbols
  10. int getIndex(const QString &str, bool) const; // return -1 if str not exist
  11. QString getStr(int i) const; // return blank QString if i is invalid
  12. int size() const { return symbols.size(); }
  13. Symbol operator[](int n) const
  14. {
  15. Symbol result = {type, n};
  16. return result;
  17. }
  18. };
  19. using T_Table = SymbolTable<true>;
  20. using NT_Table = SymbolTable<false>;

符号表分为两种:终结符表和非终结符表。其中终结符表在构造时就需要添加符号$ε。为了方便理解,使用using对不同类型的符号表进行了重命名,即T_Table和NT_Table。为了实现以上两点,使用模板来设计符号表,模板参数isTerminatorTable表示了此符号表是否是终结符号表。

符号表中并没有保存符号Symbol,而是保存了每个符号的字符串量,即QVector<QString> symbols,所以虽然可以使用operator[]从符号表获得符号但是不能修改符号表中已存在的内容。可以根据符号的下标来查询字符串量(即getStr方法),也可以根据符号的字符串量来查询下标(即getIndex)。所以符号表只是一个用来查询的表,并不是一个符号的容器。

函数解释:

  • int getIndex(const string &str) - 查询字符串并返回下标。如果没有此字符串则插入此字符串
  • int getIndex(const string &str, bool) const - 仅查询字符串并获得下标
  • string getStr(int i) const - 查询对应下标的符号的字符串
  • int size() const - 查询符号表容量

DFA与自动机

为了构造有效项目集规范族,首先定义了有效项目struct Project

  1. struct Project
  2. {
  3. int ntIndex;
  4. int candidateIndex;
  5. int index; // position of Point in a project
  6. };

其中ntIndex表示此项目的生成式左侧非终结符的下标,candidateIndex表示此项目的生成式是此非终结符的第几个生成式。index表示项目中圆点的位置。

自动机的每个状态都是一个项目的集合,即

  1. using State = QVector<Project>;

自动机保存为一个map,此map的key应该是状态和输入符号的二元组,所以定义DFA_Key:

  1. struct DFA_Key
  2. {
  3. State state;
  4. Symbol s;
  5. };

那么DFA就是:

  1. using DFA = QMap<DFA_Key, State>;

类似地,分析表也是一个map,分析表的key应该是当前状态(的下标)和输入符号的二元组。因为可以和DFA_Key都包含状态和输入符号,所以直接使用DFA_Key作为分析表的key:

  1. using SLR_Key = DFA_Key;

而分析表map的value应该是一个分析动作,所以定义Action:

  1. struct Action
  2. {
  3. enum ActionType
  4. {
  5. Shift,
  6. Reduce,
  7. Goto,
  8. Accept
  9. };
  10. ActionType type;
  11. int index;
  12. };

可以看到Action包含一个枚举类型ActionType,有四种取值,分别表示:

  • Shift - 移进,此时index表示移进后转移到的状态下标

  • Reduce - 规约,此时index表示规约使用的产生式的下标

  • Goto - 转移,此时index表示应该转移到的状态下标

  • Accept - 接收,此时index无意义

那么分析表的数据结构就是:

  1. using SLR_Table = QMap<SLR_Key, Action>;

文法表

  1. class GrammaTable
  2. {
  3. private:
  4. // input
  5. QVector<Gramma> grammas;
  6. T_Table tTable;
  7. NT_Table ntTable;
  8. // error handling
  9. int lineCount;
  10. bool error;
  11. // process
  12. QVector<First> firsts;
  13. QVector<Follow> follows;
  14. QVector<State> states;
  15. DFA dfa;
  16. SLR_Table slrTable;
  17. void killBlank(QString &str) const; // discard blank chars
  18. bool format(QString &str) const; // return false if format is wrong
  19. /**
  20. * killDuplicated:
  21. * eliminate same Candidate in grammas[index] if index != -1
  22. * eliminate same Candidate in each Gramma when index == -1
  23. */
  24. void killDuplicated(int index = -1);
  25. void killEpsilon();
  26. void getFirsts();
  27. First getFirst(const Candidate &candidate) const;
  28. void getFollows();
  29. void getDFA(); // construct DFA
  30. void getState(State &state); // construct a state
  31. int getIndex(int ntIndex, int candidateIndex) const;
  32. void getSLR_Table();
  33. int getReduceIndex(const State &s, int &ntIndex, int &candidateIndex) const;
  34. void getCandidateIndex(int index, int &ntIndex, int &candidateIndex) const;
  35. int candidateCount() const;
  36. // return empty candidate if error
  37. Candidate parseInputToCandidate(const QString &str, QVector<int> *values = nullptr) const;
  38. void outputSingleCandidate(int ntIndex, int candidateIndex) const;
  39. void outputProject(const Project &p) const;
  40. void outputSymbol(const Symbol &s) const;
  41. void outputSLR_Key(const SLR_Key &key) const;
  42. void outputAction(const Action &a) const;
  43. public:
  44. GrammaTable() : lineCount(0), error(false) {}
  45. int insert(const QString &grammaLine); // return 0 if ok, otherwise return lineCount
  46. /**
  47. * generate first set, follow set, index of candidates and predict table
  48. * return false if error
  49. */
  50. bool generate();
  51. void output() const;
  52. bool ok() const { return !error; }
  53. int currentLineCount() const { return lineCount; }
  54. bool parse(const QString &str, bool calculateResult = false) const;
  55. };

文法表包括了文法grammas、符号表tTable和ntTable、此文法生成的FIRST集与FOLLOW集、DFA、所有状态和预测分析表。

一个候选式Candidate由若干个符号Symbol组成,一个符号的生成式Gramma由若干个候选式Candidate组成

  1. using Candidate = vector<Symbol>;
  2. using Gramma = vector<Candidate>;

FIRST集和FOLLOW集是符号Symbol的集合。

  1. using First = set<Symbol>;
  2. using Follow = set<Symbol>;

变量lineCount和error用来控制错误,当错误发生时不能够继续输入文法、不能生成FIRST集和FOLLOW集、不能解析输入串。输入错误时会返回lineCount,根据此值可以定位输入的错误。

函数概述:

  • private
    • void killBlank(QString &str) const; - 清除输入串中的空白符(空格、制表、换行)
    • bool format(QString &str) const; - 如果输入串没有->则报错
    • void killDuplicated(int index = -1); - 清除第index个非终结符的重复生成式。index为-1时清除所有非终结符的重复生成式
    • void killEpsilon(); - 清除所有候选式中多余的ε
    • void getFirsts(); - 生成所有非终结符的FIRST集
    • First getFirst(const Candidate &candidate) const; - 在所有非终结符的FIRST存在的情况下生成单个候选式的FIRST集
    • void getFollows(); - 生成所有非终结符的FOLLOW集
    • void getDFA(); - 生成DFA
    • void getState(State &state); - 根据当前State进行扩充从而形成一个完整的State
    • void getIndex(int ntIndex, int candidateIndex) const; - 根据生成式左侧非终结符的下标和生成式是此非终结符的第几个生成式来判断生成式下标
    • void getSLR_Table(); - 生成SLR分析表
    • int getReduceIndex(const State &s, int &ntIndex, int &candidateIndex) const; - 根据当前状态判断是否能规约。如果能,返回规约使用的生成式下标,并把ntIndex和candidateIndex指向生成式
    • void getCandidateIndex(int index, int &ntIndex, int &candidateIndex) const; - 根据输入的index计算生成式在grammas中的位置,通过ntIndex和candidateIndex返回
    • int candidateCount() const; - 返回生成式数量
    • Candidate parseInputToCandidate(const QString &str, QVector<int> *values = nullptr) const; - 把字符串解析为符号串。如果values不为空,则解析输入串中的数字
    • void outputSingleCandidate(int ntIndex, int candidateIndex) const; - 输出单个生成式
    • void outputProject(const Project &p) const; - 输出一个项目
    • void outputSymbol(const Symbol &s) const; - 输出一个符号
    • void outputSLR_Key(const SLR_Key &key) const; - 输出一个分析表的key
    • void outputAction(const Action &a) const; - 输出一个分析动作
  • public
    • int insert(const string &grammaLine); - 插入一行文法。如果文法出错则返回lineCount,否则返回0
    • bool generate(); - 生成FIRST集、FOLLOW集和预测分析表,如果生成失败则返回false
    • void output() const; - 输出消左递归后的文法、FIRST集、FOLLOW集、预测分析表
    • bool ok() const { return !error; } - 判断此预测分析表是否能够正常继续输入
    • int currentLineCount() const { return lineCount; } - 返回当前行数,通常用来确定错误发生的位置
    • bool parse(const string &str, bool calculateResult = false) const; - 试图解析输入的字符串。如果calculateResult为true则输出结果。如果解析失败则返回false。

翻译方案设计

  1. E' -> E { print(E.v) }
  2. E -> E1 + T { E.v = E1.v + T.v }
  3. E -> E1 - T { E.v = E1.v - T.v }
  4. E -> T { E.v = T.v }
  5. T -> T1 * F { T.v = T1.v * F.v}
  6. T -> T1 / F { T.v = T1.v / F.v}
  7. T -> F { T.v = F.v }
  8. F -> (E) { F.v = E.v }
  9. F -> num { F.v = num.v }

其中所有符号的属性v均为综合属性,用来保存和传递结果。print(E.v)用来输出结果。

输入设计与限制

文法已内置在main函数中,不需要输入文法。能够输入的内容为:

  • 需要解析的符号串

  • 需要解析的表达式

输入符号串时,如果输入的符号长度超过1位,需要使用两个$符号括起来。在输入符号串时,唯一需要括起来的符号就是num。示例输入:

  1. $num$
  2. $num$+$num$*$num$/$num$-$num$
  3. ($num$+($num$-($num$*($num$/($num$)))))

输入表达式时,输入的数字也需要用两个$括起来,不论数字长短。示例输入:

  1. $123$
  2. $123$+$123$*$123$/$123$-$123$
  3. ($123$+($123$-($123$*($123$/($123$)))))

之所以使用这样的设计是因为上次写自顶向下语法分析器的时候已经写好了解析两个$括起内容的函数

表达式解析时的输入限制:毕竟不是词法分析器,输入数字时限制只能输入正整数,即两个$中间不能包含0-9以外的符号,但是输出可以是小数和负数。解析时会把所有由两个$括起的内容解析为num

关键函数设计

此处只解释DFA和分析表的生成,以及解析函数的工作原理。关于First集和Follow集的构造,在上次自顶向下语法分析时已实现,略去。

DFA的生成

  1. void GrammaTable::getDFA()
  2. {
  3. // 首先清除所有状态以及之前的DFA
  4. states.clear();
  5. dfa.clear();
  6. // 构造第一个状态,即状态0
  7. State firstState;
  8. firstState.push_back({0, 0, 0}); // 把项目 E' -> .E 装入状态
  9. getState(firstState); // 根据项目中的已有状态,拓展状态而生成完整状态
  10. states.push_back(firstState); // 把状态0装入状态集合
  11. // 扩展DFA
  12. for (int i = 0; i < states.size(); ++i)
  13. {
  14. // 在拓展的过程中states的size可能会发生变化
  15. // 所以要注意边界
  16. State state = states[i]; // 当前状态
  17. QVector<State> tStates; // 临时保存由当前状态生成的状态(因为状态可能重复
  18. DFA tDfa; // 临时保存由当前状态生成的一些转移函数
  19. // 开始扩展
  20. for (int j = 0; j < state.size(); ++j)
  21. {
  22. // 遍历当前状态中的每个项目
  23. auto project = state[j];
  24. if (project.index < grammas[project.ntIndex][project.candidateIndex].size())
  25. {
  26. // 项目中的圆点可以右移
  27. // 保存右移时接收的符号
  28. auto sym = grammas[project.ntIndex][project.candidateIndex][project.index];
  29. ++project.index; // 圆点右移
  30. if (!tDfa.contains({state, sym}))
  31. {
  32. // 临时DFA中没有此转换函数,则新建状态和转换函数
  33. State t;
  34. t.push_back(project); // 此状态目前仅有这一个项目
  35. tStates.push_back(t); // 装入临时状态集
  36. tDfa.insert({state, sym}, t); // 装入临时DFA
  37. }
  38. else
  39. {
  40. // 临时DFA中已有此转换函数
  41. // 把此项目装入转换函数的目标状态中
  42. DFA_Key key = {state, sym};
  43. int index = tStates.indexOf(tDfa[key]);
  44. tStates[index].push_back(project);
  45. tDfa[key] = tStates[index];
  46. }
  47. }
  48. }
  49. // 至此,当前状态中的每个项目都已经处理过了
  50. // 扩展临时状态集中的状态
  51. for (auto &s : tStates)
  52. {
  53. auto key = tDfa.key(s);
  54. getState(s);
  55. tDfa[key] = s;
  56. }
  57. // 合并DFA与临时DFA、状态集与已有状态集
  58. // 检查扩展后的临时状态集中的状态是否与已有的状态重复
  59. auto keys = tDfa.keys();
  60. for (auto key : keys)
  61. {
  62. int index = states.indexOf(tDfa[key]);
  63. if (index == -1)
  64. {
  65. states.push_back(tDfa[key]);
  66. dfa.insert(key, tDfa[key]);
  67. }
  68. else
  69. {
  70. dfa.insert(key, states[index]);
  71. }
  72. }
  73. }
  74. }

分析表的生成

  1. void GrammaTable::getSLR_Table()
  2. {
  3. // 先根据所有状态生成规约和接收的表项
  4. // 遍历所有状态
  5. for (auto state : states)
  6. {
  7. int ntIndex;
  8. int candidateIndex;
  9. // 判断当前状态是否存在规约项
  10. int reduceIndex = getReduceIndex(state, ntIndex, candidateIndex);
  11. if (ntIndex != -1 && candidateIndex != -1)
  12. {
  13. // 当前状态能够规约(默认只有一种规约情况
  14. // 判断是接收还是规约,生成表项
  15. for (auto s : follows[ntIndex])
  16. {
  17. Action a;
  18. a.index = reduceIndex;
  19. if (reduceIndex == 0)
  20. {
  21. a.type = Action::ActionType::Accept;
  22. }
  23. else
  24. {
  25. a.type = Action::ActionType::Reduce;
  26. }
  27. slrTable.insert({state, s}, a);
  28. }
  29. }
  30. }
  31. // 生成移进和转移的表项
  32. // 遍历DFA
  33. auto keys = dfa.keys();
  34. for (auto key : keys)
  35. {
  36. if (key.s.type == Symbol::SymbolType::T)
  37. {
  38. // 移进
  39. slrTable.insert(key, {Action::ActionType::Shift, states.indexOf(dfa[key])});
  40. }
  41. else
  42. {
  43. // 转移
  44. slrTable.insert(key, {Action::ActionType::Goto, states.indexOf(dfa[key])});
  45. }
  46. }
  47. }

输入串的解析

  1. bool GrammaTable::parse(const QString &str, bool calculateResult) const
  2. {
  3. QVector<int> values; // 用来保存每个符号的value。没有value的符号默认value为0
  4. Candidate candidate; // 用来保存解析输入串后得到的符号串
  5. if (calculateResult)
  6. candidate = parseInputToCandidate(str, &values);
  7. else
  8. candidate = parseInputToCandidate(str);
  9. if (candidate.size() == 0)
  10. {
  11. cout << "Error input.\n";
  12. return false;
  13. }
  14. candidate.push_back(END); // 在符号串末尾加上终止符$
  15. // 声明与初始化变量
  16. QStack<int> stateStack;
  17. QStack<Symbol> symbolStack;
  18. QStack<double> valueStack;
  19. stateStack.push(0);
  20. symbolStack.push(END);
  21. int index = 0; // 当前分析到的符号串的下标
  22. while (index < candidate.size()) // 没有分析结束时
  23. {
  24. // 根据当前状态和符号,从分析表获取分析动作
  25. SLR_Key key = {states[stateStack.top()], candidate[index]};
  26. if (!slrTable.contains(key)) // 分析表没有此项,停止分析
  27. break;
  28. auto action = slrTable[key];
  29. outputAction(action); // 输出动作
  30. cout << endl;
  31. switch (action.type)
  32. {
  33. case Action::ActionType::Accept: // 接收
  34. cout << "Accepted.\n";
  35. if (calculateResult)
  36. cout << "Result is " << valueStack.top() << endl;
  37. return true;
  38. break;
  39. case Action::ActionType::Reduce: // 规约
  40. {
  41. // calculate value
  42. if (calculateResult)
  43. {
  44. // 直接通过栈顶使用value栈中的内容计算结果
  45. double t = 0;
  46. switch (action.index)
  47. {
  48. case 1: // E -> E1 + T { E.v = E1.v + T.v }
  49. t = valueStack.top();
  50. valueStack.pop();
  51. valueStack.pop();
  52. t += valueStack.top();
  53. valueStack.pop();
  54. valueStack.push(t);
  55. break;
  56. case 2: // E -> E1 - T { E.v = E1.v - T.v }
  57. t = valueStack.top();
  58. valueStack.pop();
  59. valueStack.pop();
  60. t = valueStack.top() - t;
  61. valueStack.pop();
  62. valueStack.push(t);
  63. break;
  64. case 3: // E -> T { E.v = T.v }
  65. break;
  66. case 4: // T -> T1 * F { T.v = T1.v * F.v}
  67. t = valueStack.top();
  68. valueStack.pop();
  69. valueStack.pop();
  70. t *= valueStack.top();
  71. valueStack.pop();
  72. valueStack.push(t);
  73. break;
  74. case 5: // T -> T1 / F { T.v = T1.v / F.v}
  75. t = valueStack.top();
  76. valueStack.pop();
  77. valueStack.pop();
  78. t = valueStack.top() / t;
  79. valueStack.pop();
  80. valueStack.push(t);
  81. break;
  82. case 6: // T -> F { T.v = F.v }
  83. break;
  84. case 7: // F -> (E) { F.v = E.v }
  85. valueStack.pop();
  86. t = valueStack.top();
  87. valueStack.pop();
  88. valueStack.top() = t;
  89. break;
  90. case 8: // F -> num { F.v = num.v }
  91. break;
  92. default:
  93. break;
  94. }
  95. }
  96. // 规约状态栈和符号栈
  97. int ntIndex;
  98. int candidateIndex;
  99. getCandidateIndex(action.index, ntIndex, candidateIndex);
  100. for (int i = 0; i < grammas[ntIndex][candidateIndex].size(); ++i)
  101. {
  102. stateStack.pop();
  103. symbolStack.pop();
  104. }
  105. // 规约后的状态转移
  106. SLR_Key gotoKey = {states[stateStack.top()], {Symbol::SymbolType::NT, ntIndex}};
  107. auto gotoAction = slrTable[gotoKey];
  108. outputAction(gotoAction); // output
  109. cout << endl;
  110. stateStack.push(gotoAction.index);
  111. symbolStack.push(ntTable[ntIndex]);
  112. --index; // do not increase index
  113. break;
  114. }
  115. case Action::ActionType::Shift: // 移进
  116. stateStack.push(action.index);
  117. symbolStack.push(candidate[index]);
  118. if (calculateResult)
  119. valueStack.push(values[index]);
  120. break;
  121. default:
  122. break;
  123. }
  124. ++index;
  125. }
  126. cout << "This line not belongs to this gramma.\n";
  127. return false;
  128. }

工作流程设计

generate函数

  1. bool GrammaTable::generate()
  2. {
  3. // 判断输入文法时是否出错
  4. if (error)
  5. return false;
  6. // 未出错
  7. getFirsts(); // 生成FIRST集
  8. getFollows(); // 生成FOLLOW集
  9. getDFA(); // 生成DFA
  10. getSLR_Table(); // 生成分析表
  11. return true;
  12. }

main函数

  1. GrammaTable gt; // 声明文法表
  2. QString t; // 用于保存输入串
  3. // 文法表注入目标文法
  4. gt.insert("E' -> E");
  5. gt.insert("E -> E+T | E-T | T");
  6. gt.insert("T -> T*F | T/F | F");
  7. gt.insert("F -> (E) | $num$");
  8. gt.generate(); // 生成FIRST集、FOLLOW集、DFA和分析表
  9. cout << "Output:\n";
  10. gt.output(); // 输出
  11. while (1)
  12. {
  13. // 输出提示信息
  14. cout << "\nPress 1: Just parse input.\nPress 2: Calculate result.\nOtherwise: Exit\n";
  15. // 获取当前模式
  16. int mode = getch() - '0';
  17. if (mode != 1 && mode != 2) // error input
  18. mode = 3;
  19. if (mode == 3)
  20. return 0;
  21. bool flag = true;
  22. while (flag)
  23. {
  24. cout << "\nInput a line to parse, input blank line to stop.\n";
  25. getline(cin, t);
  26. if (t.length())
  27. {
  28. // 未输入空串,解析
  29. gt.parse(t, mode == 2);
  30. }
  31. else
  32. {
  33. // 输入空串,结束循环
  34. flag = false;
  35. }
  36. }
  37. }

测试与说明

初始输出

启动程序后生成First集、Follow集、DFA和分析表并输出这些内容:

  1. Output:
  2. Format gramma:
  3. E' -> E
  4. E -> E+T | E-T | T
  5. T -> T*F | T/F | F
  6. F -> (E) | num
  7. Candidates with index:
  8. 0 E' -> E
  9. 1 E -> E+T
  10. 2 E -> E-T
  11. 3 E -> T
  12. 4 T -> T*F
  13. 5 T -> T/F
  14. 6 T -> F
  15. 7 F -> (E)
  16. 8 F -> num
  17. First sets:
  18. First(E'): num (
  19. First(E): num (
  20. First(T): num (
  21. First(F): num (
  22. Follow sets:
  23. Follow(E'): $
  24. Follow(E): - + $ )
  25. Follow(T): - + $ ) / *
  26. Follow(F): - + $ ) / *
  27. LR(0) DFA states:
  28. State[0]:
  29. E' -> .E
  30. E -> .E+T
  31. E -> .E-T
  32. E -> .T
  33. T -> .T*F
  34. T -> .T/F
  35. T -> .F
  36. F -> .(E)
  37. F -> .num
  38. State[1]:
  39. E' -> E.
  40. E -> E.+T
  41. E -> E.-T
  42. State[2]:
  43. E -> T.
  44. T -> T.*F
  45. T -> T./F
  46. State[3]:
  47. T -> F.
  48. State[4]:
  49. F -> (.E)
  50. E -> .E+T
  51. E -> .E-T
  52. E -> .T
  53. T -> .T*F
  54. T -> .T/F
  55. T -> .F
  56. F -> .(E)
  57. F -> .num
  58. State[5]:
  59. F -> num.
  60. State[6]:
  61. E -> E+.T
  62. T -> .T*F
  63. T -> .T/F
  64. T -> .F
  65. F -> .(E)
  66. F -> .num
  67. State[7]:
  68. E -> E-.T
  69. T -> .T*F
  70. T -> .T/F
  71. T -> .F
  72. F -> .(E)
  73. F -> .num
  74. State[8]:
  75. T -> T*.F
  76. F -> .(E)
  77. F -> .num
  78. State[9]:
  79. T -> T/.F
  80. F -> .(E)
  81. F -> .num
  82. State[10]:
  83. F -> (E.)
  84. E -> E.+T
  85. E -> E.-T
  86. State[11]:
  87. E -> E+T.
  88. T -> T.*F
  89. T -> T./F
  90. State[12]:
  91. E -> E-T.
  92. T -> T.*F
  93. T -> T./F
  94. State[13]:
  95. T -> T*F.
  96. State[14]:
  97. T -> T/F.
  98. State[15]:
  99. F -> (E).
  100. LR(0) DFA transition functions:
  101. 1 + '+' -> 6
  102. 1 + '-' -> 7
  103. 11 + '*' -> 8
  104. 11 + '/' -> 9
  105. 12 + '*' -> 8
  106. 12 + '/' -> 9
  107. 2 + '*' -> 8
  108. 2 + '/' -> 9
  109. 8 + 'F' -> 13
  110. 8 + '(' -> 4
  111. 8 + 'num' -> 5
  112. 9 + 'F' -> 14
  113. 9 + '(' -> 4
  114. 9 + 'num' -> 5
  115. 10 + '+' -> 6
  116. 10 + '-' -> 7
  117. 10 + ')' -> 15
  118. 6 + 'T' -> 11
  119. 6 + 'F' -> 3
  120. 6 + '(' -> 4
  121. 6 + 'num' -> 5
  122. 7 + 'T' -> 12
  123. 7 + 'F' -> 3
  124. 7 + '(' -> 4
  125. 7 + 'num' -> 5
  126. 0 + 'E' -> 1
  127. 0 + 'T' -> 2
  128. 0 + 'F' -> 3
  129. 0 + '(' -> 4
  130. 0 + 'num' -> 5
  131. 4 + 'E' -> 10
  132. 4 + 'T' -> 2
  133. 4 + 'F' -> 3
  134. 4 + '(' -> 4
  135. 4 + 'num' -> 5
  136. SLR_1 table:
  137. 13 + '$' -> R4
  138. 13 + '+' -> R4
  139. 13 + '-' -> R4
  140. 13 + '*' -> R4
  141. 13 + '/' -> R4
  142. 13 + ')' -> R4
  143. 14 + '$' -> R5
  144. 14 + '+' -> R5
  145. 14 + '-' -> R5
  146. 14 + '*' -> R5
  147. 14 + '/' -> R5
  148. 14 + ')' -> R5
  149. 3 + '$' -> R6
  150. 3 + '+' -> R6
  151. 3 + '-' -> R6
  152. 3 + '*' -> R6
  153. 3 + '/' -> R6
  154. 3 + ')' -> R6
  155. 15 + '$' -> R7
  156. 15 + '+' -> R7
  157. 15 + '-' -> R7
  158. 15 + '*' -> R7
  159. 15 + '/' -> R7
  160. 15 + ')' -> R7
  161. 5 + '$' -> R8
  162. 5 + '+' -> R8
  163. 5 + '-' -> R8
  164. 5 + '*' -> R8
  165. 5 + '/' -> R8
  166. 5 + ')' -> R8
  167. 1 + '$' -> ACC
  168. 1 + '+' -> S6
  169. 1 + '-' -> S7
  170. 11 + '$' -> R1
  171. 11 + '+' -> R1
  172. 11 + '-' -> R1
  173. 11 + '*' -> S8
  174. 11 + '/' -> S9
  175. 11 + ')' -> R1
  176. 12 + '$' -> R2
  177. 12 + '+' -> R2
  178. 12 + '-' -> R2
  179. 12 + '*' -> S8
  180. 12 + '/' -> S9
  181. 12 + ')' -> R2
  182. 2 + '$' -> R3
  183. 2 + '+' -> R3
  184. 2 + '-' -> R3
  185. 2 + '*' -> S8
  186. 2 + '/' -> S9
  187. 2 + ')' -> R3
  188. 8 + 'F' -> GOTO 13
  189. 8 + '(' -> S4
  190. 8 + 'num' -> S5
  191. 9 + 'F' -> GOTO 14
  192. 9 + '(' -> S4
  193. 9 + 'num' -> S5
  194. 10 + '+' -> S6
  195. 10 + '-' -> S7
  196. 10 + ')' -> S15
  197. 6 + 'T' -> GOTO 11
  198. 6 + 'F' -> GOTO 3
  199. 6 + '(' -> S4
  200. 6 + 'num' -> S5
  201. 7 + 'T' -> GOTO 12
  202. 7 + 'F' -> GOTO 3
  203. 7 + '(' -> S4
  204. 7 + 'num' -> S5
  205. 0 + 'E' -> GOTO 1
  206. 0 + 'T' -> GOTO 2
  207. 0 + 'F' -> GOTO 3
  208. 0 + '(' -> S4
  209. 0 + 'num' -> S5
  210. 4 + 'E' -> GOTO 10
  211. 4 + 'T' -> GOTO 2
  212. 4 + 'F' -> GOTO 3
  213. 4 + '(' -> S4
  214. 4 + 'num' -> S5
  215. Press 1: Just parse input.
  216. Press 2: Calculate result.
  217. Otherwise: Exit

符号串解析

在初始界面按下1进入符号串解析状态。

输入:

  1. $num$+$num$*$num$/$num$-$num$
  2. ($num$+($num$-($num$*($num$/($num$)))))
  3. $num$
  4. ($num$+($num$-($num$*($num$/($num$))))
  5. $num$+($num$-($num$*($num$/($num$)))))
  6. ($num$+($num$-($nu*($num$/($num$))))

输出:

  1. Input a line to parse, input blank line to stop.
  2. $num$+$num$*$num$/$num$-$num$
  3. S5
  4. R8
  5. GOTO 3
  6. R6
  7. GOTO 2
  8. R3
  9. GOTO 1
  10. S6
  11. S5
  12. R8
  13. GOTO 3
  14. R6
  15. GOTO 11
  16. S8
  17. S5
  18. R8
  19. GOTO 13
  20. R4
  21. GOTO 11
  22. S9
  23. S5
  24. R8
  25. GOTO 14
  26. R5
  27. GOTO 11
  28. R1
  29. GOTO 1
  30. S7
  31. S5
  32. R8
  33. GOTO 3
  34. R6
  35. GOTO 12
  36. R2
  37. GOTO 1
  38. ACC
  39. Accepted.
  40. Input a line to parse, input blank line to stop.
  41. ($num$+($num$-($num$*($num$/($num$)))))
  42. S4
  43. S5
  44. R8
  45. GOTO 3
  46. R6
  47. GOTO 2
  48. R3
  49. GOTO 10
  50. S6
  51. S4
  52. S5
  53. R8
  54. GOTO 3
  55. R6
  56. GOTO 2
  57. R3
  58. GOTO 10
  59. S7
  60. S4
  61. S5
  62. R8
  63. GOTO 3
  64. R6
  65. GOTO 2
  66. S8
  67. S4
  68. S5
  69. R8
  70. GOTO 3
  71. R6
  72. GOTO 2
  73. S9
  74. S4
  75. S5
  76. R8
  77. GOTO 3
  78. R6
  79. GOTO 2
  80. R3
  81. GOTO 10
  82. S15
  83. R7
  84. GOTO 14
  85. R5
  86. GOTO 2
  87. R3
  88. GOTO 10
  89. S15
  90. R7
  91. GOTO 13
  92. R4
  93. GOTO 2
  94. R3
  95. GOTO 10
  96. S15
  97. R7
  98. GOTO 3
  99. R6
  100. GOTO 12
  101. R2
  102. GOTO 10
  103. S15
  104. R7
  105. GOTO 3
  106. R6
  107. GOTO 11
  108. R1
  109. GOTO 10
  110. S15
  111. R7
  112. GOTO 3
  113. R6
  114. GOTO 2
  115. R3
  116. GOTO 1
  117. ACC
  118. Accepted.
  119. Input a line to parse, input blank line to stop.
  120. $num$
  121. S5
  122. R8
  123. GOTO 3
  124. R6
  125. GOTO 2
  126. R3
  127. GOTO 1
  128. ACC
  129. Accepted.
  130. Input a line to parse, input blank line to stop.
  131. ($num$+($num$-($num$*($num$/($num$))))
  132. S4
  133. S5
  134. R8
  135. GOTO 3
  136. R6
  137. GOTO 2
  138. R3
  139. GOTO 10
  140. S6
  141. S4
  142. S5
  143. R8
  144. GOTO 3
  145. R6
  146. GOTO 2
  147. R3
  148. GOTO 10
  149. S7
  150. S4
  151. S5
  152. R8
  153. GOTO 3
  154. R6
  155. GOTO 2
  156. S8
  157. S4
  158. S5
  159. R8
  160. GOTO 3
  161. R6
  162. GOTO 2
  163. S9
  164. S4
  165. S5
  166. R8
  167. GOTO 3
  168. R6
  169. GOTO 2
  170. R3
  171. GOTO 10
  172. S15
  173. R7
  174. GOTO 14
  175. R5
  176. GOTO 2
  177. R3
  178. GOTO 10
  179. S15
  180. R7
  181. GOTO 13
  182. R4
  183. GOTO 2
  184. R3
  185. GOTO 10
  186. S15
  187. R7
  188. GOTO 3
  189. R6
  190. GOTO 12
  191. R2
  192. GOTO 10
  193. S15
  194. R7
  195. GOTO 3
  196. R6
  197. GOTO 11
  198. R1
  199. GOTO 10
  200. This line not belongs to this gramma.
  201. Input a line to parse, input blank line to stop.
  202. $num$+($num$-($num$*($num$/($num$)))))
  203. S5
  204. R8
  205. GOTO 3
  206. R6
  207. GOTO 2
  208. R3
  209. GOTO 1
  210. S6
  211. S4
  212. S5
  213. R8
  214. GOTO 3
  215. R6
  216. GOTO 2
  217. R3
  218. GOTO 10
  219. S7
  220. S4
  221. S5
  222. R8
  223. GOTO 3
  224. R6
  225. GOTO 2
  226. S8
  227. S4
  228. S5
  229. R8
  230. GOTO 3
  231. R6
  232. GOTO 2
  233. S9
  234. S4
  235. S5
  236. R8
  237. GOTO 3
  238. R6
  239. GOTO 2
  240. R3
  241. GOTO 10
  242. S15
  243. R7
  244. GOTO 14
  245. R5
  246. GOTO 2
  247. R3
  248. GOTO 10
  249. S15
  250. R7
  251. GOTO 13
  252. R4
  253. GOTO 2
  254. R3
  255. GOTO 10
  256. S15
  257. R7
  258. GOTO 3
  259. R6
  260. GOTO 12
  261. R2
  262. GOTO 10
  263. S15
  264. R7
  265. GOTO 3
  266. R6
  267. GOTO 11
  268. R1
  269. GOTO 1
  270. This line not belongs to this gramma.
  271. Input a line to parse, input blank line to stop.
  272. ($num$+($num$-($nu*($num$/($num$))))
  273. Error input.
  274. Input a line to parse, input blank line to stop.

按下回车输入空行以回到初始界面。

表达式解析

在初始界面按下2进入表达式解析状态。

输入:

  1. $123$
  2. $66$+$66$*$66$/$66$-$66$
  3. ($123$+($789$-($789$*($123$/($123$)))))
  4. ($123$+($123$-($123$*($123$/($123$))))
  5. $123$+($123$-($123$*($123$/($123$)))))

输出:

  1. Press 1: Just parse input.
  2. Press 2: Calculate result.
  3. Otherwise: Exit
  4. Input a line to parse, input blank line to stop.
  5. $123$
  6. S5
  7. R8
  8. GOTO 3
  9. R6
  10. GOTO 2
  11. R3
  12. GOTO 1
  13. ACC
  14. Accepted.
  15. Result is 123
  16. Input a line to parse, input blank line to stop.
  17. $66$+$66$*$66$/$66$-$66$
  18. S5
  19. R8
  20. GOTO 3
  21. R6
  22. GOTO 2
  23. R3
  24. GOTO 1
  25. S6
  26. S5
  27. R8
  28. GOTO 3
  29. R6
  30. GOTO 11
  31. S8
  32. S5
  33. R8
  34. GOTO 13
  35. R4
  36. GOTO 11
  37. S9
  38. S5
  39. R8
  40. GOTO 14
  41. R5
  42. GOTO 11
  43. R1
  44. GOTO 1
  45. S7
  46. S5
  47. R8
  48. GOTO 3
  49. R6
  50. GOTO 12
  51. R2
  52. GOTO 1
  53. ACC
  54. Accepted.
  55. Result is 66
  56. Input a line to parse, input blank line to stop.
  57. ($123$+($789$-($789$*($123$/($123$)))))
  58. S4
  59. S5
  60. R8
  61. GOTO 3
  62. R6
  63. GOTO 2
  64. R3
  65. GOTO 10
  66. S6
  67. S4
  68. S5
  69. R8
  70. GOTO 3
  71. R6
  72. GOTO 2
  73. R3
  74. GOTO 10
  75. S7
  76. S4
  77. S5
  78. R8
  79. GOTO 3
  80. R6
  81. GOTO 2
  82. S8
  83. S4
  84. S5
  85. R8
  86. GOTO 3
  87. R6
  88. GOTO 2
  89. S9
  90. S4
  91. S5
  92. R8
  93. GOTO 3
  94. R6
  95. GOTO 2
  96. R3
  97. GOTO 10
  98. S15
  99. R7
  100. GOTO 14
  101. R5
  102. GOTO 2
  103. R3
  104. GOTO 10
  105. S15
  106. R7
  107. GOTO 13
  108. R4
  109. GOTO 2
  110. R3
  111. GOTO 10
  112. S15
  113. R7
  114. GOTO 3
  115. R6
  116. GOTO 12
  117. R2
  118. GOTO 10
  119. S15
  120. R7
  121. GOTO 3
  122. R6
  123. GOTO 11
  124. R1
  125. GOTO 10
  126. S15
  127. R7
  128. GOTO 3
  129. R6
  130. GOTO 2
  131. R3
  132. GOTO 1
  133. ACC
  134. Accepted.
  135. Result is 123
  136. Input a line to parse, input blank line to stop.
  137. ($123$+($123$-($123$*($123$/($123$))))
  138. S4
  139. S5
  140. R8
  141. GOTO 3
  142. R6
  143. GOTO 2
  144. R3
  145. GOTO 10
  146. S6
  147. S4
  148. S5
  149. R8
  150. GOTO 3
  151. R6
  152. GOTO 2
  153. R3
  154. GOTO 10
  155. S7
  156. S4
  157. S5
  158. R8
  159. GOTO 3
  160. R6
  161. GOTO 2
  162. S8
  163. S4
  164. S5
  165. R8
  166. GOTO 3
  167. R6
  168. GOTO 2
  169. S9
  170. S4
  171. S5
  172. R8
  173. GOTO 3
  174. R6
  175. GOTO 2
  176. R3
  177. GOTO 10
  178. S15
  179. R7
  180. GOTO 14
  181. R5
  182. GOTO 2
  183. R3
  184. GOTO 10
  185. S15
  186. R7
  187. GOTO 13
  188. R4
  189. GOTO 2
  190. R3
  191. GOTO 10
  192. S15
  193. R7
  194. GOTO 3
  195. R6
  196. GOTO 12
  197. R2
  198. GOTO 10
  199. S15
  200. R7
  201. GOTO 3
  202. R6
  203. GOTO 11
  204. R1
  205. GOTO 10
  206. This line not belongs to this gramma.
  207. Input a line to parse, input blank line to stop.
  208. $123$+($123$-($123$*($123$/($123$)))))
  209. S5
  210. R8
  211. GOTO 3
  212. R6
  213. GOTO 2
  214. R3
  215. GOTO 1
  216. S6
  217. S4
  218. S5
  219. R8
  220. GOTO 3
  221. R6
  222. GOTO 2
  223. R3
  224. GOTO 10
  225. S7
  226. S4
  227. S5
  228. R8
  229. GOTO 3
  230. R6
  231. GOTO 2
  232. S8
  233. S4
  234. S5
  235. R8
  236. GOTO 3
  237. R6
  238. GOTO 2
  239. S9
  240. S4
  241. S5
  242. R8
  243. GOTO 3
  244. R6
  245. GOTO 2
  246. R3
  247. GOTO 10
  248. S15
  249. R7
  250. GOTO 14
  251. R5
  252. GOTO 2
  253. R3
  254. GOTO 10
  255. S15
  256. R7
  257. GOTO 13
  258. R4
  259. GOTO 2
  260. R3
  261. GOTO 10
  262. S15
  263. R7
  264. GOTO 3
  265. R6
  266. GOTO 12
  267. R2
  268. GOTO 10
  269. S15
  270. R7
  271. GOTO 3
  272. R6
  273. GOTO 11
  274. R1
  275. GOTO 1
  276. This line not belongs to this gramma.
  277. Input a line to parse, input blank line to stop.

按下回车输入空行以回到初始界面。

运行截图

  • 文法和带下标的生成式

  • First集、Follow集与DFA状态

  • DFA转移函数

  • SLR(1)分析表

  • 提示信息

  • 解析简单符号串

  • 解析复杂符号串

  • 解析简单表达式

  • 解析复杂表达式

上传的附件 cloud_download 语法分析器的设计与实现-LR.zip ( 9.15kb, 70次下载 )
error_outline 下载需要10点积分

发送私信

如果你想飞,放弃一切让你下降的重量

16
文章数
22
评论数
最近文章
eject