編譯原理——C++版桌面計算器
編譯原理——C++版桌面計算器
系統描述
設計並實現一個桌面計算器,支援基本四則運算,關係運算,可程式設計運算
基本功能
(1)以命令列方式解析使用者輸入的表示式,計算並顯示結果;
(2)支援基本的整型和浮點型別數值計算;
(3)支援用變數和儲存計算結果、變數引用,變數型別需宣告,可根據儲存的資料變化;
擴充套件功能
(1)支援輸出變數型別
(2)支援輸出推導產生式
(3)支援輸出符號表
(4)支援輸出語法分析動作表
(5)支援輸出所有產生式
(6)支援輸出文法first集
(7)支援輸出文法follow集
實現語言和平臺
實現語言:C++
實現平臺:Visual Stdio2019
系統分析與設計
桌面計算器概述
通常來說編譯器應具有詞法分析,語法分析,語義分析,中間程式碼生成,程式碼優化,目的碼生成,符號表,錯誤處理器,這7個部分組成,由於本次實踐目標是一個簡單可程式設計桌面計算器,所以省去了中間程式碼生成,程式碼優化,目的碼生成,三個部分,並將語法分析與語義分析作為一個整體進行程式設計。
使用技術:上下文無關文法,自底向上的語法分析,與LR語法分析器結合的SDT
詞法分析
詞法分析是編譯器的第一部分,詞法分析器讀入字元流並將它們組織成為有意義的lexeme序列。對於每個詞素,詞法分析器產生詞法單元作為輸出,詞法單元格式為:
<token-name,attribute-value>
本編輯器的詞法分析器輸出儲存在out.xml中
本編輯器詞法分析器可識別詞素如下表:
可識別符號表與運算子優先順序表
Type Attribute-value Token-name
常量 Id 1
常量 True 2
常量 False 3
常量 Number 4
資料型別 Integer 5
資料型別 Decimal 6
資料型別 Bool 7
非關鍵字 8
運算子 ( 10
運算子 ) 11
運算子 ! 21
運算子 ++ 22
運算子 – 23
運算子 * 31
運算子 / 32
運算子 % 33
運算子 + 41
運算子 - 42
運算子 < 51
運算子 <= 52
運算子 > 53
運算子 >= 54
運算子 == 61
運算子 != 62
運算子 && 71
運算子 || 81
運算子 = 91
註釋 /**/ 999
結束 ## 1000
1運算子和常量 id,true,false,number,decimal
2括號 ()
3一元運算 +, - !
4算術運算 *,/,%
5算術運算 +,-
6關係運算 <, <=, >, >=
7關係運算 ==, !=
8邏輯與 &&
9邏輯或 ||
10賦值/儲存 =
語法分析
語法分析為編譯器的第二步,語法分析器使用由詞法分析器生成的各個Token結合給定文法進行語法分析,目的是成功由文法推匯出可能的句子,常用方法為語法分析樹,
本次實踐中使用方法為與LR語法分析器結合的SDT,基本思路為,程式先讀入給定文法,求出LR分析表,根據分析表和詞法分析器給的Token,構造語法分析動作表,並將移入規約動作存入Reduce.xml。(程式中$list命令可以輸出語法分析動作表)
CFG
S->L
L->L=H
L->H
H->H||G
H->G
G->G&&F
G->F
F->F!=E
F->F==E
F->E
E->EE<=D
E->E>D
E->E>=D
E->D
D->D-C
D->D+C
D->C
C->C*B
C->C/B
C->C%B
C->B
B->B++
B->B–
B->!B
B->A
A->(H)
A->id
A->true
A->false
A->var
語義分析
語義分析為編譯器的第三步,語義分析器使用語法分析樹和符號表中的資訊來檢查源程式是否和語言定義的語義一致。
根據移入規約動作與Token序列進行求結果,若有變數則去符號表中尋找值
符號表
程式中提供了符號表檢視命令$symbols,符號表由語法分析過程中建立,當程式讀入decimal或integer時進行符號表寫入,初始值設定為0,可以在後續輸入中進行變數賦值
程式碼
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cctype>
#include <vector>
#include <string>
#include <queue>
#include <map>
#include <set>
#include <sstream>
#include <fstream>
#include <cstring>
#include <cstdlib>
#include <stack>
#define _KEY_WORDEND "waiting for your expanding"
#define MAX 507
#define DEBUG
using namespace std;
typedef struct //詞的結構,二元組形式(單詞種別,單詞自身的值)
{
int typenum; //單詞種別
char* word;
}WORD;
char input[255];
char token[255] = "";
int p_input; //指標
int p_token;
char ch;
char* rwtab[] = { "id","true","false","number","integer","decimal","bool",_KEY_WORDEND };//關鍵字
int var_list_symbol[50] = {};//變數型別表
string var_list_name[50] = {};//變數名字表
double var_list_value[50] = {};//變數值
int var_list_size = 0;
bool cout_type = false;
bool cout_induction = false;
bool cout_action = false;
bool cout_list = false;
bool cout_first = false;
bool cout_follow = false;
bool cout_itemset = false;
bool cout_ERROR = false;
WORD* scanner();//掃描
int words(string input_str)
{
ofstream outfile("out.xml", ios::trunc);
int over = 1;
memset(input, 0, sizeof(input) / sizeof(char));
WORD* oneword = new WORD;
for (int i = 0; i < input_str.length(); i++) {
input[i] = input_str[i];
}
p_input = 0;
memset(token, 0, sizeof(token) / sizeof(char));
p_token = 0;
ch = 0;
//printf("your words: %s\n", input);
while (over < 1000 && over != -1)
{
oneword = scanner();
if (oneword->typenum < 1000)
{
if (oneword->typenum != 999)
outfile << oneword->typenum << " " << oneword->word << endl;
}
over = oneword->typenum;
}
outfile.close();
return 0;
}
//從輸入緩衝區讀取一個字元到ch中
char m_getch()
{
ch = input[p_input];
p_input++;
return ch;
}
//去掉空白符號
void getbc()
{
while (ch == ' ' || ch == 10)
{
ch = input[p_input];
p_input++;
}
}
//拼接單詞
void concat()
{
token[p_token] = ch;
p_token++;
token[p_token] = '\0';
}
//判斷是否字母
int letter()
{
if (ch >= 'a' && ch <= 'z' || ch >= 'A' && ch <= 'Z')
return 1;
else
return 0;
}
//判斷是否數字
int digit()
{
if (ch >= '0' && ch <= '9')
return 1;
else if (ch == '.')
return 2;
else
return 0;
}
//檢索關鍵字表格
int reserve()
{
int i = 0;
while (strcmp(rwtab[i], _KEY_WORDEND))
{
if (!strcmp(rwtab[i], token))
return i + 1;
i++;
}
return 8;//如果不是關鍵字,則返回種別碼8
}
//回退一個字元
void retract()
{
p_input--;
}
//詞法掃描程式
WORD* scanner()
{
WORD* myword = new WORD;
myword->typenum = 10; //初始值
myword->word = "";
p_token = 0; //單詞緩衝區指標
m_getch();
getbc();//去掉空白
if (letter())//判斷讀取到的首字母是字母
{
//如int
while (letter() || digit())
{
concat(); //連線
m_getch();
}
retract(); //回退一個字元
myword->typenum = reserve();//判斷是否為關鍵字,返回種別碼
myword->word = token;
return myword;
}
else if (digit()) //判斷讀取到的單詞首字元是數字
{
while (digit()) //所有數字連線起來
{
concat();
m_getch();
}
retract();
//數字單詞種別碼統一為1,單詞自身的值為數字本身
myword->typenum = 1;
myword->word = token;
return(myword);
}
else switch (ch)
{
case '=':
m_getch();//首字元為=,再讀取下一個字元判斷
if (ch == '=')
{
myword->typenum = 61;
myword->word = "==";
return(myword);
}
retract();//讀取到的下個字元不是=,則要回退,直接輸出=
myword->typenum = 91;
myword->word = "=";
return(myword);
break;
case '+':
m_getch();//首字元為+,再讀取下一個字元判斷
if (ch == '+')
{
myword->typenum = 22;
myword->word = "++";
return(myword);
}
retract();//讀取到的下個字元不是+,則要回退,直接輸出+
myword->typenum = 41;
myword->word = "+";
return(myword);
break;
case '-':
m_getch();//首字元為+,再讀取下一個字元判斷
if (ch == '-')
{
myword->typenum = 23;
myword->word = "--";
return(myword);
}
retract();//讀取到的下個字元不是+,則要回退,直接輸出+
myword->typenum = 42;
myword->word = "-";
return(myword);
break;
case '/'://讀取到該符號之後,要判斷下一個字元是什麼符號,判斷是否為註釋
m_getch();//首字元為/,再讀取下一個字元判斷
if (ch == '*') // 說明讀取到的是註釋
{
m_getch();
while (ch != '*')
{
m_getch();//註釋沒結束之前一直讀取註釋,但不輸出
if (ch == '*')
{
m_getch();
if (ch == '/')//註釋結束
{
myword->typenum = 999;
myword->word = "註釋";
return (myword);
break;
}
}
}
}
else
{
retract();//讀取到的下個字元不是*,即不是註釋,則要回退,直接輸出/
myword->typenum = 32;
myword->word = "/";
return (myword);
break;
}
case '*':
myword->typenum = 31;
myword->word = "*";
return(myword);
break;
case '(':
myword->typenum = 10;
myword->word = "(";
return(myword);
break;
case ')':
myword->typenum = 11;
myword->word = ")";
return(myword);
break;
case '%':
myword->typenum = 33;
myword->word = "%";
return(myword);
break;
case '>':
m_getch();
if (ch == '=')
{
myword->typenum = 54;
myword->word = ">=";
return(myword);
break;
}
retract();
myword->typenum = 53;
myword->word = ">";
return(myword);
break;
case '<':
m_getch();
if (ch == '=')
{
myword->typenum = 52;
myword->word = "<=";
return(myword);
break;
}
else
{
retract();
myword->typenum = 51;
myword->word = "<";
return (myword);
}
case '\0':
myword->typenum = 1000;
myword->word = "OVER";
return(myword);
break;
case '&':
m_getch();
if (ch == '&')
{
myword->typenum = 71;
myword->word = "&&";
return(myword);
break;
}
retract();
myword->typenum = -1;
myword->word = "ERROR";
return(myword);
break;
case '|':
m_getch();
if (ch == '|')
{
myword->typenum = 81;
myword->word = "||";
return(myword);
break;
}
retract();
myword->typenum = -1;
myword->word = "ERROR";
return(myword);
break;
case '!':
m_getch();
if (ch == '=')
{
myword->typenum = 62;
myword->word = "!=";
return(myword);
break;
}
else
{
retract();
myword->typenum = 21;
myword->word = "!";
return (myword);
}
case '$':
myword->typenum = 1000;
myword->word = "OVER";
return(myword);
break;
default:
myword->typenum = -1;
myword->word = "ERROR";
return(myword);
break;
}
}
class WF
{
public:
string left, right;
int back;
int id;
WF(char s1[], char s2[], int x, int y)
{
left = s1;
right = s2;
back = x;
id = y;
}
WF(const string& s1, const string& s2, int x, int y)
{
left = s1;
right = s2;
back = x;
id = y;
}
bool operator < (const WF& a) const
{
if (left == a.left)
return right < a.right;
return left < a.left;
}
bool operator == (const WF& a) const
{
return (left == a.left) && (right == a.right);
}
void print()
{
if (cout_itemset)printf("%s->%s\n", left.c_str(), right.c_str());
}
};
class Closure
{
public:
vector<WF> element;
void print(string str)
{
//項集族
if (cout_itemset)
printf("%-15s%-15s\n", "", str.c_str());
for (int i = 0; i < element.size(); i++)
element[i].print();
}
bool operator == (const Closure& a) const
{
if (a.element.size() != element.size()) return false;
for (int i = 0; i < a.element.size(); i++)
if (element[i] == a.element[i]) continue;
else return false;
return true;
}
};
struct Content
{
int type;
int num;
string out;
Content() { type = -1; }
Content(int a, int b)
:type(a), num(b) {}
};
vector<WF> wf;
map<string, vector<int> > dic;
map<string, vector<int> > VN_set;
map<string, bool> vis;
string start = "S";
vector<Closure> collection;
vector<WF> items;
char CH = '$';
int go[MAX][MAX];
int to[MAX];
vector<char> V;
bool used[MAX];
Content action[MAX][MAX];
int Goto[MAX][MAX];
map<string, set<char> > first;
map<string, set<char> > follow;
void make_item()
{
memset(to, -1, sizeof(-1));
for (int i = 0; i < wf.size(); i++)
VN_set[wf[i].left].push_back(i);
for (int i = 0; i < wf.size(); i++)
for (int j = 0; j <= wf[i].right.length(); j++)
{
string temp = wf[i].right;
temp.insert(temp.begin() + j, CH);
dic[wf[i].left].push_back(items.size());
if (j)
to[items.size() - 1] = items.size();
items.push_back(WF(wf[i].left, temp, i, items.size()));
}
#ifdef DEBUG
//puts("-------------------------專案表-------------------------");
//for (int i = 0; i < items.size(); i++)
//printf("%s->%s back:%d id:%d\n", items[i].left.c_str(), items[i].right.c_str(), items[i].back, items[i].id);
//puts("--------------------------------------------------------");
#endif
}
void dfs(const string& x)
{
if (vis[x]) return;
vis[x] = 1;
vector<int>& id = VN_set[x];
for (int i = 0; i < id.size(); i++)
{
string& left = wf[id[i]].left;
string& right = wf[id[i]].right;
for (int j = 0; j < right.length(); j++)
if (isupper(right[j]))
{
dfs(right.substr(j, 1));
set<char>& temp = first[right.substr(j, 1)];
set<char>::iterator it = temp.begin();
bool flag = true;
for (; it != temp.end(); it++)
{
if (*it == '~') flag = false;
first[left].insert(*it);
}
if (flag) break;
}
else
{
first[left].insert(right[j]);
break;
}
}
}
void make_first()
{
vis.clear();
map<string, vector<int> >::iterator it2 = dic.begin();
for (; it2 != dic.end(); it2++)
if (vis[it2->first]) continue;
else dfs(it2->first);
#ifdef DEBUG
if (cout_first)
puts("****************FIRST集***************************");
map<string, set<char> >::iterator it = first.begin();
for (; it != first.end(); it++)
{
if (cout_first)
printf("FIRST(%s)={", it->first.c_str());
set<char>& temp = it->second;
set<char>::iterator it1 = temp.begin();
bool flag = false;
for (; it1 != temp.end(); it1++)
{
if (flag)
if (cout_first)
printf(",");
if (cout_first) printf("%c", *it1);
flag = true;
}
if (cout_first) puts("}");
}
#endif
}
void append(const string& str1, const string& str2)
{
set<char>& from = follow[str1];
set<char>& to = follow[str2];
set<char>::iterator it = from.begin();
for (; it != from.end(); it++)
to.insert(*it);
}
bool _check(const vector<int>& id, const string str)
{
for (int i = 0; i < id.size(); i++)
{
int x = id[i];
if (wf[x].right == str) return true;
}
return false;
}
void make_follow()
{
while (true)
{
bool goon = false;
map<string, vector<int> >::iterator it2 = VN_set.begin();
for (; it2 != VN_set.end(); it2++)
{
vector<int>& id = it2->second;
for (int i = 0; i < id.size(); i++)
{
bool flag = true;
WF& tt = wf[id[i]];
string& left = tt.left;
const string& right = tt.right;
for (int j = right.length() - 1; j >= 0; j--)
if (isupper(right[j]))
{
if (flag)
{
int tx = follow[right.substr(j, 1)].size();
append(left, right.substr(j, 1));
int tx1 = follow[right.substr(j, 1)].size();
if (tx1 > tx) goon = true;
if (_check(id, "~"))
flag = false;
}
for (int k = j + 1; k < right.length(); k++)
if (isupper(right[k]))
{
string idd = right.substr(k, 1);
set<char>& from = first[idd];
set<char>& to = follow[right.substr(j, 1)];
set<char>::iterator it1 = from.begin();
int tx = follow[right.substr(j, 1)].size();
for (; it1 != from.end(); it1++)
if (*it1 != '~')
to.insert(*it1);
int tx1 = follow[right.substr(j, 1)].size();
if (tx1 > tx) goon = true;
if (_check(id, "~"))
break;
}
else
{
int tx = follow[right.substr(j, 1)].size();
follow[right.substr(j, 1)].insert(right[k]);
int tx1 = follow[right.substr(j, 1)].size();
if (tx1 > tx) goon = true;
break;
}
}
else flag = false;
}
}
if (!goon) break;
}
#ifdef DEBUG
if (cout_follow)
puts("***************FOLLOW集*******************");
map<string, set<char> >::iterator it = follow.begin();
for (; it != follow.end(); it++)
{
if (cout_follow)printf("FOLLOW(%s)={", it->first.c_str());
set<char>& temp = it->second;
//if ( it->first[0] == 'S' )
temp.insert('#');
set<char>::iterator it1 = temp.begin();
bool flag = false;
for (; it1 != temp.end(); it1++)
{
if (flag) if (cout_follow)printf(",");
if (cout_follow)printf("%c", *it1);
flag = true;
}
if (cout_follow)puts("}");
}
#endif
}
void make_set()
{
bool has[MAX];
for (int i = 0; i < items.size(); i++)
if (items[i].left[0] == 'S' && items[i].right[0] == CH)
{
Closure temp;
string& str = items[i].right;
vector<WF>& element = temp.element;
element.push_back(items[i]);
int x = 0;
for (x = 0; x < str.length(); x++)
if (str[x] == CH)
break;
memset(has, 0, sizeof(has));
has[i] = 1;
if (x != str.length() - 1)
{
queue<string> q;
q.push(str.substr(x + 1, 1));
while (!q.empty())
{
string u = q.front();
q.pop();
vector<int>& id = dic[u];
for (int j = 0; j < id.size(); j++)
{
int tx = id[j];
if (items[tx].right[0] == CH)
{
if (has[tx]) continue;
has[tx] = 1;
if (isupper(items[tx].right[1]))
q.push(items[tx].right.substr(1, 1));
element.push_back(items[tx]);
}
}
}
}
collection.push_back(temp);
}
for (int i = 0; i < collection.size(); i++)
{
map<int, Closure> temp;
for (int j = 0; j < collection[i].element.size(); j++)
{
string str = collection[i].element[j].right;
int x = 0;
for (; x < str.length(); x++)
if (str[x] == CH) break;
if (x == str.length() - 1)
continue;
int y = str[x + 1];
int ii;
//cout << i << "previous: " << str << endl;
str.erase(str.begin() + x);
str.insert(str.begin() + x + 1, CH);
//cout << i <<"after: " << str << endl;
WF cmp = WF(collection[i].element[j].left, str, -1, -1);
for (int k = 0; k < items.size(); k++)
if (items[k] == cmp)
{
ii = k;
break;
}
//string& str1 = items[ii].right;
memset(has, 0, sizeof(has));
vector<WF>& element = temp[y].element;
element.push_back(items[ii]);
has[ii] = 1;
x++;
if (x != str.length() - 1)
{
queue<string> q;
q.push(str.substr(x + 1, 1));
while (!q.empty())
{
string u = q.front();
q.pop();
vector<int>& id = dic[u];
for (int j = 0; j < id.size(); j++)
{
int tx = id[j];
if (items[tx].right[0] == CH)
{
if (has[tx]) continue;
has[tx] = 1;
if (isupper(items[tx].right[1]))
q.push(items[tx].right.substr(1, 1));
element.push_back(items[tx]);
}
}
}
}
}
map<int, Closure>::iterator it = temp.begin();
for (; it != temp.end(); it++)
collection.push_back(it->second);
for (int i = 0; i < collection.size(); i++)
sort(collection[i].element.begin(), collection[i].element.end());
for (int i = 0; i < collection.size(); i++)
for (int j = i + 1; j < collection.size(); j++)
if (collection[i] == collection[j])
collection.erase(collection.begin() + j);
}
#ifdef DEBUG
//puts("-------------CLOSURE---------------------");
stringstream sin;
for (int i = 0; i < collection.size(); i++)
{
sin.clear();
string out;
sin << "closure-I" << i;
sin >> out;
collection[i].print(out);
}
//puts("");
#endif
}
void make_V()
{
memset(used, 0, sizeof(used));
for (int i = 0; i < wf.size(); i++)
{
string& str = wf[i].left;
for (int j = 0; j < str.length(); j++)
{
if (used[str[j]]) continue;
used[str[j]] = 1;
V.push_back(str[j]);
}
string& str1 = wf[i].right;
for (int j = 0; j < str1.length(); j++)
{
if (used[str1[j]]) continue;
used[str1[j]] = 1;
V.push_back(str1[j]);
}
}
sort(V.begin(), V.end());
V.push_back('#');
}
void make_cmp(vector<WF>& cmp1, int i, char ch)
{
for (int j = 0; j < collection[i].element.size(); j++)
{
string str = collection[i].element[j].right;
int k;
for (k = 0; k < str.length(); k++)
if (str[k] == CH)
break;
if (k != str.length() - 1 && str[k + 1] == ch)
{
str.erase(str.begin() + k);
str.insert(str.begin() + k + 1, CH);
cmp1.push_back(WF(collection[i].element[j].left, str, -1, -1));
}
}
sort(cmp1.begin(), cmp1.end());
}
void make_go()
{
memset(go, -1, sizeof(go));
int m = collection.size();
for (int t = 0; t < V.size(); t++)
{
char ch = V[t];
for (int i = 0; i < m; i++)
{
vector<WF> cmp1;
make_cmp(cmp1, i, ch);
//cout << cmp1.size() << endl;
if (cmp1.size() == 0) continue;
for (int j = 0; j < m; j++)
{
vector<WF> cmp2;
for (int k = 0; k < collection[j].element.size(); k++)
{
string& str = collection[j].element[k].right;
int x;
for (x = 0; x < str.length(); x++)
if (str[x] == CH)
break;
if (x && str[x - 1] == ch)
cmp2.push_back(WF(collection[j].element[k].left, str, -1, -1));
}
sort(cmp2.begin(), cmp2.end());
//cout << cmp2.size() << endl;
bool flag = true;
if (cmp2.size() != cmp1.size()) continue;
//cout << cmp1.size() << endl;
for (int k = 0; k < cmp1.size(); k++)
if (cmp1[k] == cmp2[k]) continue;
else flag = false;
//cout << "out " << endl;
if (flag)
go[i][ch] = j;
}
//cout << "YES" << endl;
}
}
#ifdef DEBUG
//puts("---------------EDGE----------------------");
stringstream sin;
string out;
for (int i = 0; i < m; i++)
for (int j = 0; j < m; j++)
for (int k = 0; k < MAX; k++)
if (go[i][k] == j)
{
sin.clear();
sin << "I" << i << "--" << (char)(k) << "--I" << j;
sin >> out;
//printf("%s\n", out.c_str());
}
#endif
}
void make_table()
{
memset(Goto, -1, sizeof(Goto));
//write s to the table
for (int i = 0; i < collection.size(); i++)
for (int j = 0; j < V.size(); j++)
{
char ch = V[j];
int x = go[i][ch];
if (x == -1) continue;
if (!isupper(ch))
action[i][ch] = Content(0, x);
else
Goto[i][ch] = x;
}
//write r and acc to the table
for (int i = 0; i < collection.size(); i++)
for (int j = 0; j < collection[i].element.size(); j++)
{
WF& tt = collection[i].element[j];
if (tt.right[tt.right.length() - 1] == CH)
{
if (tt.left[0] == 'S')
action[i]['#'] = Content(2, -1);
else
for (int k = 0; k < V.size(); k++)
{
int y = V[k];
//cout << "YES " << endl;
//cout << tt.left << "->" << tt.right << " " << tt.back << endl;
if (!follow[tt.left].count(V[k])) continue;
//cout <<tt.left << "->" << tt.right << " " << i << " " << V[k] << " " << tt.back << endl;
action[i][y] = Content(1, tt.back);
}
}
}
#ifdef DEBUG
if (cout_action) {
puts("------------------------------------------LR(0)分析表--------------------------------------------------------");
printf("%10s%5c%5s", "|", V[0], "|");
for (int i = 1; i < V.size(); i++)
printf("%5c%5s", V[i], "|");
puts("");
for (int i = 0; i < (V.size() + 1) * 10; i++)
printf("-");
puts("");
}
stringstream sin;
for (int i = 0; i < collection.size(); i++)
{
if (cout_action)printf("%5d%5s", i, "|");
for (int j = 0; j < V.size(); j++)
{
char ch = V[j];
if (isupper(ch))
{
if (cout_action) {
if (Goto[i][ch] == -1)
printf("%10s", "|");
else
printf("%5d%5s", Goto[i][ch], "|");
}
}
else
{
sin.clear();
if (action[i][ch].type == -1);
if (cout_action)printf("%10s", "|");
else
{
Content& temp = action[i][ch];
if (temp.type == 0)
sin << "S";
if (temp.type == 1)
sin << "R";
if (temp.type == 2)
sin << "acc";
if (temp.num != -1)
sin << temp.num;
sin >> temp.out;
if (cout_action)printf("%7s%3s", temp.out.c_str(), "|");
}
}
}
if (cout_action)puts("");
}
if (cout_action) {
for (int i = 0; i < (V.size() + 1) * 10; i++)
printf("-");
puts("");
}
#endif
}
void print(string s1, string s2, string s3, string s4, string s5, string s6, string s7)
{
printf("%-15s|%-15s%-15s%-20s|%-15s%-15s%-15s\n", s1.c_str(), s2.c_str(), s3.c_str(), s4.c_str(), s5.c_str(),
s6.c_str(), s7.c_str());
}
string get_steps(int x)
{
stringstream sin;
sin << x;
string ret;
sin >> ret;
return ret;
}
template<class T>
string get_stk(vector<T> stk)
{
stringstream sin;
for (int i = 0; i < stk.size(); i++)
sin << stk[i];
string ret;
sin >> ret;
return ret;
}
string get_shift(WF& temp)
{
stringstream sin;
sin << "reduce(" << temp.left << "->" << temp.right << ")";//推導過程
string out;
sin >> out;
return out;
}
void analyse(string src)
{
ofstream reduce_file("reduce.xml", ios::trunc);
if (cout_list)print("steps", "op-stack", "input", "operation", "state-stack", "ACTION", "GOTO");
vector<char> op_stack;
vector<int> st_stack;
src += "#";
op_stack.push_back('#');
st_stack.push_back(0);
int steps = 1;
for (int i = 0; i < src.length(); i++)
{
char u = src[i];
int top = st_stack[st_stack.size() - 1];
Content& act = action[top][u];
//cout << "YES : " << i << " " << u << " " << top << " " << act.type << endl;
if (act.type == 0)
{
if (cout_list)print(get_steps(steps++), get_stk(op_stack), src.substr(i), "shift", get_stk(st_stack), act.out, "");
op_stack.push_back(u);
st_stack.push_back(act.num);
}
else if (act.type == 1)
{
WF& tt = wf[act.num];
int y = st_stack[st_stack.size() - tt.right.length() - 1];
int x = Goto[y][tt.left[0]];
//cout << y << " " << tt.left[0] << " " << x << endl;
if (cout_induction)
cout << get_shift(tt) << endl;
reduce_file << act.out << endl;
if (cout_list)print(get_steps(steps++), get_stk(op_stack), src.substr(i), get_shift(tt), get_stk(st_stack), act.out, get_steps(x));
for (int j = 0; j < tt.right.length(); j++)
{
st_stack.pop_back();
op_stack.pop_back();
}
op_stack.push_back(tt.left[0]);
st_stack.push_back(x);
i--;
}
else if (act.type == 2)
{
if (cout_list)
print(get_steps(steps++), get_stk(op_stack), src.substr(i), "Accept", get_stk(st_stack), act.out, "");
//i--;
}
else continue;
}
if (op_stack.size() > 2) {
cout << "Error [error:#]" << endl;
cout_ERROR = true;
}
else
cout_ERROR = false;
reduce_file.close();
}
void cout_varlist() {
cout << "符號表" << endl;
for (int i = 0; i < var_list_size; i++) {
if (var_list_symbol[i] == 5)
cout << "[ " << "integer" << " " << var_list_name[i] << " ]" << endl;
else
cout << "[ " << "decimal" << " " << var_list_name[i] << " ]" << endl;
}
}
void add_symbols_txt() {
ofstream outfile("symbols.xml", ios::trunc);
for (int i = 0; i < var_list_size; i++)
outfile << "[ " << var_list_symbol[i] << " " << var_list_name[i] << " " << var_list_value[i] << " ]" << endl;
outfile.close();
return;
}
void add_var(int n, string token_str) {//新增符號表
token_str = token_str.substr(2, token_str.length());
for (int i = 0; i < var_list_size; i++) {
if (var_list_name[i] == token_str)
return;
}
var_list_symbol[var_list_size] = n;
var_list_name[var_list_size] = token_str;
var_list_size++;
add_symbols_txt();
}
string get_tokens() {
string token_temp = "";
string token_temp1 = "";
ifstream file("out.xml");
while (getline(file, token_temp1)) {
int num_token = atoi(token_temp1.c_str());
switch (num_token) {
case 1:token_temp.append("id"); break;
case 2:token_temp.append("true"); break;
case 3:token_temp.append("false"); break;
case 4:token_temp.append("number"); break;
case 5:
getline(file, token_temp1);
if (atoi(token_temp1.c_str()) == 8)
add_var(5, token_temp1);
break;
case 6:
getline(file, token_temp1);
if (atoi(token_temp1.c_str()) == 8)
add_var(6, token_temp1);
break;
case 7:token_temp.append("bool"); break;
case 8:token_temp.append("var"); break;
case 10:token_temp.append("("); break;
case 11:token_temp.append(")"); break;
case 21:token_temp.append("!"); break;
case 22:token_temp.append("++"); break;
case 23:token_temp.append("--"); break;
case 31:token_temp.append("*"); break;
case 32:token_temp.append("/"); break;
case 33:token_temp.append("%"); break;
case 41:token_temp.append("+"); break;
case 42:token_temp.append("-"); break;
case 51:token_temp.append("<"); break;
case 52:token_temp.append("<="); break;
case 53:token_temp.append(">"); break;
case 54:token_temp.append(">="); break;
case 61:token_temp.append("=="); break;
case 62:token_temp.append("!="); break;
case 71:token_temp.append("&&"); break;
case 81:token_temp.append("||"); break;
case 91:token_temp.append("="); break;
case 999:token_temp.append(""); break;
case 1000:token_temp.append(""); break;
}
}
file.close();
return token_temp;
}
void init() {
int n;
char s[MAX];
ifstream myfile("production.xml");
string temp;
getline(myfile, temp);
n = atoi(temp.c_str());
for (int i = 0; i < n; i++)
{
getline(myfile, temp);
int k = 0;
for (k = 0; k < temp.length(); k++) {
s[k] = temp[k];
}
s[k] = '\0';
int len = strlen(s), j;
for (j = 0; j < len; j++)
if (s[j] == '-') break;
s[j] = 0;
wf.push_back(WF(s, s + j + 2, -1, -1));
#ifdef DEBUG
wf[wf.size() - 1].print();
#endif
}
make_item();
make_first();
make_follow();
make_set();
make_V();
make_go();
make_table();
}
void rush_var_list() {
for (int i = 0; i < var_list_size; i++) {
if (var_list_symbol[i] == 5)
var_list_value[i] = int(var_list_value[i]);
}
}
void make_production() {
ifstream production_file("production.xml");
string str;
getline(production_file, str);
while (getline(production_file, str)) {
cout << str << endl;
}
}
void result() {
rush_var_list();
stack<double> result_stack;
ifstream production_file("production.xml");
ifstream token_file("out.xml");
ifstream reduce_file("reduce.xml");
string reduce_str;
string token_str, t;
double num[50];
string str[50];
int _str_size = 0;//非關鍵字指標
int _str_size_now = 0;
int num_ptr = 0;//num最大指標
int reduce_ptr = 0;//reduce棧用到的num當前指標
while (getline(token_file, token_str)) {//token提取數字
stringstream linestream;
linestream.str(token_str);
string first = token_str.substr(0, 1);
int n = atoi(token_str.c_str());
if (n == 1) {
token_str = token_str.substr(1, token_str.length());
double num1 = atof(token_str.c_str());
num[num_ptr] = num1;
num_ptr++;
}
}
token_file.clear();//讀檔案指標回到起始
token_file.seekg(ios_base::beg);
while (getline(token_file, token_str)) {//token提取非關鍵字
stringstream linestream;
linestream.str(token_str);
linestream >> t;
char c = t[0];
int num1 = atoi(t.c_str());
if (num1 == 8) {
str[_str_size] = token_str.substr(2, token_str.length());
_str_size++;
}
}
while (getline(reduce_file, reduce_str)) {
reduce_str = reduce_str.substr(1, reduce_str.length());
int n = atoi(reduce_str.c_str());
n = n + 2;
double a, b;
bool not_found_flag = true;
string symbols_str, symbols_str1;
switch (n) {
//32 尋找符號表中值
case 32:
token_file.clear();//讀檔案指標回到起始
token_file.seekg(ios_base::beg);
getline(token_file, symbols_str);
if (!getline(token_file, symbols_str1)) {
symbols_str = symbols_str.substr(2, symbols_str.length());
for (int i = 0; i < var_list_size; i++) {
if (var_list_name[i] == symbols_str) {
if (cout_type) {
if (var_list_symbol[i] == 6)
cout << "[Decimal, " << var_list_value[i] << "]" << endl;
else if (var_list_symbol[i] == 5)
cout << "[Integer, " << var_list_value[i] << "]" << endl;
}
else
cout << var_list_value[i] << endl;
not_found_flag = false;
}
}
if (not_found_flag)
cout << "Error [undefined identifier:" << symbols_str << "]" << endl;
}
else {
string str_now = str[_str_size_now];
for (int i = 0; i < var_list_size; i++) {
if (var_list_name[i] == str_now) {
result_stack.push(var_list_value[i]);
_str_size_now++;
}
}
}
break;
case 31: result_stack.push(0); break;
case 30: result_stack.push(1); break;
case 29: result_stack.push(num[reduce_ptr]); reduce_ptr++; break;
case 28:break;
case 27:break;
case 26:
a = result_stack.top();
result_stack.pop();
if (a != 0)result_stack.push(0);
else result_stack.push(1);
break;
case 25:
a = result_stack.top();
result_stack.pop();
result_stack.push(a--);
break;
case 24:
a = result_stack.top();
result_stack.pop();
result_stack.push(a++);
break;
case 23:break;
case 22:
a = result_stack.top();
result_stack.pop();
b = result_stack.top();
result_stack.pop();
result_stack.push(int(b) % int(a));
break;
case 21:
a = result_stack.top();
result_stack.pop();
b = result_stack.top();
result_stack.pop();
if (a == 0)result_stack.push(b);
else result_stack.push(b / a);
break;
case 20:
a = result_stack.top();
result_stack.pop();
b = result_stack.top();
result_stack.pop();
result_stack.push(b * a);
break;
case 19:break;
case 18:
a = result_stack.top();
result_stack.pop();
b = result_stack.top();
result_stack.pop();
result_stack.push(a + b);
break;
case 17:
a = result_stack.top();
result_stack.pop();
b = result_stack.top();
result_stack.pop();
result_stack.push(b - a); break;
case 16:break;
case 15:
a = result_stack.top();
result_stack.pop();
b = result_stack.top();
result_stack.pop();
if (b >= a) result_stack.push(1);
else result_stack.push(0); break;
case 14:
a = result_stack.top();
result_stack.pop();
b = result_stack.top();
result_stack.pop();
if (b > a) result_stack.push(1);
else result_stack.push(0); break;
case 13:
a = result_stack.top();
result_stack.pop();
b = result_stack.top();
result_stack.pop();
if (b <= a) result_stack.push(1);
else result_stack.push(0); break;
case 12:
a = result_stack.top();
result_stack.pop();
b = result_stack.top();
result_stack.pop();
if (b < a) result_stack.push(1);
else result_stack.push(0); break;
case 11:break;
case 10:
a = result_stack.top();
result_stack.pop();
b = result_stack.top();
result_stack.pop();
if (b == a) result_stack.push(1);
else result_stack.push(0); break;
case 9:
a = result_stack.top();
result_stack.pop();
b = result_stack.top();
result_stack.pop();
if (b != a) result_stack.push(1);
else result_stack.push(0); break;
case 8:break;
case 7:
a = result_stack.top();
result_stack.pop();
b = result_stack.top();
result_stack.pop();
if (b && a) result_stack.push(1);
else result_stack.push(0); break;
case 6:break;
case 5:
a = result_stack.top();
result_stack.pop();
b = result_stack.top();
result_stack.pop();
if (b || a) result_stack.push(1);
else result_stack.push(0); break;
case 4:break;
case 3:
token_file.clear();//讀檔案指標回到起始
token_file.seekg(ios_base::beg);
getline(token_file, symbols_str);
symbols_str = symbols_str.substr(2, symbols_str.length());
for (int i = 0; i < var_list_size; i++) {
if (var_list_name[i] == symbols_str) {
var_list_value[i] = result_stack.top();
not_found_flag = false;
}
}
if (not_found_flag)
cout << "not found " << symbols_str << endl;
break;
case 2:break;
}
}
if (!result_stack.empty() && !cout_ERROR) {
double result = result_stack.top();
if (result == 1) {
if (cout_type)
cout << "[Bool, true]" << endl;
else
cout << "true" << endl;
}
else if (result == 0) {
if (cout_type)
cout << "[Bool, false]" << endl;
else
cout << "false" << endl;
}
else {
ifstream file1("reduce.xml");
string temp1, temp2;
while (getline(file1, temp1))
temp2 = temp1;
file1.close();
bool flag = true;
if (temp2 == "R1") {//=產生式
flag = false;
}
if (cout_type) {
int result1 = result;
float temp = result1 - result;
if (fabs(temp) < 1e-6) {
if (flag)cout << "[Integer, " << result << "]" << endl;
}
else
if (flag)cout << "[decimal, " << result << "]" << endl;
}
else
if (flag)cout << result << endl;
}
}
production_file.close();
token_file.close();
reduce_file.close();
}
void cout_help() {
cout << "---------------------------------" << endl;
cout << "編輯器中所有變數都需要定義才可使用,資料型別有integer和decimal" << endl;
cout << "可輸入命令如下:預設只輸出值 " << endl;
cout << " $type(輸出型別和值)" << endl;
cout << " $induction(輸出推到產生式)" << endl;
cout << " $symbols(輸出符號表)" << endl;
cout << " $default(恢復預設值)" << endl;
cout << " $first(輸出文法first集)" << endl;
cout << " $follow(輸出文法follow集)" << endl;
cout << " $production(輸出所有產生式)" << endl;
cout << " $help(輸出幫助)" << endl;
cout << " $list(輸出語法分析動作表)" << endl;
cout << " ##(退出)" << endl;
cout << "---------------------------------" << endl;
}
int main()
{
init();
string input_str;
bool flag = true;
cout_help();
while (flag) {
cout << ">>>";
getline(cin, input_str);
if (input_str == "##") {
cout << "quit" << endl;
return 0;
}
else if (input_str == "$symbols") {
cout_varlist();
}
else if (input_str == "$first") {
cout_first = !cout_first;
make_first();
cout_first = !cout_first;
}
else if (input_str == "$follow") {
cout_follow = !cout_follow;
make_follow();
cout_follow = !cout_follow;
}
else if (input_str == "$production") {
make_production();
}
else if (input_str == "$type") {
cout_type = !cout_type;
cout << "$type=" << cout_type << endl;
}
else if (input_str == "$induction") {
cout_induction = !cout_induction;
cout << "$induction=" << cout_induction << endl;
}
else if (input_str == "$default") {
bool cout_type = false;
bool cout_induction = false;
bool cout_action = false;
bool cout_list = false;
bool cout_first = false;
bool cout_follow = false;
bool cout_itemset = false;
bool cout_ERROR = false;
cout << "init" << endl;
}
else if (input_str == "$list") {
cout_list = !cout_list;
cout << "$list=" << cout_list << endl;
}
else if (input_str == "$help") {
cout_help();
}
else {
words(input_str);
analyse(get_tokens());
result();
}
}
return 0;
}
github地址
相關文章
- 表示式編譯計算器(下) (轉)編譯
- 編譯原理實戰入門:用 JavaScript 寫一個簡單的四則運算編譯器(修訂版)編譯原理JavaScript
- C++編譯器優化C++編譯優化
- C++簡易計算器自寫棧版C++
- 編譯原理: FIRST(x) FOLLOW(x) SELECT(x)的計算編譯原理
- 走進Golang之編譯器原理Golang編譯
- 《計算機組成原理/CSAPP》網課總結(二)——編譯原理基礎計算機APP編譯原理
- 名家點評之《編譯器設計(第2版)》編譯
- 編譯原理編譯原理
- 安裝c, c++編譯器 on AIXC++編譯AI
- 小白說編譯原理-7-算術表示式編譯樹(支撐類)編譯原理
- 人人都能讀懂的編譯器原理編譯
- Clojure 執行原理之編譯器剖析編譯
- 編譯器的工作過程和原理編譯
- 關於Basic程式直譯器及編譯原理的簡單化(2)---C++封裝好的Basic直譯器 (轉)C程式編譯原理C++封裝
- Flutter 編譯原理Flutter編譯原理
- 編譯原理概述編譯原理
- Electron 實戰桌面計算器應用
- 簡單版計算器
- C/C++—— C++編譯器是如何實現多型C++編譯多型
- 工程中的編譯原理 -- Mapfile解析器編譯原理
- 【編譯原理】手工打造詞法分析器編譯原理詞法分析
- 【編譯原理】手工打造語法分析器編譯原理語法分析
- C語言編譯器手機版C語言編譯
- 從編譯原理看一個直譯器的實現編譯原理
- 科學計算器學生時代小作品原始碼(C++版)原始碼C++
- 一文搞懂C/C++常用編譯器C++編譯
- Ubuntu16桌面版編譯和安裝OpenCV4Ubuntu編譯OpenCV
- Java語言編寫計算器(簡單的計算器)Java
- VS設定 LLVM-Clang 編譯器進行編譯C++專案LVM編譯C++
- gcc 編譯器與 clang 編譯器GC編譯
- Typescript編譯原理(一)TypeScript編譯原理
- 編譯原理概覽編譯原理
- Vue 模板編譯原理Vue編譯原理
- 白話編譯原理編譯原理
- Calca for mac(文字編輯器/符號計算器) v1.5.1啟用版Mac符號
- 前端與編譯原理——用 JS 寫一個 JS 直譯器前端編譯原理JS
- 前端與編譯原理——用JS寫一個JS直譯器前端編譯原理JS