├── .gitignore ├── LR ├── .gitignore ├── Test │ ├── LR.data3.in │ ├── PL0.pdf │ ├── LR.data.in │ ├── LR.data.pdf │ ├── LR.data2.pdf │ ├── LR.data3.pdf │ ├── PL0_simple.pdf │ ├── LR.data2.in │ ├── PL0.in │ ├── LR.data3.out │ ├── LR.data.out │ └── LR.data2.out ├── Makefile ├── LR.php ├── LR_DFA.cpp ├── LR.h ├── index.html └── LR.cpp ├── LR.gif ├── ll1.gif ├── LL1 ├── Test │ ├── LL1.data3.in │ ├── LL1.data4.in │ ├── LL1.data5.in │ ├── LL1.data2.in │ ├── LL1.data.in │ ├── LL1.data5.out │ ├── LL1.data3.out │ ├── LL1.data4.out │ ├── LL1.data.out │ └── LL1.data2.out ├── Makefile ├── LL1.php ├── LL1.h ├── index.html └── LL1.cpp ├── fork.png ├── lexical.gif ├── Lexical ├── lexical.data.in ├── Makefile ├── lexical.php ├── lexical.data.out ├── lexical.h ├── index.html └── lexical.cpp ├── package.json ├── index.html └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | -------------------------------------------------------------------------------- /LR/.gitignore: -------------------------------------------------------------------------------- 1 | LR 2 | LR_DFA 3 | -------------------------------------------------------------------------------- /LR/Test/LR.data3.in: -------------------------------------------------------------------------------- 1 | S->BB 2 | B->bB|a 3 | # 4 | baba 5 | -------------------------------------------------------------------------------- /LR.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/netcan/compilingTheory/HEAD/LR.gif -------------------------------------------------------------------------------- /ll1.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/netcan/compilingTheory/HEAD/ll1.gif -------------------------------------------------------------------------------- /LL1/Test/LL1.data3.in: -------------------------------------------------------------------------------- 1 | S->aA 2 | S->d 3 | A->bAS 4 | A->@ 5 | # 6 | ababd 7 | -------------------------------------------------------------------------------- /fork.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/netcan/compilingTheory/HEAD/fork.png -------------------------------------------------------------------------------- /lexical.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/netcan/compilingTheory/HEAD/lexical.gif -------------------------------------------------------------------------------- /LR/Test/PL0.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/netcan/compilingTheory/HEAD/LR/Test/PL0.pdf -------------------------------------------------------------------------------- /LL1/Test/LL1.data4.in: -------------------------------------------------------------------------------- 1 | S->pA 2 | S->qB 3 | A->cAd 4 | A->a 5 | B->dB 6 | B->b 7 | # 8 | pccadd 9 | -------------------------------------------------------------------------------- /LL1/Test/LL1.data5.in: -------------------------------------------------------------------------------- 1 | S->Ap 2 | S->Bp 3 | A->a 4 | A->cA 5 | B->b 6 | B->dB 7 | # 8 | ccap 9 | -------------------------------------------------------------------------------- /LR/Test/LR.data.in: -------------------------------------------------------------------------------- 1 | E->E+T 2 | E->T 3 | T->T*F 4 | T->F 5 | F->(E) 6 | F->i 7 | # 8 | i+i*i 9 | -------------------------------------------------------------------------------- /LR/Test/LR.data.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/netcan/compilingTheory/HEAD/LR/Test/LR.data.pdf -------------------------------------------------------------------------------- /LR/Test/LR.data2.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/netcan/compilingTheory/HEAD/LR/Test/LR.data2.pdf -------------------------------------------------------------------------------- /LR/Test/LR.data3.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/netcan/compilingTheory/HEAD/LR/Test/LR.data3.pdf -------------------------------------------------------------------------------- /LL1/Test/LL1.data2.in: -------------------------------------------------------------------------------- 1 | E->TA 2 | A->+TA|@ 3 | T->FB 4 | B->*FB|@ 5 | F->(E)|i 6 | # 7 | i*(i+i)+i 8 | -------------------------------------------------------------------------------- /LR/Test/PL0_simple.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/netcan/compilingTheory/HEAD/LR/Test/PL0_simple.pdf -------------------------------------------------------------------------------- /LL1/Test/LL1.data.in: -------------------------------------------------------------------------------- 1 | E->TG 2 | G->+TG|-TG 3 | G->@ 4 | T->FS 5 | S->*FS|/FS 6 | S->@ 7 | F->(E) 8 | F->i 9 | # 10 | i+i*i 11 | -------------------------------------------------------------------------------- /LR/Test/LR.data2.in: -------------------------------------------------------------------------------- 1 | E->TG 2 | G->+TG|-TG 3 | G->@ 4 | T->FS 5 | S->*FS|/FS 6 | S->@ 7 | F->(E) 8 | F->i 9 | # 10 | i+i*i 11 | -------------------------------------------------------------------------------- /Lexical/lexical.data.in: -------------------------------------------------------------------------------- 1 | void fun() { 2 | int a = 20; 3 | int b=30; 4 | int n = a*b; 5 | for(int i=0; i "$$(echo $$i | sed -r 's/(.*)\.in/\1\.out/')";\ 18 | done 19 | -------------------------------------------------------------------------------- /LR/Makefile: -------------------------------------------------------------------------------- 1 | CXX=clang++ 2 | CFLAGS=-O3 --std=c++11 3 | 4 | all: LR LR_DFA 5 | 6 | LR: LR.cpp 7 | $(CXX) $(CFLAGS) $< -o $@ 8 | 9 | LR_DFA: LR_DFA.cpp LR.cpp 10 | $(CXX) $(CFLAGS) -D_GENERATE_DOT_ $^ -o $@ 11 | 12 | clean: 13 | @rm LR LR_DFA 14 | 15 | test: LR LR_DFA 16 | for i in $$(ls Test/*.in); \ 17 | do\ 18 | ./LR < $$i > "$$(echo $$i | sed -r 's/(.*)\.in/\1\.out/')";\ 19 | ./LR_DFA < $$i | dot -Tpdf -o "$$(echo $$i | sed -r 's/(.*)\.in/\1\.pdf/')";\ 20 | done 21 | -------------------------------------------------------------------------------- /LR/Test/PL0.in: -------------------------------------------------------------------------------- 1 | A->B, 2 | B->CEFH 3 | B->H 4 | B->CH 5 | B->EH 6 | B->FH 7 | B->CFH 8 | B->CEH 9 | B->EFH 10 | C->cY; 11 | D->b=a 12 | E->dX; 13 | F->GB; 14 | G->eb; 15 | H->I 16 | H->R 17 | H->T 18 | H->S 19 | H->U 20 | H->V 21 | H->J 22 | I->btL 23 | J->fWg 24 | K->LQL 25 | K->hL 26 | L->LOM 27 | L->M 28 | L->-M 29 | L->+M 30 | M->MPN 31 | M->N 32 | N->b 33 | N->a 34 | N->(L) 35 | O->+ 36 | O->- 37 | P->* 38 | P->/ 39 | Q->= 40 | Q->% 41 | Q->< 42 | Q->r 43 | Q->> 44 | Q->s 45 | R->pKqH 46 | S->mb 47 | T->nKoH 48 | U->i(X) 49 | V->j(Z) 50 | W->W;H 51 | W->H 52 | X->X,b 53 | X->b 54 | Y->Y,D 55 | Y->D 56 | Z->Z,L 57 | Z->L 58 | # 59 | phaqj(a), 60 | -------------------------------------------------------------------------------- /LR/LR.php: -------------------------------------------------------------------------------- 1 | array("pipe", "r"), // stdin is a pipe that the child will read from 7 | 1 => array("pipe", "w"), // stdout is a pipe that the child will write to 8 | ); 9 | 10 | if (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN') 11 | $process = proc_open('LR', $descriptorspec, $pipes); 12 | else 13 | $process = proc_open('./LR', $descriptorspec, $pipes); 14 | 15 | if(is_resource($process)) { 16 | 17 | fwrite($pipes[0], $data); 18 | fclose($pipes[0]); 19 | 20 | echo stream_get_contents($pipes[1]); 21 | fclose($pipes[1]); 22 | proc_close($process); 23 | } 24 | 25 | 26 | -------------------------------------------------------------------------------- /LL1/LL1.php: -------------------------------------------------------------------------------- 1 | array("pipe", "r"), // stdin is a pipe that the child will read from 7 | 1 => array("pipe", "w"), // stdout is a pipe that the child will write to 8 | ); 9 | 10 | if (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN') 11 | $process = proc_open('LL1', $descriptorspec, $pipes); 12 | else 13 | $process = proc_open('./LL1', $descriptorspec, $pipes); 14 | 15 | if(is_resource($process)) { 16 | 17 | fwrite($pipes[0], $data); 18 | fclose($pipes[0]); 19 | 20 | echo stream_get_contents($pipes[1]); 21 | fclose($pipes[1]); 22 | proc_close($process); 23 | } 24 | 25 | 26 | -------------------------------------------------------------------------------- /Lexical/lexical.php: -------------------------------------------------------------------------------- 1 | array("pipe", "r"), // stdin is a pipe that the child will read from 7 | 1 => array("pipe", "w"), // stdout is a pipe that the child will write to 8 | ); 9 | 10 | if (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN') 11 | $process = proc_open('lexical', $descriptorspec, $pipes); 12 | else 13 | $process = proc_open('./lexical', $descriptorspec, $pipes); 14 | 15 | if(is_resource($process)) { 16 | 17 | fwrite($pipes[0], $data); 18 | fclose($pipes[0]); 19 | 20 | echo "[" . stream_get_contents($pipes[1]) . "]"; 21 | fclose($pipes[1]); 22 | proc_close($process); 23 | } 24 | 25 | 26 | -------------------------------------------------------------------------------- /LL1/Test/LL1.data5.out: -------------------------------------------------------------------------------- 1 | { 2 | "VT": [ "a", "b", "c", "d", "p"], 3 | "VN": [ "A", "B", "S"], 4 | "FIRST": [ 5 | { "noTerminal": "S", "Terminal": [ "a", "b", "c", "d"] } 6 | ,{ "noTerminal": "A", "Terminal": [ "a", "c"] } 7 | ,{ "noTerminal": "B", "Terminal": [ "b", "d"] }], 8 | "FOLLOW": [ 9 | { "noTerminal": "S", "Terminal": [ "#"] } 10 | ,{ "noTerminal": "A", "Terminal": [ "p"] } 11 | ,{ "noTerminal": "B", "Terminal": [ "p"] }], 12 | "Table": { 13 | "Header": ["a", "b", "c", "d", "p", "#"], 14 | "Body": [ {"noTerminal": "S", "production": ["Ap", "Bp", "Ap", "Bp", "", ""]} 15 | , {"noTerminal": "A", "production": ["a", "", "cA", "", "", ""]} 16 | , {"noTerminal": "B", "production": ["", "b", "", "dB", "", ""]} 17 | ] }, 18 | "Parser": [ { "step": 0, "parseStack": "#S", "indataStack": "ccap#", "production": ""} 19 | , { "step": 1, "parseStack": "#pA", "indataStack": "ccap#", "production": "S->Ap"} 20 | , { "step": 2, "parseStack": "#pAc", "indataStack": "ccap#", "production": "A->cA"} 21 | , { "step": 3, "parseStack": "#pA", "indataStack": "cap#", "production": "match c"} 22 | , { "step": 4, "parseStack": "#pAc", "indataStack": "cap#", "production": "A->cA"} 23 | , { "step": 5, "parseStack": "#pA", "indataStack": "ap#", "production": "match c"} 24 | , { "step": 6, "parseStack": "#pa", "indataStack": "ap#", "production": "A->a"} 25 | , { "step": 7, "parseStack": "#p", "indataStack": "p#", "production": "match a"} 26 | , { "step": 8, "parseStack": "#", "indataStack": "#", "production": "match p"} 27 | ] 28 | } 29 | -------------------------------------------------------------------------------- /LL1/Test/LL1.data3.out: -------------------------------------------------------------------------------- 1 | { 2 | "VT": [ "@", "a", "b", "d"], 3 | "VN": [ "A", "S"], 4 | "FIRST": [ 5 | { "noTerminal": "S", "Terminal": [ "a", "d"] } 6 | ,{ "noTerminal": "A", "Terminal": [ "@", "b"] }], 7 | "FOLLOW": [ 8 | { "noTerminal": "S", "Terminal": [ "#", "a", "d"] } 9 | ,{ "noTerminal": "A", "Terminal": [ "#", "a", "d"] }], 10 | "Table": { 11 | "Header": ["a", "b", "d", "#"], 12 | "Body": [ {"noTerminal": "S", "production": ["aA", "", "d", ""]} 13 | , {"noTerminal": "A", "production": ["@", "bAS", "@", "@"]} 14 | ] }, 15 | "Parser": [ { "step": 0, "parseStack": "#S", "indataStack": "ababd#", "production": ""} 16 | , { "step": 1, "parseStack": "#Aa", "indataStack": "ababd#", "production": "S->aA"} 17 | , { "step": 2, "parseStack": "#A", "indataStack": "babd#", "production": "match a"} 18 | , { "step": 3, "parseStack": "#SAb", "indataStack": "babd#", "production": "A->bAS"} 19 | , { "step": 4, "parseStack": "#SA", "indataStack": "abd#", "production": "match b"} 20 | , { "step": 5, "parseStack": "#S", "indataStack": "abd#", "production": "A->@"} 21 | , { "step": 6, "parseStack": "#Aa", "indataStack": "abd#", "production": "S->aA"} 22 | , { "step": 7, "parseStack": "#A", "indataStack": "bd#", "production": "match a"} 23 | , { "step": 8, "parseStack": "#SAb", "indataStack": "bd#", "production": "A->bAS"} 24 | , { "step": 9, "parseStack": "#SA", "indataStack": "d#", "production": "match b"} 25 | , { "step": 10, "parseStack": "#S", "indataStack": "d#", "production": "A->@"} 26 | , { "step": 11, "parseStack": "#d", "indataStack": "d#", "production": "S->d"} 27 | , { "step": 12, "parseStack": "#", "indataStack": "#", "production": "match d"} 28 | ] 29 | } 30 | -------------------------------------------------------------------------------- /LL1/Test/LL1.data4.out: -------------------------------------------------------------------------------- 1 | { 2 | "VT": [ "a", "b", "c", "d", "p", "q"], 3 | "VN": [ "A", "B", "S"], 4 | "FIRST": [ 5 | { "noTerminal": "S", "Terminal": [ "p", "q"] } 6 | ,{ "noTerminal": "A", "Terminal": [ "a", "c"] } 7 | ,{ "noTerminal": "B", "Terminal": [ "b", "d"] }], 8 | "FOLLOW": [ 9 | { "noTerminal": "S", "Terminal": [ "#"] } 10 | ,{ "noTerminal": "A", "Terminal": [ "#", "d"] } 11 | ,{ "noTerminal": "B", "Terminal": [ "#"] }], 12 | "Table": { 13 | "Header": ["a", "b", "c", "d", "p", "q", "#"], 14 | "Body": [ {"noTerminal": "S", "production": ["", "", "", "", "pA", "qB", ""]} 15 | , {"noTerminal": "A", "production": ["a", "", "cAd", "", "", "", ""]} 16 | , {"noTerminal": "B", "production": ["", "b", "", "dB", "", "", ""]} 17 | ] }, 18 | "Parser": [ { "step": 0, "parseStack": "#S", "indataStack": "pccadd#", "production": ""} 19 | , { "step": 1, "parseStack": "#Ap", "indataStack": "pccadd#", "production": "S->pA"} 20 | , { "step": 2, "parseStack": "#A", "indataStack": "ccadd#", "production": "match p"} 21 | , { "step": 3, "parseStack": "#dAc", "indataStack": "ccadd#", "production": "A->cAd"} 22 | , { "step": 4, "parseStack": "#dA", "indataStack": "cadd#", "production": "match c"} 23 | , { "step": 5, "parseStack": "#ddAc", "indataStack": "cadd#", "production": "A->cAd"} 24 | , { "step": 6, "parseStack": "#ddA", "indataStack": "add#", "production": "match c"} 25 | , { "step": 7, "parseStack": "#dda", "indataStack": "add#", "production": "A->a"} 26 | , { "step": 8, "parseStack": "#dd", "indataStack": "dd#", "production": "match a"} 27 | , { "step": 9, "parseStack": "#d", "indataStack": "d#", "production": "match d"} 28 | , { "step": 10, "parseStack": "#", "indataStack": "#", "production": "match d"} 29 | ] 30 | } 31 | -------------------------------------------------------------------------------- /LR/LR_DFA.cpp: -------------------------------------------------------------------------------- 1 | /************************************************************************* 2 | > File Name: LR_DFA.cpp 3 | > Author: Netcan 4 | > Blog: http://www.netcan666.com 5 | > Mail: 1469709759@qq.com 6 | > Created Time: 2016-10-21 五 23:08:06 CST 7 | 8 | __----~~~~~~~~~~~------___ 9 | . . ~~//====...... __--~ ~~ 10 | -. \_|// |||\\ ~~~~~~::::... /~ 11 | ___-==_ _-~o~ \/ ||| \\ _/~~- 12 | __---~~~.==~||\=_ -_--~/_-~|- |\\ \\ _/~ 13 | _-~~ .=~ | \\-_ '-~7 /- / || \ / 14 | .~ .~ | \\ -_ / /- / || \ / 15 | / ____ / | \\ ~-_/ /|- _/ .|| \ / 16 | |~~ ~~|--~~~~--_ \ ~==-/ | \~--===~~ .\ 17 | ' ~-| /| |-~\~~ __--~~ 18 | |-~~-_/ | | ~\_ _-~ /\ 19 | / \ \__ \/~ \__ 20 | _--~ _/ | .-~~____--~-/ ~~==. 21 | ((->/~ '.|||' -_| ~~-/ , . _|| 22 | -_ ~\ ~~---l__i__i__i--~~_/ 23 | _-~-__ ~) \--______________--~~ 24 | //.-~~~-~_--~- |-------~~~~~~~~ 25 | //.-~~~--\ 26 | 神兽保佑,代码无BUG! 27 | ************************************************************************/ 28 | 29 | #include "LR.h" 30 | 31 | int main() { 32 | LR lr; 33 | string in; 34 | while(cin >> in && in != "#") 35 | lr.add(in); 36 | in = ""; 37 | cin >> in; 38 | if(in == "#" || in.size() == 0) return -1; 39 | lr.loadStr(in); 40 | lr.build(); 41 | lr.generateDot(); 42 | } 43 | -------------------------------------------------------------------------------- /LL1/Test/LL1.data.out: -------------------------------------------------------------------------------- 1 | { 2 | "VT": [ "(", ")", "*", "+", "-", "/", "@", "i"], 3 | "VN": [ "E", "F", "G", "S", "T"], 4 | "FIRST": [ 5 | { "noTerminal": "E", "Terminal": [ "(", "i"] } 6 | ,{ "noTerminal": "G", "Terminal": [ "+", "-", "@"] } 7 | ,{ "noTerminal": "T", "Terminal": [ "(", "i"] } 8 | ,{ "noTerminal": "S", "Terminal": [ "*", "/", "@"] } 9 | ,{ "noTerminal": "F", "Terminal": [ "(", "i"] }], 10 | "FOLLOW": [ 11 | { "noTerminal": "E", "Terminal": [ "#", ")"] } 12 | ,{ "noTerminal": "G", "Terminal": [ "#", ")"] } 13 | ,{ "noTerminal": "T", "Terminal": [ "#", ")", "+", "-"] } 14 | ,{ "noTerminal": "S", "Terminal": [ "#", ")", "+", "-"] } 15 | ,{ "noTerminal": "F", "Terminal": [ "#", ")", "*", "+", "-", "/"] }], 16 | "Table": { 17 | "Header": ["(", ")", "*", "+", "-", "/", "i", "#"], 18 | "Body": [ {"noTerminal": "E", "production": ["TG", "", "", "", "", "", "TG", ""]} 19 | , {"noTerminal": "G", "production": ["", "@", "", "+TG", "-TG", "", "", "@"]} 20 | , {"noTerminal": "T", "production": ["FS", "", "", "", "", "", "FS", ""]} 21 | , {"noTerminal": "S", "production": ["", "@", "*FS", "@", "@", "/FS", "", "@"]} 22 | , {"noTerminal": "F", "production": ["(E)", "", "", "", "", "", "i", ""]} 23 | ] }, 24 | "Parser": [ { "step": 0, "parseStack": "#E", "indataStack": "i+i*i#", "production": ""} 25 | , { "step": 1, "parseStack": "#GT", "indataStack": "i+i*i#", "production": "E->TG"} 26 | , { "step": 2, "parseStack": "#GSF", "indataStack": "i+i*i#", "production": "T->FS"} 27 | , { "step": 3, "parseStack": "#GSi", "indataStack": "i+i*i#", "production": "F->i"} 28 | , { "step": 4, "parseStack": "#GS", "indataStack": "+i*i#", "production": "match i"} 29 | , { "step": 5, "parseStack": "#G", "indataStack": "+i*i#", "production": "S->@"} 30 | , { "step": 6, "parseStack": "#GT+", "indataStack": "+i*i#", "production": "G->+TG"} 31 | , { "step": 7, "parseStack": "#GT", "indataStack": "i*i#", "production": "match +"} 32 | , { "step": 8, "parseStack": "#GSF", "indataStack": "i*i#", "production": "T->FS"} 33 | , { "step": 9, "parseStack": "#GSi", "indataStack": "i*i#", "production": "F->i"} 34 | , { "step": 10, "parseStack": "#GS", "indataStack": "*i#", "production": "match i"} 35 | , { "step": 11, "parseStack": "#GSF*", "indataStack": "*i#", "production": "S->*FS"} 36 | , { "step": 12, "parseStack": "#GSF", "indataStack": "i#", "production": "match *"} 37 | , { "step": 13, "parseStack": "#GSi", "indataStack": "i#", "production": "F->i"} 38 | , { "step": 14, "parseStack": "#GS", "indataStack": "#", "production": "match i"} 39 | , { "step": 15, "parseStack": "#G", "indataStack": "#", "production": "S->@"} 40 | , { "step": 16, "parseStack": "#", "indataStack": "#", "production": "G->@"} 41 | ] 42 | } 43 | -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Compile Theory courses design by netcan 5 | 6 | 7 | 8 | 9 | 10 |
11 |

Compile Theory courses design by netcan

12 |
13 |
14 |
15 |
16 |
17 |
18 | 词法分析器 19 |
20 |
21 | 实验一 22 |
23 |
24 | 用 C++ 语言实现对 C 语言子集的源程序进行词法分析。通过输入源程序从左到右对字符串进行扫描和分解,依次输出各个单词的内部编码及单词符号自身值;若遇到错误则显示“Error”,然后跳过错误部分继续显示 ;同时进行标识符登记符号表的管理。 25 |
26 |
27 | 28 |
29 | 30 | 查看 31 |
32 |
33 |
34 |
35 | 36 |
37 |
38 |
39 |
40 | LL1预测分析 41 |
42 |
43 | 实验二 44 |
45 |
46 |
    47 |
  • 48 | 根据任意文法编制调试 LL ( 1 )分析程序,以便对任意输入的符号串进行分析。 49 |
  • 50 |
  • 51 | 构造预测分析表,并利用分析表和一个栈来实现对上述程序设计语言的分析程序。 52 |
  • 53 |
  • 54 | 分析法的功能是利用 LL(1)控制程序根据显示栈栈顶内容、向前看符号以及 LL(1)分析表,对输入符号串自上而下的分析过程。 55 |
  • 56 |
57 |
58 |
59 | 60 |
61 | 62 | 查看 63 |
64 |
65 |
66 |
67 | 68 |
69 |
70 |
71 |
72 | LR(1)分析器 73 |
74 |
75 | 实验三 76 |
77 |
78 | 构造 LR(1)分析程序,利用它进行语法分析,判断给出的符号串是否为该文法识别的句子,了解 LR(K)分析方法是严格的从左向右扫描,和自底向上的语法分析方法。 79 |
80 |
81 | 82 |
83 | 84 | 查看 85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 | 93 | 94 | -------------------------------------------------------------------------------- /LR/Test/LR.data3.out: -------------------------------------------------------------------------------- 1 | {"Grammar": [ 2 | "S->BB", "B->bB", "B->a" 3 | ] 4 | ,"parseTable": { 5 | "Vt": ["a", "b", "#"], 6 | "Vn": [ "B", "S"], 7 | "Body": [ 8 | [ "s3", "s4", "", 1, 2] 9 | , [ "s6", "s7", "", 5, ""] 10 | , [ "", "", "acc", "", ""] 11 | , [ "r2", "r2", "", "", ""] 12 | , [ "s3", "s4", "", 8, ""] 13 | , [ "", "", "r0", "", ""] 14 | , [ "", "", "r2", "", ""] 15 | , [ "s6", "s7", "", 9, ""] 16 | , [ "r1", "r1", "", "", ""] 17 | , [ "", "", "r1", "", ""] 18 | ]} 19 | ,"Graph": {"All": "digraph all{node [shape=box style=filled];Grammar[style=rounded label=\"Grammar\nS->BB\nB->bB\nB->a\n\" ];\nI0[label=\"I0\nS'->.S,#\nS->.BB,#\nB->.bB,a|b\nB->.a,a|b\n\" ];\nI1[label=\"I1\nS->B.B,#\nB->.bB,#\nB->.a,#\n\" ];\nI2[label=\"I2\nS'->S.,#\n\" ];\nI3[label=\"I3\nB->a.,a|b\n\" ];\nI4[label=\"I4\nB->b.B,a|b\nB->.bB,a|b\nB->.a,a|b\n\" ];\nI5[label=\"I5\nS->BB.,#\n\" ];\nI6[label=\"I6\nB->a.,#\n\" ];\nI7[label=\"I7\nB->b.B,#\nB->.bB,#\nB->.a,#\n\" ];\nI8[label=\"I8\nB->bB.,a|b\n\" ];\nI9[label=\"I9\nB->bB.,#\n\" ];\nI0 -> I1[label=\"B\"];I0 -> I2[label=\"S\"];I0 -> I3[label=\"a\"];I0 -> I4[label=\"b\"];I1 -> I5[label=\"B\"];I1 -> I6[label=\"a\"];I1 -> I7[label=\"b\"];I4 -> I8[label=\"B\"];I4 -> I3[label=\"a\"];I4 -> I4[label=\"b\"];I7 -> I9[label=\"B\"];I7 -> I6[label=\"a\"];I7 -> I7[label=\"b\"];Grammar -> I0[style=invis];}" 20 | , "Simple": "digraph simple {node [shape = circle style=filled];Grammar[shape=box style=rounded label=\"Grammar\nS->BB\nB->bB\nB->a\n\" ];\nI0[tooltip=\"I0\nS'->.S,#\nS->.BB,#\nB->.bB,a|b\nB->.a,a|b\n\" ];\nI1[tooltip=\"I1\nS->B.B,#\nB->.bB,#\nB->.a,#\n\" ];\nI2[tooltip=\"I2\nS'->S.,#\n\" ];\nI3[tooltip=\"I3\nB->a.,a|b\n\" ];\nI4[tooltip=\"I4\nB->b.B,a|b\nB->.bB,a|b\nB->.a,a|b\n\" ];\nI5[tooltip=\"I5\nS->BB.,#\n\" ];\nI6[tooltip=\"I6\nB->a.,#\n\" ];\nI7[tooltip=\"I7\nB->b.B,#\nB->.bB,#\nB->.a,#\n\" ];\nI8[tooltip=\"I8\nB->bB.,a|b\n\" ];\nI9[tooltip=\"I9\nB->bB.,#\n\" ];\nI0 -> I1[label=\"B\"];I0 -> I2[label=\"S\"];I0 -> I3[label=\"a\"];I0 -> I4[label=\"b\"];I1 -> I5[label=\"B\"];I1 -> I6[label=\"a\"];I1 -> I7[label=\"b\"];I4 -> I8[label=\"B\"];I4 -> I3[label=\"a\"];I4 -> I4[label=\"b\"];I7 -> I9[label=\"B\"];I7 -> I6[label=\"a\"];I7 -> I7[label=\"b\"];Grammar -> I0[style=invis];}"}, 21 | "parser": [ 22 | {"statusStack": " 0 ", "parseStack": "", "inStrStack": "baba#", "action": "SHIFT"} 23 | , {"statusStack": " 0 4 ", "parseStack": "b", "inStrStack": "aba#", "action": "SHIFT"} 24 | , {"statusStack": " 0 4 3 ", "parseStack": "ba", "inStrStack": "ba#", "action": "REDUCE B->a"} 25 | , {"statusStack": " 0 4 8 ", "parseStack": "bB", "inStrStack": "ba#", "action": "REDUCE B->bB"} 26 | , {"statusStack": " 0 1 ", "parseStack": "B", "inStrStack": "ba#", "action": "SHIFT"} 27 | , {"statusStack": " 0 1 7 ", "parseStack": "Bb", "inStrStack": "a#", "action": "SHIFT"} 28 | , {"statusStack": " 0 1 7 6 ", "parseStack": "Bba", "inStrStack": "#", "action": "REDUCE B->a"} 29 | , {"statusStack": " 0 1 7 9 ", "parseStack": "BbB", "inStrStack": "#", "action": "REDUCE B->bB"} 30 | , {"statusStack": " 0 1 5 ", "parseStack": "BB", "inStrStack": "#", "action": "REDUCE S->BB"} 31 | , {"statusStack": " 0 2 ", "parseStack": "S", "inStrStack": "#", "action": "ACCEPT"}] 32 | } 33 | -------------------------------------------------------------------------------- /LL1/LL1.h: -------------------------------------------------------------------------------- 1 | /************************************************************************* 2 | > File Name: LL1.h 3 | > Author: Netcan 4 | > Blog: http://www.netcan666.com 5 | > Mail: 1469709759@qq.com 6 | > Created Time: 2016-10-11 二 23:18:13 CST 7 | 8 | __----~~~~~~~~~~~------___ 9 | . . ~~//====...... __--~ ~~ 10 | -. \_|// |||\\ ~~~~~~::::... /~ 11 | ___-==_ _-~o~ \/ ||| \\ _/~~- 12 | __---~~~.==~||\=_ -_--~/_-~|- |\\ \\ _/~ 13 | _-~~ .=~ | \\-_ '-~7 /- / || \ / 14 | .~ .~ | \\ -_ / /- / || \ / 15 | / ____ / | \\ ~-_/ /|- _/ .|| \ / 16 | |~~ ~~|--~~~~--_ \ ~==-/ | \~--===~~ .\ 17 | ' ~-| /| |-~\~~ __--~~ 18 | |-~~-_/ | | ~\_ _-~ /\ 19 | / \ \__ \/~ \__ 20 | _--~ _/ | .-~~____--~-/ ~~==. 21 | ((->/~ '.|||' -_| ~~-/ , . _|| 22 | -_ ~\ ~~---l__i__i__i--~~_/ 23 | _-~-__ ~) \--______________--~~ 24 | //.-~~~-~_--~- |-------~~~~~~~~ 25 | //.-~~~--\ 26 | 神兽保佑,代码无BUG! 27 | *************************************************************************/ 28 | 29 | #ifndef LL1_H 30 | #define LL1_H 31 | 32 | #include 33 | #include 34 | #include 35 | #include 36 | #include 37 | #include 38 | #include 39 | using namespace std; 40 | 41 | class Prod { // 产生式 42 | friend class LL1; 43 | private: 44 | string prod; // 产生式 45 | char noTerminal; // 产生式左部非终结符名字 46 | set selection; // 候选式集合 47 | set Vn; // 非终结符 48 | set Vt; // 终结符 49 | string cut(int i, int j) { 50 | return string(prod.begin() + i, prod.begin() + j); 51 | } 52 | friend bool operator == (const Prod &a, const char &c) { 53 | return a.noTerminal == c; 54 | } 55 | 56 | bool isValid; // 产生式是否合法 57 | 58 | public: 59 | Prod(const string &in); 60 | bool split(); // 分割终结符、非终结符、产生式集合、左部非终结符名字,返回分割是否成功 61 | }; 62 | 63 | class LL1 { 64 | private: vector G; // 文法G 65 | set VN; // 非终结符 66 | set VT; // 终结符 67 | map > FIRST; // first集 68 | map > FOLLOW; // follow集 69 | map, string> M; // 分析表 70 | set first(const string &s); 71 | void follow(); 72 | vector parse; // 分析栈 73 | vector indata; // 输入表达式栈 74 | void parseTable(); 75 | public: 76 | bool addProd(const Prod & prod); // 添加产生式 77 | void info(); // 输出相关结果 78 | void tableInfo(); // 输出表 79 | void build(); // 建立first、follow集、分析表 80 | void showIndataStack(); // 输出输入串内容 81 | void showParseStack(); // 输出分析栈内容 82 | void loadIndata(const string &s); // 输入串入栈 83 | void parser(); // LL1预测分析 84 | void error(int step); // 错误处理 85 | void run(); // 运行LL1 86 | }; 87 | 88 | #endif 89 | -------------------------------------------------------------------------------- /Lexical/lexical.data.out: -------------------------------------------------------------------------------- 1 | {"word": "void", "tuple": [1, 23], "type": "KEY", "pos": [1, 1]} 2 | , {"word": "fun", "tuple": [6, 1], "type": "ID", "pos": [1, 6]} 3 | , {"word": "(", "tuple": [2, 2], "type": "DELIMITER", "pos": [1, 9]} 4 | , {"word": ")", "tuple": [2, 3], "type": "DELIMITER", "pos": [1, 10]} 5 | , {"word": "{", "tuple": [2, 6], "type": "DELIMITER", "pos": [1, 12]} 6 | , {"word": "int", "tuple": [1, 2], "type": "KEY", "pos": [2, 2]} 7 | , {"word": "a", "tuple": [6, 2], "type": "ID", "pos": [2, 6]} 8 | , {"word": "=", "tuple": [4, 21], "type": "RELATIONOPTR", "pos": [2, 8]} 9 | , {"word": "20", "tuple": [5, 1], "type": "NUMBER", "pos": [2, 10]} 10 | , {"word": ";", "tuple": [2, 1], "type": "DELIMITER", "pos": [2, 12]} 11 | , {"word": "int", "tuple": [1, 2], "type": "KEY", "pos": [3, 2]} 12 | , {"word": "b", "tuple": [6, 3], "type": "ID", "pos": [3, 6]} 13 | , {"word": "=", "tuple": [4, 21], "type": "RELATIONOPTR", "pos": [3, 7]} 14 | , {"word": "30", "tuple": [5, 2], "type": "NUMBER", "pos": [3, 8]} 15 | , {"word": ";", "tuple": [2, 1], "type": "DELIMITER", "pos": [3, 10]} 16 | , {"word": "int", "tuple": [1, 2], "type": "KEY", "pos": [4, 2]} 17 | , {"word": "n", "tuple": [6, 4], "type": "ID", "pos": [4, 6]} 18 | , {"word": "=", "tuple": [4, 21], "type": "RELATIONOPTR", "pos": [4, 8]} 19 | , {"word": "a", "tuple": [6, 2], "type": "ID", "pos": [4, 10]} 20 | , {"word": "*", "tuple": [3, 10], "type": "ARITHMETICOPTR", "pos": [4, 11]} 21 | , {"word": "b", "tuple": [6, 3], "type": "ID", "pos": [4, 12]} 22 | , {"word": ";", "tuple": [2, 1], "type": "DELIMITER", "pos": [4, 13]} 23 | , {"word": "for", "tuple": [1, 21], "type": "KEY", "pos": [5, 2]} 24 | , {"word": "(", "tuple": [2, 2], "type": "DELIMITER", "pos": [5, 5]} 25 | , {"word": "int", "tuple": [1, 2], "type": "KEY", "pos": [5, 6]} 26 | , {"word": "i", "tuple": [6, 5], "type": "ID", "pos": [5, 10]} 27 | , {"word": "=", "tuple": [4, 21], "type": "RELATIONOPTR", "pos": [5, 11]} 28 | , {"word": "0", "tuple": [5, 3], "type": "NUMBER", "pos": [5, 12]} 29 | , {"word": ";", "tuple": [2, 1], "type": "DELIMITER", "pos": [5, 13]} 30 | , {"word": "i", "tuple": [6, 5], "type": "ID", "pos": [5, 15]} 31 | , {"word": "<", "tuple": [4, 17], "type": "RELATIONOPTR", "pos": [5, 16]} 32 | , {"word": "n", "tuple": [6, 4], "type": "ID", "pos": [5, 17]} 33 | , {"word": ";", "tuple": [2, 1], "type": "DELIMITER", "pos": [5, 18]} 34 | , {"word": "++", "tuple": [3, 13], "type": "ARITHMETICOPTR", "pos": [5, 20]} 35 | , {"word": "i", "tuple": [6, 5], "type": "ID", "pos": [5, 22]} 36 | , {"word": ")", "tuple": [2, 3], "type": "DELIMITER", "pos": [5, 23]} 37 | , {"word": "{", "tuple": [2, 6], "type": "DELIMITER", "pos": [5, 25]} 38 | , {"word": "if", "tuple": [1, 29], "type": "KEY", "pos": [6, 3]} 39 | , {"word": "(", "tuple": [2, 2], "type": "DELIMITER", "pos": [6, 5]} 40 | , {"word": "i", "tuple": [6, 5], "type": "ID", "pos": [6, 6]} 41 | , {"word": "%", "tuple": [3, 12], "type": "ARITHMETICOPTR", "pos": [6, 7]} 42 | , {"word": "30", "tuple": [5, 2], "type": "NUMBER", "pos": [6, 8]} 43 | , {"word": "==", "tuple": [4, 19], "type": "RELATIONOPTR", "pos": [6, 11]} 44 | , {"word": "0", "tuple": [5, 3], "type": "NUMBER", "pos": [6, 14]} 45 | , {"word": ")", "tuple": [2, 3], "type": "DELIMITER", "pos": [6, 15]} 46 | , {"word": "break", "tuple": [1, 4], "type": "KEY", "pos": [6, 17]} 47 | , {"word": ";", "tuple": [2, 1], "type": "DELIMITER", "pos": [6, 22]} 48 | , {"word": "else", "tuple": [1, 5], "type": "KEY", "pos": [7, 3]} 49 | , {"word": "continue", "tuple": [1, 20], "type": "KEY", "pos": [7, 8]} 50 | , {"word": ";", "tuple": [2, 1], "type": "DELIMITER", "pos": [7, 16]} 51 | , {"word": "}", "tuple": [2, 7], "type": "DELIMITER", "pos": [8, 2]} 52 | , {"word": "}", "tuple": [2, 7], "type": "DELIMITER", "pos": [9, 1]} 53 | -------------------------------------------------------------------------------- /LL1/Test/LL1.data2.out: -------------------------------------------------------------------------------- 1 | { 2 | "VT": [ "(", ")", "*", "+", "@", "i"], 3 | "VN": [ "A", "B", "E", "F", "T"], 4 | "FIRST": [ 5 | { "noTerminal": "E", "Terminal": [ "(", "i"] } 6 | ,{ "noTerminal": "A", "Terminal": [ "+", "@"] } 7 | ,{ "noTerminal": "T", "Terminal": [ "(", "i"] } 8 | ,{ "noTerminal": "B", "Terminal": [ "*", "@"] } 9 | ,{ "noTerminal": "F", "Terminal": [ "(", "i"] }], 10 | "FOLLOW": [ 11 | { "noTerminal": "E", "Terminal": [ "#", ")"] } 12 | ,{ "noTerminal": "A", "Terminal": [ "#", ")"] } 13 | ,{ "noTerminal": "T", "Terminal": [ "#", ")", "+"] } 14 | ,{ "noTerminal": "B", "Terminal": [ "#", ")", "+"] } 15 | ,{ "noTerminal": "F", "Terminal": [ "#", ")", "*", "+"] }], 16 | "Table": { 17 | "Header": ["(", ")", "*", "+", "i", "#"], 18 | "Body": [ {"noTerminal": "E", "production": ["TA", "", "", "", "TA", ""]} 19 | , {"noTerminal": "A", "production": ["", "@", "", "+TA", "", "@"]} 20 | , {"noTerminal": "T", "production": ["FB", "", "", "", "FB", ""]} 21 | , {"noTerminal": "B", "production": ["", "@", "*FB", "@", "", "@"]} 22 | , {"noTerminal": "F", "production": ["(E)", "", "", "", "i", ""]} 23 | ] }, 24 | "Parser": [ { "step": 0, "parseStack": "#E", "indataStack": "i*(i+i)+i#", "production": ""} 25 | , { "step": 1, "parseStack": "#AT", "indataStack": "i*(i+i)+i#", "production": "E->TA"} 26 | , { "step": 2, "parseStack": "#ABF", "indataStack": "i*(i+i)+i#", "production": "T->FB"} 27 | , { "step": 3, "parseStack": "#ABi", "indataStack": "i*(i+i)+i#", "production": "F->i"} 28 | , { "step": 4, "parseStack": "#AB", "indataStack": "*(i+i)+i#", "production": "match i"} 29 | , { "step": 5, "parseStack": "#ABF*", "indataStack": "*(i+i)+i#", "production": "B->*FB"} 30 | , { "step": 6, "parseStack": "#ABF", "indataStack": "(i+i)+i#", "production": "match *"} 31 | , { "step": 7, "parseStack": "#AB)E(", "indataStack": "(i+i)+i#", "production": "F->(E)"} 32 | , { "step": 8, "parseStack": "#AB)E", "indataStack": "i+i)+i#", "production": "match ("} 33 | , { "step": 9, "parseStack": "#AB)AT", "indataStack": "i+i)+i#", "production": "E->TA"} 34 | , { "step": 10, "parseStack": "#AB)ABF", "indataStack": "i+i)+i#", "production": "T->FB"} 35 | , { "step": 11, "parseStack": "#AB)ABi", "indataStack": "i+i)+i#", "production": "F->i"} 36 | , { "step": 12, "parseStack": "#AB)AB", "indataStack": "+i)+i#", "production": "match i"} 37 | , { "step": 13, "parseStack": "#AB)A", "indataStack": "+i)+i#", "production": "B->@"} 38 | , { "step": 14, "parseStack": "#AB)AT+", "indataStack": "+i)+i#", "production": "A->+TA"} 39 | , { "step": 15, "parseStack": "#AB)AT", "indataStack": "i)+i#", "production": "match +"} 40 | , { "step": 16, "parseStack": "#AB)ABF", "indataStack": "i)+i#", "production": "T->FB"} 41 | , { "step": 17, "parseStack": "#AB)ABi", "indataStack": "i)+i#", "production": "F->i"} 42 | , { "step": 18, "parseStack": "#AB)AB", "indataStack": ")+i#", "production": "match i"} 43 | , { "step": 19, "parseStack": "#AB)A", "indataStack": ")+i#", "production": "B->@"} 44 | , { "step": 20, "parseStack": "#AB)", "indataStack": ")+i#", "production": "A->@"} 45 | , { "step": 21, "parseStack": "#AB", "indataStack": "+i#", "production": "match )"} 46 | , { "step": 22, "parseStack": "#A", "indataStack": "+i#", "production": "B->@"} 47 | , { "step": 23, "parseStack": "#AT+", "indataStack": "+i#", "production": "A->+TA"} 48 | , { "step": 24, "parseStack": "#AT", "indataStack": "i#", "production": "match +"} 49 | , { "step": 25, "parseStack": "#ABF", "indataStack": "i#", "production": "T->FB"} 50 | , { "step": 26, "parseStack": "#ABi", "indataStack": "i#", "production": "F->i"} 51 | , { "step": 27, "parseStack": "#AB", "indataStack": "#", "production": "match i"} 52 | , { "step": 28, "parseStack": "#A", "indataStack": "#", "production": "B->@"} 53 | , { "step": 29, "parseStack": "#", "indataStack": "#", "production": "A->@"} 54 | ] 55 | } 56 | -------------------------------------------------------------------------------- /Lexical/lexical.h: -------------------------------------------------------------------------------- 1 | /************************************************************************* 2 | > File Name: lexical.h 3 | > Author: Netcan 4 | > Blog: http://www.netcan666.com 5 | > Mail: 1469709759@qq.com 6 | > Created Time: 2016-10-06 四 10:05:08 CST 7 | 8 | __----~~~~~~~~~~~------___ 9 | . . ~~//====...... __--~ ~~ 10 | -. \_|// |||\\ ~~~~~~::::... /~ 11 | ___-==_ _-~o~ \/ ||| \\ _/~~- 12 | __---~~~.==~||\=_ -_--~/_-~|- |\\ \\ _/~ 13 | _-~~ .=~ | \\-_ '-~7 /- / || \ / 14 | .~ .~ | \\ -_ / /- / || \ / 15 | / ____ / | \\ ~-_/ /|- _/ .|| \ / 16 | |~~ ~~|--~~~~--_ \ ~==-/ | \~--===~~ .\ 17 | ' ~-| /| |-~\~~ __--~~ 18 | |-~~-_/ | | ~\_ _-~ /\ 19 | / \ \__ \/~ \__ 20 | _--~ _/ | .-~~____--~-/ ~~==. 21 | ((->/~ '.|||' -_| ~~-/ , . _|| 22 | -_ ~\ ~~---l__i__i__i--~~_/ 23 | _-~-__ ~) \--______________--~~ 24 | //.-~~~-~_--~- |-------~~~~~~~~ 25 | //.-~~~--\ 26 | 神兽保佑,代码无BUG! 27 | ************************************************************************/ 28 | 29 | #ifndef LEXICAL_H 30 | #define LEXICAL_H 31 | #include 32 | #include 33 | #include 34 | #include 35 | #include 36 | #include 37 | using namespace std; 38 | 39 | struct Trie { 40 | Trie *next[26]; 41 | bool isEnd; // 字符串是否是结尾 42 | int loc; // 字符串的位置 43 | Trie() { 44 | isEnd = false; 45 | for(int i=0; i<26; ++i) next[i] = NULL; 46 | } 47 | }; 48 | 49 | class Key { // 存放关键字数据结构,采用字典树结构 50 | private: 51 | Trie *root; 52 | public: 53 | Key() { 54 | root = new Trie(); 55 | } 56 | void add(const string &str, int loc); // 添加关键字 57 | void add(vector strs); 58 | int find(const string &str); // 查找关键字 59 | void free(Trie *p); // 释放关键字 60 | ~Key() { // 释放关键字 61 | free(root); 62 | } 63 | }; 64 | 65 | enum Type { 66 | ERROR = 0, 67 | KEY, 68 | DELIMITER, 69 | ARITHMETICOPTR, 70 | RELATIONOPTR, 71 | NUMBER, 72 | ID, 73 | CHAR, 74 | STRING, 75 | COMMENT 76 | }; 77 | 78 | struct Symbol { 79 | Type type; 80 | string optr; 81 | Symbol(Type type,string optr) : type(type), optr(optr) {}; 82 | friend bool operator==(const Symbol &a,const Symbol &b) { 83 | return a.optr == b.optr; 84 | } 85 | }; 86 | 87 | class Lexical { // 词法分析 88 | private: 89 | Key keys; // 关键字 90 | vector > optrs; // 运算符 91 | vector > indetifiers; // 标识符 92 | vector > constants; // 常量 93 | vector > strings; // 字符串 94 | vector > chars; // 字符 95 | unsigned int row, column; 96 | bool isFirst; // 输出的第一个结果 97 | string in; // 输入程序 98 | static const char* typeStr[]; 99 | 100 | string cut(int i, int j); // 截取in的字符串[i, j) 101 | public: 102 | Lexical(); 103 | bool isKey(const string &str); // 是否为关键字 104 | int getKeyPointer(const string &str); 105 | bool isOptr(const string &str); // 是否为运算符 106 | int getOptrPointer(const string &str); // 查找运算符位置 107 | Type getOptrType(const string &str); // 查找运算符类型 108 | bool isId(const string &str); // 是否为标识符 109 | int getIDPointer(const string &str); 110 | bool isNum(const string &str); // 是否数值 111 | int getNumPointer(const string &str); 112 | bool isString(const string &str); // 是否字符串 113 | int getStringPointer(const string &str); 114 | bool isChar(const string &str); // 是否字符 115 | int getCharPointer(const string &str); 116 | bool getIn(); 117 | void analysis(); 118 | void run(); 119 | }; 120 | 121 | const char *Lexical::typeStr[] = { 122 | "ERROR", 123 | "KEY", 124 | "DELIMITER", 125 | "ARITHMETICOPTR", 126 | "RELATIONOPTR", 127 | "NUMBER", 128 | "IDENTIFIER", 129 | "CHAR", 130 | "STRING", 131 | "COMMENT" 132 | }; 133 | 134 | #endif 135 | -------------------------------------------------------------------------------- /LR/LR.h: -------------------------------------------------------------------------------- 1 | /************************************************************************* 2 | > File Name: LR.h 3 | > Author: Netcan 4 | > Blog: http://www.netcan666.com 5 | > Mail: 1469709759@qq.com 6 | > Created Time: 2016-10-19 三 08:36:05 CST 7 | 8 | __----~~~~~~~~~~~------___ 9 | . . ~~//====...... __--~ ~~ 10 | -. \_|// |||\\ ~~~~~~::::... /~ 11 | ___-==_ _-~o~ \/ ||| \\ _/~~- 12 | __---~~~.==~||\=_ -_--~/_-~|- |\\ \\ _/~ 13 | _-~~ .=~ | \\-_ '-~7 /- / || \ / 14 | .~ .~ | \\ -_ / /- / || \ / 15 | / ____ / | \\ ~-_/ /|- _/ .|| \ / 16 | |~~ ~~|--~~~~--_ \ ~==-/ | \~--===~~ .\ 17 | ' ~-| /| |-~\~~ __--~~ 18 | |-~~-_/ | | ~\_ _-~ /\ 19 | / \ \__ \/~ \__ 20 | _--~ _/ | .-~~____--~-/ ~~==. 21 | ((->/~ '.|||' -_| ~~-/ , . _|| 22 | -_ ~\ ~~---l__i__i__i--~~_/ 23 | _-~-__ ~) \--______________--~~ 24 | //.-~~~-~_--~- |-------~~~~~~~~ 25 | //.-~~~--\ 26 | 神兽保佑,代码无BUG! 27 | ************************************************************************/ 28 | 29 | #ifndef _LR_H 30 | #define _LR_H 31 | 32 | #include 33 | #include 34 | #include 35 | #include 36 | #include 37 | #include 38 | #include 39 | using namespace std; 40 | #define EXTENSION_NOTERMINAL '^' 41 | 42 | class Prod { // 这里是存放形如X->abc的形式,不存在多个候选式 43 | friend class Item; 44 | friend class LR; 45 | private: 46 | char noTerminal; // 产生式左部非终结符名字 47 | string right; // 产生式右部 48 | set additionalVt; // 附加终结符 49 | friend bool operator == (const Prod &a, const Prod &b) { 50 | return a.noTerminal == b.noTerminal && a.right == b.right; 51 | } 52 | friend bool operator == (const Prod &a, char c) { 53 | return a.noTerminal == c; 54 | } 55 | 56 | public: 57 | static string cut(const string &in, int i, int j) { 58 | return string(in.begin() + i, in.begin() + j); 59 | } 60 | static string replaceAll(const string &in, const string from, const string to); 61 | string displayStr() const; 62 | Prod(const string &in); 63 | Prod(const char &noTerminal, const string& right, const set& additionalVt): 64 | noTerminal(noTerminal), right(right), additionalVt(additionalVt) {} 65 | }; 66 | 67 | class Item { // 项目集 68 | friend class LR; 69 | private: 70 | vector prods; // 项目集 71 | static set Vn; // 非终结符 72 | static set Vt; // 终结符 73 | static set Symbol; // 所有符号 74 | friend bool operator == (const Item &a, const Item &b) { 75 | if(a.prods.size() != b.prods.size()) return false; 76 | else { 77 | for(const auto& p: a.prods) {// 选择a的每个产生式 78 | auto it = find(b.prods.begin(), b.prods.end(), p); 79 | if(it == b.prods.end()) // 找不到 80 | return false; 81 | else {// 找到的话判断附加终结符是否都相等 82 | if(p.additionalVt != it->additionalVt) 83 | return false; 84 | } 85 | } 86 | return true; 87 | } 88 | } 89 | public: 90 | void add(const string &prod); 91 | void display() const; 92 | }; 93 | 94 | class LR { 95 | private: 96 | Item G; // 文法G 97 | enum actionStat{ 98 | ACCEPT=0, 99 | SHIFT, 100 | REDUCE, 101 | }; 102 | static const char *actionStatStr[]; 103 | 104 | vector C; // 项目集规范族 105 | map, int> GOTO; // goto数组,项目集=char 106 | map, pair > ACTION; // Action数组,Action[(i, a)]=(s|r)j 107 | map > FIRST; // first集 108 | map > FOLLOW; // follow集 109 | set first(const string &s); // 求first集 110 | void follow(); 111 | vector inStr; // 输入串/栈 112 | vector status; // 状态栈 113 | vector parse; // 分析栈 114 | Item closure(Item I); // 求该项目的闭包 115 | Item Goto(const Item& I, char X); // 求I经过X到达的项目集 116 | void items(); // 求项目集状态机DFA!! 117 | void showStrStack(); // 显示输入栈 118 | void showStatusStack(); 119 | void showParseStack(); 120 | public: 121 | void add(const string &s); // 添加产生式 122 | void build(); // 构造Action、GOTO表 123 | void showTable(); // 打印LR分析表! 124 | void debug(); 125 | void loadStr(const string &in); // 读取输入串 126 | void parser(); // LR(1)分析 127 | void showGrammar(); // 显示输入的文法产生式 128 | void drawGraph(); // 画出DFA! 129 | void generateDot(); 130 | void run(); 131 | }; 132 | 133 | #endif 134 | -------------------------------------------------------------------------------- /Lexical/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Lexical analyer by netcan 5 | 6 | 7 | 50 | 51 | 52 |
53 |

Lexical analyer by netcan

54 | 55 |
56 |
57 |
58 |
59 |
60 | 61 | 62 |
63 |
64 |
65 |
66 |
67 |
68 |

69 | 记号块 70 |

71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 | 80 |
81 |
82 |

83 | 84 | Lexical analyer output 85 |

86 |
87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 |
#WordTupleTypePosition
101 |
102 |
103 |
104 | 105 |
106 | 107 | 108 | 109 | Fork me on GitHub 110 | 111 |
112 | 113 | 114 | 172 | 173 | 174 | -------------------------------------------------------------------------------- /LR/Test/LR.data.out: -------------------------------------------------------------------------------- 1 | {"Grammar": [ 2 | "E->E+T", "E->T", "T->T*F", "T->F", "F->(E)", "F->i" 3 | ] 4 | ,"parseTable": { 5 | "Vt": ["(", ")", "*", "+", "i", "#"], 6 | "Vn": [ "E", "F", "T"], 7 | "Body": [ 8 | [ "s1", "", "", "", "s5", "", 2, 3, 4] 9 | , [ "s6", "", "", "", "s10", "", 7, 8, 9] 10 | , [ "", "", "", "s11", "", "acc", "", "", ""] 11 | , [ "", "", "r3", "r3", "", "r3", "", "", ""] 12 | , [ "", "", "s12", "r1", "", "r1", "", "", ""] 13 | , [ "", "", "r5", "r5", "", "r5", "", "", ""] 14 | , [ "s6", "", "", "", "s10", "", 13, 8, 9] 15 | , [ "", "s14", "", "s15", "", "", "", "", ""] 16 | , [ "", "r3", "r3", "r3", "", "", "", "", ""] 17 | , [ "", "r1", "s16", "r1", "", "", "", "", ""] 18 | , [ "", "r5", "r5", "r5", "", "", "", "", ""] 19 | , [ "s1", "", "", "", "s5", "", "", 3, 17] 20 | , [ "s1", "", "", "", "s5", "", "", 18, ""] 21 | , [ "", "s19", "", "s15", "", "", "", "", ""] 22 | , [ "", "", "r4", "r4", "", "r4", "", "", ""] 23 | , [ "s6", "", "", "", "s10", "", "", 8, 20] 24 | , [ "s6", "", "", "", "s10", "", "", 21, ""] 25 | , [ "", "", "s12", "r0", "", "r0", "", "", ""] 26 | , [ "", "", "r2", "r2", "", "r2", "", "", ""] 27 | , [ "", "r4", "r4", "r4", "", "", "", "", ""] 28 | , [ "", "r0", "s16", "r0", "", "", "", "", ""] 29 | , [ "", "r2", "r2", "r2", "", "", "", "", ""] 30 | ]} 31 | ,"Graph": {"All": "digraph all{node [shape=box style=filled];Grammar[style=rounded label=\"Grammar\nE->E+T\nE->T\nT->T*F\nT->F\nF->(E)\nF->i\n\" ];\nI0[label=\"I0\nE'->.E,#\nE->.E+T,+|#\nE->.T,+|#\nT->.T*F,*|+|#\nT->.F,*|+|#\nF->.(E),*|+|#\nF->.i,*|+|#\n\" ];\nI1[label=\"I1\nF->(.E),*|+|#\nE->.E+T,)|+\nE->.T,)|+\nT->.T*F,)|*|+\nT->.F,)|*|+\nF->.(E),)|*|+\nF->.i,)|*|+\n\" ];\nI2[label=\"I2\nE'->E.,#\nE->E.+T,+|#\n\" ];\nI3[label=\"I3\nT->F.,*|+|#\n\" ];\nI4[label=\"I4\nE->T.,+|#\nT->T.*F,*|+|#\n\" ];\nI5[label=\"I5\nF->i.,*|+|#\n\" ];\nI6[label=\"I6\nF->(.E),)|*|+\nE->.E+T,)|+\nE->.T,)|+\nT->.T*F,)|*|+\nT->.F,)|*|+\nF->.(E),)|*|+\nF->.i,)|*|+\n\" ];\nI7[label=\"I7\nF->(E.),*|+|#\nE->E.+T,)|+\n\" ];\nI8[label=\"I8\nT->F.,)|*|+\n\" ];\nI9[label=\"I9\nE->T.,)|+\nT->T.*F,)|*|+\n\" ];\nI10[label=\"I10\nF->i.,)|*|+\n\" ];\nI11[label=\"I11\nE->E+.T,+|#\nT->.T*F,*|+|#\nT->.F,*|+|#\nF->.(E),*|+|#\nF->.i,*|+|#\n\" ];\nI12[label=\"I12\nT->T*.F,*|+|#\nF->.(E),*|+|#\nF->.i,*|+|#\n\" ];\nI13[label=\"I13\nF->(E.),)|*|+\nE->E.+T,)|+\n\" ];\nI14[label=\"I14\nF->(E).,*|+|#\n\" ];\nI15[label=\"I15\nE->E+.T,)|+\nT->.T*F,)|*|+\nT->.F,)|*|+\nF->.(E),)|*|+\nF->.i,)|*|+\n\" ];\nI16[label=\"I16\nT->T*.F,)|*|+\nF->.(E),)|*|+\nF->.i,)|*|+\n\" ];\nI17[label=\"I17\nE->E+T.,+|#\nT->T.*F,*|+|#\n\" ];\nI18[label=\"I18\nT->T*F.,*|+|#\n\" ];\nI19[label=\"I19\nF->(E).,)|*|+\n\" ];\nI20[label=\"I20\nE->E+T.,)|+\nT->T.*F,)|*|+\n\" ];\nI21[label=\"I21\nT->T*F.,)|*|+\n\" ];\nI0 -> I1[label=\"(\"];I0 -> I2[label=\"E\"];I0 -> I3[label=\"F\"];I0 -> I4[label=\"T\"];I0 -> I5[label=\"i\"];I1 -> I6[label=\"(\"];I1 -> I7[label=\"E\"];I1 -> I8[label=\"F\"];I1 -> I9[label=\"T\"];I1 -> I10[label=\"i\"];I2 -> I11[label=\"+\"];I4 -> I12[label=\"*\"];I6 -> I6[label=\"(\"];I6 -> I13[label=\"E\"];I6 -> I8[label=\"F\"];I6 -> I9[label=\"T\"];I6 -> I10[label=\"i\"];I7 -> I14[label=\")\"];I7 -> I15[label=\"+\"];I9 -> I16[label=\"*\"];I11 -> I1[label=\"(\"];I11 -> I3[label=\"F\"];I11 -> I17[label=\"T\"];I11 -> I5[label=\"i\"];I12 -> I1[label=\"(\"];I12 -> I18[label=\"F\"];I12 -> I5[label=\"i\"];I13 -> I19[label=\")\"];I13 -> I15[label=\"+\"];I15 -> I6[label=\"(\"];I15 -> I8[label=\"F\"];I15 -> I20[label=\"T\"];I15 -> I10[label=\"i\"];I16 -> I6[label=\"(\"];I16 -> I21[label=\"F\"];I16 -> I10[label=\"i\"];I17 -> I12[label=\"*\"];I20 -> I16[label=\"*\"];Grammar -> I0[style=invis];}" 32 | , "Simple": "digraph simple {node [shape = circle style=filled];Grammar[shape=box style=rounded label=\"Grammar\nE->E+T\nE->T\nT->T*F\nT->F\nF->(E)\nF->i\n\" ];\nI0[tooltip=\"I0\nE'->.E,#\nE->.E+T,+|#\nE->.T,+|#\nT->.T*F,*|+|#\nT->.F,*|+|#\nF->.(E),*|+|#\nF->.i,*|+|#\n\" ];\nI1[tooltip=\"I1\nF->(.E),*|+|#\nE->.E+T,)|+\nE->.T,)|+\nT->.T*F,)|*|+\nT->.F,)|*|+\nF->.(E),)|*|+\nF->.i,)|*|+\n\" ];\nI2[tooltip=\"I2\nE'->E.,#\nE->E.+T,+|#\n\" ];\nI3[tooltip=\"I3\nT->F.,*|+|#\n\" ];\nI4[tooltip=\"I4\nE->T.,+|#\nT->T.*F,*|+|#\n\" ];\nI5[tooltip=\"I5\nF->i.,*|+|#\n\" ];\nI6[tooltip=\"I6\nF->(.E),)|*|+\nE->.E+T,)|+\nE->.T,)|+\nT->.T*F,)|*|+\nT->.F,)|*|+\nF->.(E),)|*|+\nF->.i,)|*|+\n\" ];\nI7[tooltip=\"I7\nF->(E.),*|+|#\nE->E.+T,)|+\n\" ];\nI8[tooltip=\"I8\nT->F.,)|*|+\n\" ];\nI9[tooltip=\"I9\nE->T.,)|+\nT->T.*F,)|*|+\n\" ];\nI10[tooltip=\"I10\nF->i.,)|*|+\n\" ];\nI11[tooltip=\"I11\nE->E+.T,+|#\nT->.T*F,*|+|#\nT->.F,*|+|#\nF->.(E),*|+|#\nF->.i,*|+|#\n\" ];\nI12[tooltip=\"I12\nT->T*.F,*|+|#\nF->.(E),*|+|#\nF->.i,*|+|#\n\" ];\nI13[tooltip=\"I13\nF->(E.),)|*|+\nE->E.+T,)|+\n\" ];\nI14[tooltip=\"I14\nF->(E).,*|+|#\n\" ];\nI15[tooltip=\"I15\nE->E+.T,)|+\nT->.T*F,)|*|+\nT->.F,)|*|+\nF->.(E),)|*|+\nF->.i,)|*|+\n\" ];\nI16[tooltip=\"I16\nT->T*.F,)|*|+\nF->.(E),)|*|+\nF->.i,)|*|+\n\" ];\nI17[tooltip=\"I17\nE->E+T.,+|#\nT->T.*F,*|+|#\n\" ];\nI18[tooltip=\"I18\nT->T*F.,*|+|#\n\" ];\nI19[tooltip=\"I19\nF->(E).,)|*|+\n\" ];\nI20[tooltip=\"I20\nE->E+T.,)|+\nT->T.*F,)|*|+\n\" ];\nI21[tooltip=\"I21\nT->T*F.,)|*|+\n\" ];\nI0 -> I1[label=\"(\"];I0 -> I2[label=\"E\"];I0 -> I3[label=\"F\"];I0 -> I4[label=\"T\"];I0 -> I5[label=\"i\"];I1 -> I6[label=\"(\"];I1 -> I7[label=\"E\"];I1 -> I8[label=\"F\"];I1 -> I9[label=\"T\"];I1 -> I10[label=\"i\"];I2 -> I11[label=\"+\"];I4 -> I12[label=\"*\"];I6 -> I6[label=\"(\"];I6 -> I13[label=\"E\"];I6 -> I8[label=\"F\"];I6 -> I9[label=\"T\"];I6 -> I10[label=\"i\"];I7 -> I14[label=\")\"];I7 -> I15[label=\"+\"];I9 -> I16[label=\"*\"];I11 -> I1[label=\"(\"];I11 -> I3[label=\"F\"];I11 -> I17[label=\"T\"];I11 -> I5[label=\"i\"];I12 -> I1[label=\"(\"];I12 -> I18[label=\"F\"];I12 -> I5[label=\"i\"];I13 -> I19[label=\")\"];I13 -> I15[label=\"+\"];I15 -> I6[label=\"(\"];I15 -> I8[label=\"F\"];I15 -> I20[label=\"T\"];I15 -> I10[label=\"i\"];I16 -> I6[label=\"(\"];I16 -> I21[label=\"F\"];I16 -> I10[label=\"i\"];I17 -> I12[label=\"*\"];I20 -> I16[label=\"*\"];Grammar -> I0[style=invis];}"}, 33 | "parser": [ 34 | {"statusStack": " 0 ", "parseStack": "", "inStrStack": "i+i*i#", "action": "SHIFT"} 35 | , {"statusStack": " 0 5 ", "parseStack": "i", "inStrStack": "+i*i#", "action": "REDUCE F->i"} 36 | , {"statusStack": " 0 3 ", "parseStack": "F", "inStrStack": "+i*i#", "action": "REDUCE T->F"} 37 | , {"statusStack": " 0 4 ", "parseStack": "T", "inStrStack": "+i*i#", "action": "REDUCE E->T"} 38 | , {"statusStack": " 0 2 ", "parseStack": "E", "inStrStack": "+i*i#", "action": "SHIFT"} 39 | , {"statusStack": " 0 2 11 ", "parseStack": "E+", "inStrStack": "i*i#", "action": "SHIFT"} 40 | , {"statusStack": " 0 2 11 5 ", "parseStack": "E+i", "inStrStack": "*i#", "action": "REDUCE F->i"} 41 | , {"statusStack": " 0 2 11 3 ", "parseStack": "E+F", "inStrStack": "*i#", "action": "REDUCE T->F"} 42 | , {"statusStack": " 0 2 11 17 ", "parseStack": "E+T", "inStrStack": "*i#", "action": "SHIFT"} 43 | , {"statusStack": " 0 2 11 17 12 ", "parseStack": "E+T*", "inStrStack": "i#", "action": "SHIFT"} 44 | , {"statusStack": " 0 2 11 17 12 5 ", "parseStack": "E+T*i", "inStrStack": "#", "action": "REDUCE F->i"} 45 | , {"statusStack": " 0 2 11 17 12 18 ", "parseStack": "E+T*F", "inStrStack": "#", "action": "REDUCE T->T*F"} 46 | , {"statusStack": " 0 2 11 17 ", "parseStack": "E+T", "inStrStack": "#", "action": "REDUCE E->E+T"} 47 | , {"statusStack": " 0 2 ", "parseStack": "E", "inStrStack": "#", "action": "ACCEPT"}] 48 | } 49 | -------------------------------------------------------------------------------- /LL1/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | LL1 parser by netcan 5 | 6 | 7 | 8 | 18 | 19 | 20 | 21 | 22 | Fork me on GitHub 23 | 24 | 25 |
26 |

LL1 parser by netcan

27 | 28 |
29 |

30 | Parse Tree 31 |

32 |
33 |
请检查是否为LL1文法,或者输入是否有效,否则请联系我,谢谢合作
34 |
35 |
36 |
37 |
38 | 39 |
40 |
41 |
42 |
43 |
44 | 45 | 46 |
47 |
48 | 49 | 50 |
51 | 52 |
53 |
54 |
55 | 56 | 57 |
58 |
59 |

60 | First & Follow 61 |

62 |
63 |
请检查是否为LL1文法,或者输入是否有效,否则请联系我,谢谢合作
64 |
65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 |
FIRSTFOLLOW
76 |
77 |
78 |
79 |
80 |

81 | Parse Table 82 |

83 |
84 |
请检查是否为LL1文法,或者输入是否有效,否则请联系我,谢谢合作
85 |
86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 |
94 |
95 |
96 |
97 | 98 | 99 |
100 |
101 |

102 | Parser 103 |

104 |
105 |
请检查是否为LL1文法,或者输入是否有效,否则请联系我,谢谢合作
106 |
107 |
108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 |
StepParseStackInputStackProduction
120 |
121 |
122 |
123 |
124 |
125 |
126 | 127 | 128 | 129 | 282 | 283 | 284 | 285 | -------------------------------------------------------------------------------- /LR/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | LR(1) parser by netcan 5 | 6 | 7 | 8 | 29 | 30 | 31 | 32 | 33 | Fork me on GitHub 34 | 35 | 36 |
37 |

LR(1) parser by netcan

38 | 39 | 40 |
41 |

42 | DFA Graph 43 |

44 |
45 |
46 |
47 |
48 | 51 |
52 | 55 |
56 | 58 |
59 |
60 |
61 | 62 |
63 | 64 |
65 |
66 |
67 |
68 | 69 | 71 |
72 |
73 | 74 | 75 |
76 |
77 | 78 | 79 |
80 |
81 |
82 | 83 | 84 |
85 |
86 |

87 | Grammar List 88 |

89 |
90 |
91 |
92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 |
IDProduction
102 |
103 |
104 |
105 | 106 |
107 | 108 |
109 |
110 |

111 | Parse Table 112 |

113 |
114 |
115 |
116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 |
126 |
127 |
128 | 129 |
130 | 131 |
132 |
133 |

134 | Parser 135 |

136 |
137 |
138 |
139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 |
StepstatusStackparseStackinStrStackaction
152 |
153 |
154 | 155 |
156 |
157 |
158 |
159 | 160 | 161 | 162 | 301 | 302 | 303 | -------------------------------------------------------------------------------- /LL1/LL1.cpp: -------------------------------------------------------------------------------- 1 | /************************************************************************* 2 | > File Name: LL1.cpp 3 | > Author: Netcan 4 | > Blog: http://www.netcan666.com 5 | > Mail: 1469709759@qq.com 6 | > Created Time: 2016-10-09 日 19:23:18 CST 7 | 8 | __----~~~~~~~~~~~------___ 9 | . . ~~//====...... __--~ ~~ 10 | -. \_|// |||\\ ~~~~~~::::... /~ 11 | ___-==_ _-~o~ \/ ||| \\ _/~~- 12 | __---~~~.==~||\=_ -_--~/_-~|- |\\ \\ _/~ 13 | _-~~ .=~ | \\-_ '-~7 /- / || \ / 14 | .~ .~ | \\ -_ / /- / || \ / 15 | / ____ / | \\ ~-_/ /|- _/ .|| \ / 16 | |~~ ~~|--~~~~--_ \ ~==-/ | \~--===~~ .\ 17 | ' ~-| /| |-~\~~ __--~~ 18 | |-~~-_/ | | ~\_ _-~ /\ 19 | / \ \__ \/~ \__ 20 | _--~ _/ | .-~~____--~-/ ~~==. 21 | ((->/~ '.|||' -_| ~~-/ , . _|| 22 | -_ ~\ ~~---l__i__i__i--~~_/ 23 | _-~-__ ~) \--______________--~~ 24 | //.-~~~-~_--~- |-------~~~~~~~~ 25 | //.-~~~--\ 26 | 神兽保佑,代码无BUG! 27 | *************************************************************************/ 28 | 29 | #include "LL1.h" 30 | 31 | Prod::Prod(const string &in) { 32 | prod = in; 33 | isValid = false; 34 | split(); 35 | } 36 | 37 | bool Prod::split() { 38 | if(prod.length() < 4) return false; 39 | if(cut(1, 3) == "->" && isupper(prod[0])) // A->...则noTerminal = A 40 | noTerminal = prod[0]; 41 | else return false; 42 | for(unsigned int i=0; i' && ++i)) Vt.insert(c); 46 | } 47 | 48 | for(unsigned int i=3; i::iterator it = find(G.begin(), G.end(), prod.noTerminal); 61 | if(it != G.end()) { // 找到产生式 62 | it->selection.insert(prod.selection.begin(), prod.selection.end()); // 追加候选式 63 | for(auto s: prod.selection) 64 | it->prod += ("|" + s); // 追加候选式 65 | } 66 | else // 没找到 67 | G.push_back(prod); 68 | VN.insert(prod.Vn.begin(), prod.Vn.end()); 69 | VT.insert(prod.Vt.begin(), prod.Vt.end()); 70 | return true; 71 | } 72 | else return false; 73 | } 74 | 75 | set LL1::first(const string &s) { 76 | Prod prod = Prod(s); 77 | if(prod.isValid) { // 产生式 78 | if(FIRST[prod.noTerminal].size() != 0) return FIRST[prod.noTerminal]; 79 | for(auto sel:prod.selection) { // 候选式 80 | set f = first(sel); // 求出候选式的first集合 81 | FIRST[prod.noTerminal].insert(f.begin(), f.end()); 82 | } 83 | return FIRST[prod.noTerminal]; 84 | } 85 | else if(s.length() == 0) // 空串 86 | return set({'@'}); 87 | else if(s.length() == 1){ // 终结符或非终结符 88 | if(VT.find(s[0]) != VT.end()) // 终结符 89 | return set({s[0]}); 90 | else { // 非终结符 91 | if(FIRST[s[0]].size() != 0) return FIRST[s[0]]; 92 | else { 93 | vector::iterator it = find(G.begin(), G.end(), s[0]); // 求出非终结符的产生式 94 | if(it != G.end()) { // 找到产生式 95 | set f = first(it->prod); 96 | FIRST[s[0]].insert(f.begin(), f.end()); 97 | } 98 | return FIRST[s[0]]; 99 | } 100 | } 101 | } else { // 候选式X1X2X3X4... 102 | set ret; 103 | for(unsigned int i=0; i f = first(string(1, s[i])); // 逐个符号求first(Xi)集 105 | if(f.find('@') != f.end() && s.length() - 1 != i) { // 发现@ 106 | f.erase(f.find('@')); // 减去@ 107 | ret.insert(f.begin(), f.end()); // 放入first集合 108 | } else { // 无@,则不需要求下去了 109 | ret.insert(f.begin(), f.end()); 110 | break; 111 | } 112 | } 113 | return ret; 114 | } 115 | } 116 | 117 | // A->aXb,求follow(X) 118 | void LL1::follow() { // 非递归求法,防止死递归 119 | FOLLOW[G[0].noTerminal].insert('#'); // 开始符号放'#' 120 | for(auto pp: G) { // 直到follow(X)不在增大 121 | unsigned int size = 0; 122 | while(size != FOLLOW[pp.noTerminal].size()) { 123 | size = FOLLOW[pp.noTerminal].size(); 124 | for(auto prod: G) { // 求出所有非终结符的follow集合 125 | char X = prod.noTerminal; 126 | for(auto p: G) // 求出X的follow集合 127 | for(auto s: p.selection) { // 逐个候选式找X 128 | unsigned long loc = 0; 129 | if((loc = s.find(X)) != string::npos) { // 找到非终结符X 130 | set f = first(string(s.begin() + loc + 1, s.end())); // 求first(b) 131 | FOLLOW[X].insert(f.begin(), f.end()); // 加入到follow(X)中 132 | if(f.find('@') != f.end()) {// 找到@ 133 | FOLLOW[X].erase(FOLLOW[X].find('@')); // 删除@ 134 | set fw = FOLLOW[p.noTerminal]; // 把follow(A)放入follow(X) 135 | FOLLOW[X].insert(fw.begin(), fw.end()); 136 | } 137 | } 138 | } 139 | } 140 | } 141 | } 142 | } 143 | 144 | void LL1::parseTable() { // X->a 145 | for(auto prod: G) { // 枚举产生式 146 | for(auto sel:prod.selection) { // 枚举候选式 147 | set f = first(sel); // 求first集合 148 | for(auto terminal: f) 149 | if(terminal == '@') // 存在@,将follow(x)的每个终结符放入表中 150 | for(auto term: FOLLOW[prod.noTerminal]) 151 | M[make_pair(prod.noTerminal, term)] = sel; 152 | else 153 | M[make_pair(prod.noTerminal, terminal)] = sel; 154 | } 155 | } 156 | } 157 | 158 | void LL1::build() { 159 | for(auto prod: G) first(prod.prod); // 求first集 160 | 161 | // 求follow集 162 | follow(); 163 | 164 | parseTable(); // 预测分析表 165 | info(); 166 | // 求完表后,将@替换为# 167 | if(VT.find('@') != VT.end()) 168 | VT.erase(VT.find('@')); 169 | VT.insert('#'); 170 | tableInfo(); 171 | 172 | return; 173 | } 174 | 175 | void LL1::showIndataStack() { 176 | for(vector::reverse_iterator it = indata.rbegin(); it != indata.rend(); ++it) 177 | printf("%c", *it); 178 | } 179 | 180 | void LL1::showParseStack() { 181 | for(vector::iterator it = parse.begin(); it != parse.end(); ++it) 182 | printf("%c", *it); 183 | } 184 | 185 | void LL1::loadIndata(const string &s) { 186 | indata.push_back('#'); 187 | for(int i=s.length()-1; i>=0; --i) 188 | indata.push_back(s[i]); 189 | } 190 | 191 | void LL1::error(int step) { 192 | printf("{ \"step\": %d, ", step++); 193 | 194 | printf("\"parseStack\": \"ERROR\"" 195 | ", \"indataStack\": \"ERROR\"" 196 | ", \"production\": \"ERROR\"" 197 | "}\n"); 198 | } 199 | 200 | void LL1::parser() { 201 | parse.push_back('#'); 202 | parse.push_back(G[0].noTerminal); // 文法开始符号 203 | // printf("step\tparseStack\tindataStack\tproduction\n"); 204 | printf("\"Parser\": ["); 205 | int i = 0; // 处理打印的第一个逗号 206 | 207 | int ptop, itop, step = 0; 208 | string prod = ""; // 候选式 209 | while((ptop = parse.size() - 1) >= 0) { 210 | itop = indata.size() - 1; 211 | 212 | printf("%s{ \"step\": %d, ", i++==0?" ":", ", step++); 213 | 214 | printf("\"parseStack\": \""); 215 | showParseStack(); 216 | printf("\", \"indataStack\": \""); 217 | showIndataStack(); 218 | printf("\", \"production\": \"%s\"", prod.c_str()); 219 | printf("}\n"); 220 | 221 | // begin 222 | prod = ""; 223 | char X = parse[ptop]; 224 | char curc = indata[itop]; 225 | parse.pop_back(); 226 | if(VT.find(X) != VT.end()) { // 终结符 227 | if(X != curc) { 228 | printf("%s", i==0?" ":", "); 229 | error(step); 230 | break; 231 | } 232 | else { 233 | indata.pop_back(); 234 | prod = "match " + string(1, X); 235 | } 236 | } else if(X == '@') 237 | continue; 238 | else { // 终结符 239 | prod = M[make_pair(X, curc)]; 240 | if(prod.size()) { // 找得到 241 | if(prod != "@") 242 | for(int i=prod.size() - 1; i>=0; --i) 243 | parse.push_back(prod[i]); 244 | } 245 | else { 246 | printf("%s", i==0?" ":", "); 247 | error(step); 248 | break; 249 | } 250 | prod = string(1, X) + "->" + prod; 251 | } 252 | } 253 | 254 | printf("]\n"); 255 | // printf("Parse Success!\n"); 256 | } 257 | 258 | void LL1::info() { 259 | printf("\"VT\": ["); 260 | int i = 0; // 处理打印的第一个逗号 261 | 262 | for(auto c: VT) { 263 | printf("%s\"%c\"", i == 0?" ":", ", c); 264 | ++i; 265 | } 266 | printf("], \n"); 267 | 268 | i = 0; 269 | printf("\"VN\": ["); 270 | for(auto c: VN) { 271 | printf("%s\"%c\"", i == 0?" ":", ", c); 272 | ++i; 273 | } 274 | printf("], \n"); 275 | 276 | // for(auto p: G) 277 | // printf("noTerminal: %s\n", p.prod.c_str()); 278 | 279 | printf("\"FIRST\": ["); 280 | i = 0; 281 | for(auto prod:G) { 282 | printf("\n%c{ \"noTerminal\": \"%c\", \"Terminal\": [", i==0?' ':',', prod.noTerminal); 283 | int j = 0; 284 | for(auto c:FIRST[prod.noTerminal]) { 285 | printf("%s\"%c\"", j == 0?" ":", ", c); 286 | ++j; 287 | } 288 | printf("] }"); 289 | ++i; 290 | } 291 | printf("], \n"); 292 | 293 | printf("\"FOLLOW\": ["); 294 | i = 0; 295 | for(auto prod:G) { 296 | printf("\n%c{ \"noTerminal\": \"%c\", \"Terminal\": [", i==0?' ':',', prod.noTerminal); 297 | int j = 0; 298 | for(auto c:FOLLOW[prod.noTerminal]) { 299 | printf("%s\"%c\"", j == 0?" ":", ", c); 300 | ++j; 301 | } 302 | printf("] }"); 303 | ++i; 304 | } 305 | printf("], \n"); 306 | } 307 | 308 | void LL1::tableInfo() { 309 | printf("\"Table\": {\n"); 310 | printf("\"Header\": ["); 311 | for(auto c:VT) // 终结符,表头, #号放在最后一列 312 | if(c != '#') 313 | printf("\"%c\", ", c); 314 | printf("\"#\""); 315 | printf("], \n"); 316 | 317 | printf("\"Body\": ["); 318 | int i = 0; 319 | for(auto prod:G) { 320 | printf("%s{\"noTerminal\": \"%c\", ", i == 0?" ":", ", prod.noTerminal); 321 | printf("\"production\": ["); 322 | for(auto c:VT) // 终结符 323 | if(c != '#') 324 | printf("\"%s\", ", M[make_pair(prod.noTerminal, c)].c_str()); 325 | printf("\"%s\"", M[make_pair(prod.noTerminal, '#')].c_str()); 326 | 327 | printf("]}\n"); 328 | ++i; 329 | } 330 | printf("] }, \n"); 331 | } 332 | 333 | void LL1::run() { 334 | puts("{"); // 输出json,与前端交互 335 | string in; 336 | while(cin >> in && in != "#") // 读取文法 337 | addProd(Prod(in)); 338 | in = ""; 339 | cin >> in; // 表达式 340 | if(in == "#" || in.size() == 0) return; 341 | loadIndata(in); 342 | 343 | build(); 344 | parser(); 345 | puts("}"); 346 | } 347 | 348 | int main() { 349 | LL1 ll; 350 | ll.run(); 351 | 352 | return 0; 353 | } 354 | -------------------------------------------------------------------------------- /Lexical/lexical.cpp: -------------------------------------------------------------------------------- 1 | /************************************************************************* 2 | > File Name: lexical.cpp 3 | > Author: Netcan 4 | > Blog: http://www.netcan666.com 5 | > Mail: 1469709759@qq.com 6 | > Created Time: 2016-10-05 三 20:34:12 CST 7 | 8 | __----~~~~~~~~~~~------___ 9 | . . ~~//====...... __--~ ~~ 10 | -. \_|// |||\\ ~~~~~~::::... /~ 11 | ___-==_ _-~o~ \/ ||| \\ _/~~- 12 | __---~~~.==~||\=_ -_--~/_-~|- |\\ \\ _/~ 13 | _-~~ .=~ | \\-_ '-~7 /- / || \ / 14 | .~ .~ | \\ -_ / /- / || \ / 15 | / ____ / | \\ ~-_/ /|- _/ .|| \ / 16 | |~~ ~~|--~~~~--_ \ ~==-/ | \~--===~~ .\ 17 | ' ~-| /| |-~\~~ __--~~ 18 | |-~~-_/ | | ~\_ _-~ /\ 19 | / \ \__ \/~ \__ 20 | _--~ _/ | .-~~____--~-/ ~~==. 21 | ((->/~ '.|||' -_| ~~-/ , . _|| 22 | -_ ~\ ~~---l__i__i__i--~~_/ 23 | _-~-__ ~) \--______________--~~ 24 | //.-~~~-~_--~- |-------~~~~~~~~ 25 | //.-~~~--\ 26 | 神兽保佑,代码无BUG! 27 | *************************************************************************/ 28 | 29 | #include "lexical.h" 30 | 31 | void Key::add(const string &str, int loc) { 32 | Trie *p = this->root, *q; 33 | for(unsigned int i=0; inext[id] == NULL) { 36 | q = new Trie(); 37 | p->next[id] = q; 38 | } 39 | p = p->next[id]; 40 | } 41 | p->isEnd = true; 42 | p->loc = loc; 43 | } 44 | 45 | void Key::add(vector strs) { 46 | int loc = 0; 47 | for(auto str : strs) { 48 | this->add(str, loc++); 49 | } 50 | } 51 | 52 | int Key::find(const string &str) { 53 | Trie *p = this->root; 54 | for(unsigned int i=0; i= 26) 57 | return -1; 58 | p = p->next[id]; 59 | if(p == NULL) return -1; 60 | } 61 | if(p->isEnd) return p->loc; 62 | else return -1; 63 | } 64 | 65 | void Key::free(Trie *p) { 66 | if(p == NULL) return; 67 | for(int i=0; i<26; ++i) this->free(p->next[i]); 68 | delete p; 69 | } 70 | 71 | template // 数组末尾元素指针 72 | T* tail(T (&a)[n]) { 73 | return a+n; 74 | } 75 | 76 | Lexical::Lexical() { 77 | const char * ks[] = { // 关键字表 78 | "auto", "double", "int", "struct", "break", "else", "long", 79 | "switch","case", "enum", "register", "typedef", "char", 80 | "extern", "return", "union","const", "float", "short", 81 | "unsigned", "continue", "for", "signed", "void","default", 82 | "goto", "sizeof", "volatile", "do", "if", "while", "static" 83 | }; 84 | keys.add(vector(ks, tail(ks))); 85 | 86 | // 分界符 87 | optrs.push_back(make_pair(",", DELIMITER)); 88 | optrs.push_back(make_pair(";", DELIMITER)); 89 | optrs.push_back(make_pair("(", DELIMITER)); 90 | optrs.push_back(make_pair(")", DELIMITER)); 91 | optrs.push_back(make_pair("[", DELIMITER)); 92 | optrs.push_back(make_pair("]", DELIMITER)); 93 | optrs.push_back(make_pair("{", DELIMITER)); 94 | optrs.push_back(make_pair("}", DELIMITER)); 95 | 96 | // 算术运算符 97 | optrs.push_back(make_pair("+", ARITHMETICOPTR)); 98 | optrs.push_back(make_pair("-", ARITHMETICOPTR)); 99 | optrs.push_back(make_pair("*", ARITHMETICOPTR)); 100 | optrs.push_back(make_pair("/", ARITHMETICOPTR)); 101 | optrs.push_back(make_pair("%", ARITHMETICOPTR)); 102 | optrs.push_back(make_pair("++", ARITHMETICOPTR)); 103 | optrs.push_back(make_pair("--", ARITHMETICOPTR)); 104 | 105 | // 关系运算符 106 | optrs.push_back(make_pair(">", RELATIONOPTR)); 107 | optrs.push_back(make_pair(">=", RELATIONOPTR)); 108 | optrs.push_back(make_pair("<", RELATIONOPTR)); 109 | optrs.push_back(make_pair("<=", RELATIONOPTR)); 110 | optrs.push_back(make_pair("==", RELATIONOPTR)); 111 | optrs.push_back(make_pair("<>", RELATIONOPTR)); 112 | optrs.push_back(make_pair("=", RELATIONOPTR)); 113 | 114 | row = column = 0; 115 | isFirst = true; 116 | } 117 | 118 | 119 | string Lexical::cut(int i, int j) { 120 | return string(in.begin() + i, in.begin() + j); 121 | } 122 | 123 | bool Lexical::isKey(const string &str) { 124 | if(keys.find(str) != -1) return true; 125 | else return false; 126 | } 127 | 128 | 129 | int Lexical::getKeyPointer(const string &str) { 130 | return keys.find(str); 131 | } 132 | 133 | bool Lexical::isOptr(const string &str) { 134 | for(auto opt:optrs) 135 | if(opt.first == str) return true; 136 | return false; 137 | } 138 | 139 | int Lexical::getOptrPointer(const string &str) { 140 | vector >::iterator it; 141 | for(it = optrs.begin(); it != optrs.end() && it->first != str; ++it); 142 | return it - optrs.begin(); 143 | } 144 | 145 | Type Lexical::getOptrType(const string &str) { 146 | vector >::iterator it; 147 | for(it = optrs.begin(); it != optrs.end() && it->first != str; ++it); 148 | if(it != optrs.end()) 149 | return it->second; 150 | else return ERROR; 151 | } 152 | 153 | bool Lexical::isId(const string &str) { 154 | if(!isalpha(str.c_str()[0]) && str.c_str()[0] != '_') 155 | return false; 156 | for(auto c: str) 157 | if(!isalnum(c) && c != '_') return false; 158 | return true; 159 | } 160 | 161 | int Lexical::getIDPointer(const string &str) { 162 | vector >::iterator it = find(indetifiers.begin(), indetifiers.end(), make_pair(str, ID)); 163 | if(it != indetifiers.end()) // 找到了 164 | return it - indetifiers.begin(); 165 | else { 166 | indetifiers.push_back(make_pair(str, ID)); 167 | return indetifiers.size() - 1; 168 | } 169 | } 170 | 171 | bool Lexical::isNum(const string &str) { 172 | for(auto c:str) 173 | if(!isdigit(c)) return false; 174 | return true; 175 | } 176 | 177 | int Lexical::getNumPointer(const string &str) { 178 | vector >::iterator it = find(constants.begin(), constants.end(), make_pair(str, NUMBER)); 179 | if(it != constants.end()) // 找到了 180 | return it - constants.begin(); 181 | else { 182 | constants.push_back(make_pair(str, NUMBER)); 183 | return constants.size() - 1; 184 | } 185 | } 186 | 187 | bool Lexical::isString(const string &str) { // 是否字符串 188 | return true; 189 | } 190 | 191 | int Lexical::getStringPointer(const string &str) { 192 | vector >::iterator it = find(strings.begin(), strings.end(), make_pair(str, STRING)); 193 | if(it != strings.end()) // 找到了 194 | return it - strings.begin(); 195 | else { 196 | strings.push_back(make_pair(str, STRING)); 197 | return strings.size() - 1; 198 | } 199 | } 200 | 201 | bool Lexical::isChar(const string &chr) { 202 | if(chr.length() == 1 || (chr[0] == '\\' && chr.length() == 2)) 203 | return true; 204 | else 205 | return false; 206 | } 207 | 208 | int Lexical::getCharPointer(const string &chr) { 209 | vector >::iterator it = find(chars.begin(), chars.end(), make_pair(chr.c_str()[0], CHAR)); 210 | if(it != chars.end()) // 找到了 211 | return it - chars.begin(); 212 | else { 213 | chars.push_back(make_pair(chr.c_str()[0], CHAR)); 214 | return chars.size() - 1; 215 | } 216 | }; 217 | 218 | bool Lexical::getIn() { 219 | ++row; 220 | return getline(cin, in); 221 | } 222 | 223 | void Lexical::analysis() { 224 | unsigned int j = 0; 225 | for(column = 0; column < in.length(); ++column) { 226 | char c = in.c_str()[column]; 227 | if(isalpha(c)) { 228 | for(j = column+1; j < in.length() && (isalnum(in[j]) || in[j] == '_'); ++j); // 匹配关键字或者标识符自动机 229 | string s = cut(column, j); 230 | 231 | if(!isFirst) printf(", "); 232 | else isFirst = false; 233 | 234 | if(isKey(s)) 235 | printf("{\"word\": \"%s\", \"tuple\": [%d, %d], \"type\": \"%s\", \"pos\": [%d, %d]}\n", s.c_str(), KEY, getKeyPointer(s), typeStr[KEY], row, column+1); 236 | else if(isId(s)) 237 | printf("{\"word\": \"%s\", \"tuple\": [%d, %d], \"type\": \"%s\", \"pos\": [%d, %d]}\n", s.c_str(), ID, getIDPointer(s), typeStr[ID], row, column+1); 238 | else 239 | printf("{\"word\": \"%s\", \"tuple\": [%d, %d], \"type\": \"%s\", \"pos\": [%d, %d]}\n", s.c_str(), ERROR, ERROR, typeStr[ERROR], row, column+1); 240 | 241 | column = j-1; 242 | } 243 | else if(isdigit(c)) { 244 | for(j = column+1; j < in.length() && (isalnum(in[j]) || in[j] == '_'); ++j); // 匹配数字字符串自动机 245 | string s = cut(column, j); 246 | 247 | if(!isFirst) printf(", "); 248 | else isFirst = false; 249 | if(isNum(s)) 250 | printf("{\"word\": \"%s\", \"tuple\": [%d, %d], \"type\": \"%s\", \"pos\": [%d, %d]}\n", s.c_str(), NUMBER, getNumPointer(s), typeStr[NUMBER], row, column+1); 251 | else 252 | printf("{\"word\": \"%s\", \"tuple\": [%d, %d], \"type\": \"%s\", \"pos\": [%d, %d]}\n", s.c_str(), ERROR, ERROR, typeStr[ERROR], row, column+1); 253 | 254 | column = j - 1; 255 | } 256 | else if(c == '/' && in[column+1] == '/') { // 注释 257 | for(column += 2; column < in.length() && isspace(column); ++column); 258 | string s = cut(column, in.length()); 259 | 260 | if(!isFirst) printf(", "); 261 | else isFirst = false; 262 | printf("{\"word\": \"%s\", \"tuple\": [%d, %d], \"type\": \"%s\", \"pos\": [%d, %d]}\n", s.c_str(), COMMENT, 0, typeStr[COMMENT], row, column+1); 263 | column = in.length(); 264 | } 265 | else if(isOptr(string(1, c))){ 266 | for(j = column+1; j < in.length() && isOptr(string(1, in[j])) && getOptrType(string(1, in[j])) != DELIMITER && getOptrType(string(1, in[j])) == getOptrType(string(1,c)); ++j); // 运算符自动机 267 | string s = cut(column, j); 268 | 269 | if(!isFirst) printf(", "); 270 | else isFirst = false; 271 | if(isOptr(s)) 272 | printf("{\"word\": \"%s\", \"tuple\": [%d, %d], \"type\": \"%s\", \"pos\": [%d, %d]}\n", s.c_str(), getOptrType(s), getOptrPointer(s), typeStr[getOptrType(s)], row, column+1); 273 | else 274 | printf("{\"word\": \"%s\", \"tuple\": [%d, %d], \"type\": \"%s\", \"pos\": [%d, %d]}\n", s.c_str(), ERROR, ERROR, typeStr[ERROR], row, column+1); 275 | 276 | column = j - 1; 277 | } 278 | else if(c == '"' || c == '\'') { // 字符串 279 | for(j = column+1; j < in.length() && ( (in[j]=='\\' && ++j) || in[j] != c); ++j); // 字符(串)自动机 280 | string s = cut(column+1, j); 281 | // printf("%s(%ld)\n", s.c_str(), s.length()); 282 | 283 | if(!isFirst) printf(", "); 284 | else isFirst = false; 285 | if(c == '"' && j < in.length()) 286 | printf("{\"word\": \"%s\", \"tuple\": [%d, %d], \"type\": \"%s\", \"pos\": [%d, %d]}\n", s.c_str(), STRING, getStringPointer(s), typeStr[STRING], row, column+1); 287 | else if(c == '\'' && isChar(s)) 288 | printf("{\"word\": \"%s\", \"tuple\": [%d, %d], \"type\": \"%s\", \"pos\": [%d, %d]}\n", s.c_str(), CHAR, getCharPointer(s), typeStr[CHAR], row, column+1); 289 | else 290 | printf("{\"word\": \"%s\", \"tuple\": [%d, %d], \"type\": \"%s\", \"pos\": [%d, %d]}\n", s.c_str(), ERROR, ERROR, typeStr[ERROR], row, column+1); 291 | column = j; 292 | } 293 | else if(!isspace(c)) { 294 | if(!isFirst) printf(", "); 295 | else isFirst = false; 296 | if(c=='"') 297 | printf("{\"word\": \"\\\"\", \"tuple\": [%d, %d], \"type\": \"%s\", \"pos\": [%d, %d]}\n", ERROR, ERROR, typeStr[ERROR], row, column+1); 298 | else 299 | printf("{\"word\": \"%s\", \"tuple\": [%d, %d], \"type\": \"%s\", \"pos\": [%d, %d]}\n", string(1,c).c_str(), ERROR, ERROR, typeStr[ERROR], row, column+1); 300 | } 301 | } 302 | } 303 | 304 | void Lexical::run() { 305 | while(getIn()) { 306 | analysis(); 307 | } 308 | } 309 | 310 | int main() { 311 | Lexical lex; 312 | lex.run(); 313 | 314 | return 0; 315 | } 316 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Introduction 2 | 合肥工业大学编译原理课设。 3 | # Screencast 4 | ## Lexical 5 | ![lexical.gif](lexical.gif) 6 | 7 | ## LL1 Parser 8 | ![ll1.gif](ll1.gif) 9 | 10 | ## LR1 Parser 11 | ![LR.gif](LR.gif) 12 | 13 | # 词法分析器 14 | [http://www.netcan666.com/2016/10/07/%E7%BC%96%E8%AF%91%E5%8E%9F%E7%90%86%E4%B9%8B%E8%AF%8D%E6%B3%95%E5%88%86%E6%9E%90%E5%99%A8%E8%AE%BE%E8%AE%A1/](http://www.netcan666.com/2016/10/07/%E7%BC%96%E8%AF%91%E5%8E%9F%E7%90%86%E4%B9%8B%E8%AF%8D%E6%B3%95%E5%88%86%E6%9E%90%E5%99%A8%E8%AE%BE%E8%AE%A1/) 15 | 16 | 这是编译原理的第一个实验,算是热身实验吧,确实很简单,花了一晚上就把词法分析器底层部分写完了,老师比较喜欢图形界面,后来又加了前端,也就是现在看到的效果。实验要求能够匹配出**关键字**、**标记符**、**运算符**、**分界符**、**无符号数**,后来我又添加了一部分,现在能匹配出**字符/字符串**、**行间注释**。 17 | 18 | ## 词法分析器底层部分 19 | 底层部分是用C++写的,大体思路就是,每次从`stdin`读取出一行,然后从这行的第一个字符开始匹配。匹配完了,读取下一行,行号+1。 20 | 21 | ### 匹配**关键字**或**标记符**自动机 22 | 若当前匹配到的字符i是*字母*,就继续匹配下一个字符,直到下个字符j不是*字母*或者*数字*或者'_'为止,则截取字符串(i, j),判断这个字符串是不是**关键字**或者**标记符**,否则**错误**处理。如果是**标记符**,将其存入**标记符**表中,其在**标记符**表的位置即为其`Pointer`。最后输出相关信息。 23 | 24 | ### 匹配**无符号数**自动机 25 | 若当前匹配到的字符i是*数字*,就继续匹配下一个字符,直到下个字符j不是*字母*或者*数字*或者'_'为止,则截取字符串(i, j),判断这个字符串是不是**无符号数**。如果是**无符号数**,将其存入**常数**表中,其在**常数**表的位置即为其`Pointer`,若不是**无符号数**则当**错误**处理。最后输出相关信息。 26 | 27 | ### 匹配**行间注释**自动机 28 | 若当前匹配到的字符i是'/'并且下一个字符也是'/',就继续匹配下一个字符,直到下个字符j不是*空白*(空格或tab)为止,则截取字符串(j, lineEnd),作为注释处理。 29 | 30 | ### 匹配**运算符**、**分界符**自动机 31 | 我将**运算符**和**分界符**放到一个`optrs`表中,若当前匹配到的字符i是`optrs`的元素,就继续匹配下一个字符,直到下个字符j不是`optrs`的元素或者运算符类型与字符i不一样或者就是分界符为止,则截取字符串(i, j),判断这个字符串是不是`optrs`的元素,并确定其类型,其Pointer为该**运算符**或**分界符**在`optrs`的位置,输出相关信息,否则当**错误**处理。最后输出相关信息。 32 | 33 | ### 匹配**字符**、**字符串**自动机 34 | 若当前匹配到的字符i是`"`或者`'`,就继续匹配下一个字符,直到下个字符j是字符i为止,则截取字符串(i, j),判断这个字符串是**字符**还是**字符串**。如果是的话,将其存入**字符**或**字符串**表中,其在相应表的位置即为其`Pointer`,若不符合则**错误**处理。最后输出相关信息。 35 | 36 | ## 词法分析器前端部分 37 | 前端部分我比较认真,我用`html`+`js`+`php`来实现图形界面,之所以写成网页,是因为我不想写`native app`,我也没`GUI`开发环境。在互联网时代,`webapp`是趋势,谁还写本地客户端啊,况且带个几十M的`GUI`库实在是麻烦。 38 | 39 | 于是我的分析器底层部分设计成输出`json`格式,然后利用管道将`C++`程序与`php`程序进行数据传送。前端只要用`js`输数据取数据渲染页面即可。 40 | 41 | 在这之中发现一个问题,如果*输入文本*一长,渲染效率大大降低,因为我用`append`方法一个个加元素的。解决方案是最后转换为字符串一次性输出渲染,效率提高了不少。具体可看这个优化片段:[优化js运行效率](https://github.com/netcan/compilingTheory/commit/2a09a9054e467d35d416603c5d73247acf2af764)。 42 | 43 | # LL1语法分析器 44 | [http://www.netcan666.com/2016/10/09/%E7%BC%96%E8%AF%91%E5%8E%9F%E7%90%86%E4%B9%8BLL-1-%E8%AF%AD%E6%B3%95%E5%88%86%E6%9E%90/](http://www.netcan666.com/2016/10/09/%E7%BC%96%E8%AF%91%E5%8E%9F%E7%90%86%E4%B9%8BLL-1-%E8%AF%AD%E6%B3%95%E5%88%86%E6%9E%90/) 45 | 46 | 我写这篇博文写了好几天了,描述比较凌乱,建议大家还是看书吧,或者直接看我[程序设计部分](#程序设计)。一定要搞懂first集和follow集的求法,不然写程序也会遇到困难的,这里有篇不错的关于求first和follow集的论文,推荐看看:[https://www.cs.virginia.edu/~weimer/2008-415/reading/FirstFollowLL.pdf](https://www.cs.virginia.edu/~weimer/2008-415/reading/FirstFollowLL.pdf) 47 | 48 | LL(1)文法主要是求first集和follow集,个人觉得follow集比较麻烦点,然后就是用这两个集合求预测分析表。 49 | 50 | ## first集 51 | first集就是求文法符号串\alpha的开始符号集合first(\alpha),例如有以下文法G(E): 52 | 53 | E\to TE' \\ 54 | E'\to +TE'|\varepsilon\\ 55 | T\to FT'\\ 56 | T'\to *FT'|\varepsilon\\ 57 | F\to (E)|\bf{id} 58 | 59 | 60 | 用例子还是比较好说明的,很容易求出各非终结符的first集。 61 | 62 | first(E) = first(T) = first(F) = \{(, \bf{id}\}\\ 63 | first(E') = \{+, \varepsilon\}\\ 64 | first(T') = \{*, \varepsilon\} 65 | 66 | 67 | 这里给出first集的一般描述。 68 | 69 | 70 | FIRST(\alpha) =\{t|(t\ is\ a\ terminal\ and\ \alpha\Rightarrow^∗ t\beta)or(t=\varepsilon\ and\ \alpha \Rightarrow^* \varepsilon)\} 71 | 72 | 73 | 也就是说,如果非终结符E有产生式T\beta,那么它们first(E)=first(T),这个不难理解,因为我(E)能推出你(T),你又能推出它(开始符号,终结符),那我们都能推出它。 74 | 75 | first集的作用是,当用来匹配开头为a的文本时,有产生式A\to X\alpha|Y\beta,若a\in X,则选择候选式A\to X\alpha,若a\in Y,选择A\to Y\beta,说了那么多,我只想说,不是用first(A)这个来匹配a,而是用它的候选式first(X)或者first(Y)来匹配。 76 | 77 | 用上面的例子来说,匹配(233,因为(\in first(TE'),应该选择E'\to +TE'这个候选式。 78 | 79 | ## follow集 80 | follow集比较抽象,它用来解决这个问题的,如果非终结符E'的first(E')含有\varepsilon,那么选择会不确定,比如说G(E), 81 | 82 | E\to Tb|F\\ 83 | T\to a|\varepsilon\\ 84 | F\to c 85 | 86 | 87 | 很容易求得 88 | 89 | first(Tb) = \{a, \varepsilon\} \\ 90 | first(F) = {c} 91 | 92 | 93 | 匹配开头为a,因为a\in first(Tb),选择E\to Tb产生式,匹配开头为c,因为c\in first(F),选择E\to F产生式。然而当我匹配b时,因为b\not \in first(Tb)\land \not \in first(F),这时候就不知道选择哪个产生式了,但是因为\varepsilon\in first(Tb),且E\to Tb|F\Rightarrow (a|\varepsilon)b|F\Rightarrow ab|b|F,应该选择E\to Tb的,这说明了first集的不足,从而引进follow集。 94 | 95 | 给出定义,follow(A)即为非终结符A后面可能接的符号集。 96 | 97 | 至于怎么求follow(A),我就直接摘抄PPT的定义吧,然后在说明。 98 | 99 | 连续使用下面的规则,直至每个follow不再增大为止。 100 | * 对于文法的开始符号S,置#于follow(S)中。 101 | * 若A\to \alpha B\beta是一个产生式,则把first(\beta)\backslash \{\varepsilon \}加至follow(B)中; 102 | * 若A\to \alpha B是一个产生式,或A\to \alpha B\beta 是一个产生式而\varepsilon\in FIRST(\beta),则把follow(A)加至follow(B)中。 103 | 104 | 第三条规则可以这么理解,因为B后面啥都没,A又能推出B,所以应该把A后面的符号(follow(A))加入follow(B)中。需要注意的是,follow集不含\varepsilon。 105 | 106 | 所以要求某个非终结符的follow集,只要在**产生式右边**中找,然后根据它后面一个**符号**按照上述规则计算就行了。 107 | 108 | ## 预测分析表 109 | 求得first集和follow集后,求分析表就比较容易了。这里简单说下构建方法。 110 | 111 | 对文法的每个产生式,执行下面步骤。 112 | 113 | * 对first(\alpha)的每个**终结符**a,将候选式A\to \alpha加入M[A, a] 114 | * 如果\varepsilon\in first(\alpha),把follow(A)的每个**终结符**b(包括#),把A\to \alpha加入M[A, b]。 115 | 116 | ## 程序设计 117 | 代码的核心部分就是求first集和follow集了,这也是程序的精髓所在。 118 | 119 | 首先我约定字符@代表\varepsilon,因为键盘上没那个符号,所以随便找了个合适的符号代替。约定单个大写字母代表非终结符,小写字母或某些符号代表终结符。 120 | 121 | 然后设计一个叫做产生式的类`Prod`,它的构造函数接受一个字符串,字符串描述了一个产生式。然后分割字符串,把它的非终结符存入`noTerminal`成员中,候选式存入`selection`集合中。 122 | 123 | 接着设计一个叫`LL1`的类,也就是核心部分了,它提供了求`first`、`follow`、分析表等方法。因为`first`集和`follow`集可能会求未知表达式的`first`集和`follow`集,比如说`A->B,B->C`,欲求`first(A)`,需求`first(B)`,欲求`first(B)`,需求`first(C)`,从而确定了这两种集合求法只能用递归来求,这也是我所能想到的最简单求法,可以参考我代码。 124 | 125 | 然而现在(2016/10/21)补充下,经过反复调教,`first`集都重写了5次,而`follow`集是**不能用递归**来求的,因为有可能出现这种情况: 126 | 127 | A\to bAS\\ 128 | S\to aA\\ 129 | S\to d\\ 130 | A\to \varepsilon 131 | 132 | 133 | 求`follow(A)`需要`first(S)`和`follow(S)`,递归求`follow(S)`需要`follow(A)`,然而这样就进入了死递归。所以最后我改写成5个循环搞定。 134 | 135 | 136 | 求出了`first`和`follow`,剩下的就好办了。至于图形界面,和[上次](/2016/10/07/编译原理之词法分析器设计/)一样,套了个`php`,通过`php`传json数据到前端,前端输入数据取数据,渲染页面。那颗语法树的画法,通过前序遍历画得。 137 | 138 | # LR1语法分析器 139 | [http://www.netcan666.com/2016/10/21/%E7%BC%96%E8%AF%91%E5%8E%9F%E7%90%86%E5%AE%9E%E9%AA%8C%E4%B9%8BLR-1-%E5%88%86%E6%9E%90%E5%99%A8%E8%AE%BE%E8%AE%A1/](http://www.netcan666.com/2016/10/21/%E7%BC%96%E8%AF%91%E5%8E%9F%E7%90%86%E5%AE%9E%E9%AA%8C%E4%B9%8BLR-1-%E5%88%86%E6%9E%90%E5%99%A8%E8%AE%BE%E8%AE%A1/) 140 | 141 | 先来吐槽下,据说这个实验是最难的一个实验,当然也是最后的一个实验了。在我们实验室上一届学长只有一个人写出来,可见其难度。 142 | 143 | ![http://7xqytu.com1.z0.glb.clouddn.com//2016/10/QQ%E6%88%AA%E5%9B%BE20161021212712.png](http://7xqytu.com1.z0.glb.clouddn.com//2016/10/QQ%E6%88%AA%E5%9B%BE20161021212712.png) 144 | 145 | 然而我并不觉得有什么难的,当我上课听懂老师讲LR语法分析的时候,我就疑惑了,难点在哪?学长说难在自动机的构建上,自动机比较难拍,不好用数据结构来描述。这当然给了我巨大信心,回去不到一天把LR分析器核心拍出来了,在没有参考任何代码、龙书,仅看着教科书上的算法来写的。 146 | 147 | ## 产生式`Prod`类 148 | 我来说下具体是怎么实现的吧,用面向对象来写比较好写,绝对比面向过程好写。先来看看我设计的最小的类`Prod`(为减小篇幅已删除无关紧要的函数)。 149 | 150 | ```cpp 151 | class Prod { // 这里是存放形如X->abc的形式,不存在多个候选式 152 | private: 153 | char noTerminal; // 产生式左部非终结符名字 154 | string right; // 产生式右部 155 | set additionalVt; // 附加终结符 156 | friend bool operator == (const Prod &a, const Prod &b) { 157 | return a.noTerminal == b.noTerminal && a.right == b.right; 158 | } 159 | friend bool operator == (const Prod &a, char c) { 160 | return a.noTerminal == c; 161 | } 162 | public: 163 | Prod(const char &noTerminal, const string& right, const set& additionalVt): 164 | noTerminal(noTerminal), right(right), additionalVt(additionalVt) {} 165 | }; 166 | ``` 167 | 168 | 这个类是存放产生式的,存放形如`A->Bc`,这里的`noTerminal`就是左边的`A`,`right`就是右边的`Bc`,而`additionalVt`是`LR(1)`的项目集的**搜索符**,长度为1所以叫`LR(1)`。我重载了`==`符号,后面用来搜索项目集/文法中是否有这个产生式简直不能再方便,构造函数也能快速构造产生式,无疑为后面项目集中插入产生式提供了方便。 169 | 170 | ## 项目集`Item`类 171 | ```cpp 172 | class Item { // 项目集 173 | private: 174 | vector prods; // 项目集产生式 175 | static set Vn; // 非终结符 176 | static set Vt; // 终结符 177 | static set Symbol; // 所有符号 178 | friend bool operator == (const Item &a, const Item &b) { 179 | if(a.prods.size() != b.prods.size()) return false; 180 | else { 181 | for(const auto& p: a.prods) {// 选择a的每个产生式 182 | auto it = find(b.prods.begin(), b.prods.end(), p); 183 | if(it == b.prods.end()) // 找不到 184 | return false; 185 | else {// 找到的话判断附加终结符是否都相等 186 | if(p.additionalVt != it->additionalVt) 187 | return false; 188 | } 189 | } 190 | return true; 191 | } 192 | } 193 | public: 194 | void add(const string &prod); 195 | }; 196 | ``` 197 | 198 | 项目集`Item`类中,`prods`向量存放这个项目集的所有**项目**(即产生式+**搜索符**),而`Vn/Vt`集合存放了**所有**产生式的非终结符/终结符,`Symbol`仅仅是`Vn/Vt`的并集,为后面`GOTO`函数枚举符号提供了方便,`add`方法为项目集插入项目。这里最重要的就是重载`==`符号了,它是判断两个项目集是否相等的关键,判断也很简单,首先判断两个项目集的项目数量是否相等,若相等进一步判断是否所有的**项目**都相等,这里就展现了前面重载`==`的优点(当然还需要判断**搜索符**是否也都相等)。能判断两个项目集是否相等就好办了,后面求**项目集规范族**插入项目就简单了。 199 | 200 | 还需要注意的一点,`Prod`类已经重载`==`了,为啥项目集`prods`用向量来存,而不是直接用集合来存?这样就不用判等了,还能二分查找提高了查询效率。但是我考虑到用集合来存的话,会按照字典序来排,但是这样还要重载`<`,会打乱产生式的顺序,所以我后面的`LR`类来存放文法产生式、**项目集规范族**也是用向量来存(插入的时候判等就是了),而不是集合,以免打乱了顺序。 201 | 202 | ## `LR`类 203 | ```cpp 204 | class LR { 205 | private: 206 | Item G; // 文法G 207 | enum actionStat{ 208 | ACCEPT=0, 209 | SHIFT, 210 | REDUCE, 211 | }; 212 | 213 | vector C; // 项目集规范族 214 | map, int> GOTO; // goto数组,项目集=char 215 | map, pair > ACTION; // Action数组,Action[(i, a)]=(s|r)j 216 | map > FIRST; // first集 217 | set first(const string &s); // 求first集 218 | vector inStr; // 输入串/栈 219 | vector status; // 状态栈 220 | vector parse; // 分析栈 221 | Item closure(Item I); // 求该项目的闭包 222 | Item Goto(const Item& I, char X); // 求I经过X到达的项目集 223 | void items(); // 求项目集状态机DFA!! 224 | public: 225 | void add(const string &s); // 添加产生式 226 | void parser(); // LR(1)分析 227 | }; 228 | ``` 229 | 230 | 这是最后一个类了,重点说说。`G`用来存放输入的文法,把它看成一个项目集吧。`C`是**项目集规范族**,也就是项目集的集合,用向量来存。`actionStat`为枚举类型,用于表示`ACTION`的动作类型。`GOTO`用于存放自动机DFA上**边**,边`w(i, j)=X`,`ACTION`用于存放动作,`Action[(i, X)] = ((s|r)j)|acc`,即当状态`i`遇到**终结符X**的时候采取的动作,移进/规约/接受。`FIRST`集合存放各个**非终结符**的`FIRST`集合,`first`方法求集合会记忆化存储到`FIRST`集合里。接下来就是那三个栈了,还有`Closure`、`Goto`、`items`、`parser`这几个方法了,书上有我就不细讲了,设计好这几个数据结构,写起来会轻松很多。 231 | 232 | ## 空串处理 233 | 那时候我的分析器还不能处理形如A\to \varepsilon的产生式,书上、指导书给的文法,都没这类产生式。我就想,是不是`LR`不能处理空串啊?因为`LR`的`DFA`构建过程中,如果引出\varepsilon这条边,那就是`NFA`了,这样还要把它化为`DFA`,那就很麻烦了。请教了一下李老师,老师说处理A\to \varepsilon项目的时候,项目直接写成A\to .,也就是说求`GOTO`函数的时候不要把\varepsilon当终结符/非终结符处理,不要引出\varepsilon边。 234 | 235 | 恍然大悟,回去修改了下程序,果然能处理这类产生式了。 236 | 237 | ## `PL0`文法测试 238 | 后来有人给了一组数据,即`PL0`文法,测试失败。这里给下数据,做了点小修改,因为有些符号和我程序内部符号冲突了,所以只是做了简单的替换。 239 | ```cpp 240 | A->B, 241 | B->CEFH 242 | B->H 243 | B->CH 244 | B->EH 245 | B->FH 246 | B->CFH 247 | B->CEH 248 | B->EFH 249 | C->cY; 250 | D->b=a 251 | E->dX; 252 | F->GB; 253 | G->eb; 254 | H->I 255 | H->R 256 | H->T 257 | H->S 258 | H->U 259 | H->V 260 | H->J 261 | I->btL 262 | J->fWg 263 | K->LQL 264 | K->hL 265 | L->LOM 266 | L->M 267 | L->-M 268 | L->+M 269 | M->MPN 270 | M->N 271 | N->b 272 | N->a 273 | N->(L) 274 | O->+ 275 | O->- 276 | P->* 277 | P->/ 278 | Q->= 279 | Q->% 280 | Q->< 281 | Q->r 282 | Q->> 283 | Q->s 284 | R->pKqH 285 | S->mb 286 | T->nKoH 287 | U->i(X) 288 | V->j(Z) 289 | W->W;H 290 | W->H 291 | X->X,b 292 | X->b 293 | Y->Y,D 294 | Y->D 295 | Z->Z,L 296 | Z->L 297 | ``` 298 | 299 | 我调试了一下程序,发现2个比较严重的bug,有一个和程序无关紧要的bug,后面再说,这里先说下其中的一个bug,就是在求`first`集的bug。 300 | 301 | 如果文法产生式有直接左递归的话,那么就会死递归爆栈,所以我对`first`集做了下简单的修改,就是遇到直接左递归,忽略掉。 302 | 303 | 另一个`bug`也处理好了,`PL0`测试通过,近300个状态,这里贴一下局部预览图感受下。 304 | ![http://7xibui.com1.z0.glb.clouddn.com//2016/10/screenshot-window-2016-10-21-114458.png](http://7xibui.com1.z0.glb.clouddn.com//2016/10/screenshot-window-2016-10-21-114458.png) 305 | ![http://7xibui.com1.z0.glb.clouddn.com//2016/10/screenshot-window-2016-10-21-114315.png](http://7xibui.com1.z0.glb.clouddn.com//2016/10/screenshot-window-2016-10-21-114315.png) 306 | 307 | ## `for auto &` Bug 308 | 这个`bug`隐藏较深,就是我用`auto`引用类型引用容器中的元素,然后又在容器中插入元素,那么这个引用就会失效,换成迭代器也没达到预期效果,反而更糟,具体如下。 309 | 310 | ```cpp 311 | #include 312 | #include 313 | using namespace std; 314 | 315 | int main() { 316 | vector v={1, 2, 3}; 317 | for(const auto &i: v) { 318 | printf("i=%d\n", i); 319 | v.push_back(5); 320 | printf("i=%d\n", i); 321 | } 322 | return 0; 323 | } 324 | ``` 325 | 326 | 只是简单地插入一个元素而已,输出结果却是这样的。 327 | ```cpp 328 | i=1 329 | i=0 330 | i=0 331 | i=0 332 | i=3 333 | i=3 334 | ``` 335 | 336 | `i=0`是哪来的。。。这个没找出原因,最后简单的用`for(int i=0; ...)`来替代处理了。 337 | 338 | 现在找到原因了,看了下[cppreference.com](http://en.cppreference.com/w/)关于`push_back`的定义,有这么一句话。 339 | 340 | > If the new size() is greater than capacity() then all iterators and references (including the past-the-end iterator) are invalidated. Otherwise only the past-the-end iterator is invalidated. 341 | 342 | 就是说如果`vector`插入元素的`size()`大于`capacity()`的话,所有迭代器、引用都会无效,否则只是最后一个元素的迭代器/引用无效。这个可能和`vector`内存分配管理有关。 343 | 344 | 然后就是打印了下`vector`的大小,发现刚开始`size()==capacity()`的,所以一插入元素就会出问题,用`reserve()`简单的把`capacity()`调大就没问题了。 345 | 346 | ## 前端处理 347 | 核心程序写完了,最后就是把它展现出来,数据格式化下就好了。 348 | 349 | 之前在验收`LL1`实验的时候,老师看到我把语法树都画出来了,就说这个实验(`LL1`)没必要画语法树,`LR1`实验能把自动机画出来就好了,然后我就爽快答应了,因为只要核心程序写出来了,那么前端随便你怎么搞都行,这部分重点说下我是怎么画自动机的。 350 | 351 | 一开始我就是用`mermaid`这个`JS`库,只要给它图的描述,它就能画出来,试了下效果不是很满意。 352 | 353 | 继续`Google`,发现这么一个工具[graphviz](http://www.graphviz.org/),它用了一种很简单的`DOT`语言,只要用`DOT`语言来描述这个图,它就能画出来。进一步发现这个工具有`js`移植版本,就试了试,效果不错,就是现在的样子。缺点就是这个移植版本太大了,`3.5MB`的库,所以第一次加载的时间全都花在下载这个库了,其二就是画那个`PL0`自动机的时候,会因为内存不足崩溃掉,可能这是`JS`的机制问题了吧。 354 | 355 | 考虑上面2个问题,我写了一个小程序`LR_DFA`,用它在后台直接输出`DOT`文件,然后交给`graphviz`处理导出`pdf`,能把完整的`PL0`自动机(画`PL0`比较耗时)画出来,就是前面贴出来的那个图了。 356 | 357 | -------------------------------------------------------------------------------- /LR/Test/LR.data2.out: -------------------------------------------------------------------------------- 1 | {"Grammar": [ 2 | "E->TG", "G->+TG", "G->-TG", "G->@", "T->FS", "S->*FS", "S->/FS", "S->@", "F->(E)", "F->i" 3 | ] 4 | ,"parseTable": { 5 | "Vt": ["(", ")", "*", "+", "-", "/", "i", "#"], 6 | "Vn": [ "E", "F", "G", "S", "T"], 7 | "Body": [ 8 | [ "s1", "", "", "", "", "", "s5", "", 2, 3, "", "", 4] 9 | , [ "s6", "", "", "", "", "", "s10", "", 7, 8, "", "", 9] 10 | , [ "", "", "", "", "", "", "", "acc", "", "", "", "", ""] 11 | , [ "", "", "s11", "r7", "r7", "s12", "", "r7", "", "", "", 13, ""] 12 | , [ "", "", "", "s14", "s15", "", "", "r3", "", "", 16, "", ""] 13 | , [ "", "", "r9", "r9", "r9", "r9", "", "r9", "", "", "", "", ""] 14 | , [ "s6", "", "", "", "", "", "s10", "", 17, 8, "", "", 9] 15 | , [ "", "s18", "", "", "", "", "", "", "", "", "", "", ""] 16 | , [ "", "r7", "s19", "r7", "r7", "s20", "", "", "", "", "", 21, ""] 17 | , [ "", "r3", "", "s22", "s23", "", "", "", "", "", 24, "", ""] 18 | , [ "", "r9", "r9", "r9", "r9", "r9", "", "", "", "", "", "", ""] 19 | , [ "s1", "", "", "", "", "", "s5", "", "", 25, "", "", ""] 20 | , [ "s1", "", "", "", "", "", "s5", "", "", 26, "", "", ""] 21 | , [ "", "", "", "r4", "r4", "", "", "r4", "", "", "", "", ""] 22 | , [ "s1", "", "", "", "", "", "s5", "", "", 3, "", "", 27] 23 | , [ "s1", "", "", "", "", "", "s5", "", "", 3, "", "", 28] 24 | , [ "", "", "", "", "", "", "", "r0", "", "", "", "", ""] 25 | , [ "", "s29", "", "", "", "", "", "", "", "", "", "", ""] 26 | , [ "", "", "r8", "r8", "r8", "r8", "", "r8", "", "", "", "", ""] 27 | , [ "s6", "", "", "", "", "", "s10", "", "", 30, "", "", ""] 28 | , [ "s6", "", "", "", "", "", "s10", "", "", 31, "", "", ""] 29 | , [ "", "r4", "", "r4", "r4", "", "", "", "", "", "", "", ""] 30 | , [ "s6", "", "", "", "", "", "s10", "", "", 8, "", "", 32] 31 | , [ "s6", "", "", "", "", "", "s10", "", "", 8, "", "", 33] 32 | , [ "", "r0", "", "", "", "", "", "", "", "", "", "", ""] 33 | , [ "", "", "s11", "r7", "r7", "s12", "", "r7", "", "", "", 34, ""] 34 | , [ "", "", "s11", "r7", "r7", "s12", "", "r7", "", "", "", 35, ""] 35 | , [ "", "", "", "s14", "s15", "", "", "r3", "", "", 36, "", ""] 36 | , [ "", "", "", "s14", "s15", "", "", "r3", "", "", 37, "", ""] 37 | , [ "", "r8", "r8", "r8", "r8", "r8", "", "", "", "", "", "", ""] 38 | , [ "", "r7", "s19", "r7", "r7", "s20", "", "", "", "", "", 38, ""] 39 | , [ "", "r7", "s19", "r7", "r7", "s20", "", "", "", "", "", 39, ""] 40 | , [ "", "r3", "", "s22", "s23", "", "", "", "", "", 40, "", ""] 41 | , [ "", "r3", "", "s22", "s23", "", "", "", "", "", 41, "", ""] 42 | , [ "", "", "", "r5", "r5", "", "", "r5", "", "", "", "", ""] 43 | , [ "", "", "", "r6", "r6", "", "", "r6", "", "", "", "", ""] 44 | , [ "", "", "", "", "", "", "", "r1", "", "", "", "", ""] 45 | , [ "", "", "", "", "", "", "", "r2", "", "", "", "", ""] 46 | , [ "", "r5", "", "r5", "r5", "", "", "", "", "", "", "", ""] 47 | , [ "", "r6", "", "r6", "r6", "", "", "", "", "", "", "", ""] 48 | , [ "", "r1", "", "", "", "", "", "", "", "", "", "", ""] 49 | , [ "", "r2", "", "", "", "", "", "", "", "", "", "", ""] 50 | ]} 51 | ,"Graph": {"All": "digraph all{node [shape=box style=filled];Grammar[style=rounded label=\"Grammar\nE->TG\nG->+TG\nG->-TG\nG->@\nT->FS\nS->*FS\nS->/FS\nS->@\nF->(E)\nF->i\n\" ];\nI0[label=\"I0\nE'->.E,#\nE->.TG,#\nT->.FS,+|-|#\nF->.(E),*|+|-|/|#\nF->.i,*|+|-|/|#\n\" ];\nI1[label=\"I1\nF->(.E),*|+|-|/|#\nE->.TG,)\nT->.FS,)|+|-\nF->.(E),)|*|+|-|/\nF->.i,)|*|+|-|/\n\" ];\nI2[label=\"I2\nE'->E.,#\n\" ];\nI3[label=\"I3\nT->F.S,+|-|#\nS->.*FS,+|-|#\nS->./FS,+|-|#\nS->@.,+|-|#\n\" ];\nI4[label=\"I4\nE->T.G,#\nG->.+TG,#\nG->.-TG,#\nG->@.,#\n\" ];\nI5[label=\"I5\nF->i.,*|+|-|/|#\n\" ];\nI6[label=\"I6\nF->(.E),)|*|+|-|/\nE->.TG,)\nT->.FS,)|+|-\nF->.(E),)|*|+|-|/\nF->.i,)|*|+|-|/\n\" ];\nI7[label=\"I7\nF->(E.),*|+|-|/|#\n\" ];\nI8[label=\"I8\nT->F.S,)|+|-\nS->.*FS,)|+|-\nS->./FS,)|+|-\nS->@.,)|+|-\n\" ];\nI9[label=\"I9\nE->T.G,)\nG->.+TG,)\nG->.-TG,)\nG->@.,)\n\" ];\nI10[label=\"I10\nF->i.,)|*|+|-|/\n\" ];\nI11[label=\"I11\nS->*.FS,+|-|#\nF->.(E),*|+|-|/|#\nF->.i,*|+|-|/|#\n\" ];\nI12[label=\"I12\nS->/.FS,+|-|#\nF->.(E),*|+|-|/|#\nF->.i,*|+|-|/|#\n\" ];\nI13[label=\"I13\nT->FS.,+|-|#\n\" ];\nI14[label=\"I14\nG->+.TG,#\nT->.FS,+|-|#\nF->.(E),*|+|-|/|#\nF->.i,*|+|-|/|#\n\" ];\nI15[label=\"I15\nG->-.TG,#\nT->.FS,+|-|#\nF->.(E),*|+|-|/|#\nF->.i,*|+|-|/|#\n\" ];\nI16[label=\"I16\nE->TG.,#\n\" ];\nI17[label=\"I17\nF->(E.),)|*|+|-|/\n\" ];\nI18[label=\"I18\nF->(E).,*|+|-|/|#\n\" ];\nI19[label=\"I19\nS->*.FS,)|+|-\nF->.(E),)|*|+|-|/\nF->.i,)|*|+|-|/\n\" ];\nI20[label=\"I20\nS->/.FS,)|+|-\nF->.(E),)|*|+|-|/\nF->.i,)|*|+|-|/\n\" ];\nI21[label=\"I21\nT->FS.,)|+|-\n\" ];\nI22[label=\"I22\nG->+.TG,)\nT->.FS,)|+|-\nF->.(E),)|*|+|-|/\nF->.i,)|*|+|-|/\n\" ];\nI23[label=\"I23\nG->-.TG,)\nT->.FS,)|+|-\nF->.(E),)|*|+|-|/\nF->.i,)|*|+|-|/\n\" ];\nI24[label=\"I24\nE->TG.,)\n\" ];\nI25[label=\"I25\nS->*F.S,+|-|#\nS->.*FS,+|-|#\nS->./FS,+|-|#\nS->@.,+|-|#\n\" ];\nI26[label=\"I26\nS->/F.S,+|-|#\nS->.*FS,+|-|#\nS->./FS,+|-|#\nS->@.,+|-|#\n\" ];\nI27[label=\"I27\nG->+T.G,#\nG->.+TG,#\nG->.-TG,#\nG->@.,#\n\" ];\nI28[label=\"I28\nG->-T.G,#\nG->.+TG,#\nG->.-TG,#\nG->@.,#\n\" ];\nI29[label=\"I29\nF->(E).,)|*|+|-|/\n\" ];\nI30[label=\"I30\nS->*F.S,)|+|-\nS->.*FS,)|+|-\nS->./FS,)|+|-\nS->@.,)|+|-\n\" ];\nI31[label=\"I31\nS->/F.S,)|+|-\nS->.*FS,)|+|-\nS->./FS,)|+|-\nS->@.,)|+|-\n\" ];\nI32[label=\"I32\nG->+T.G,)\nG->.+TG,)\nG->.-TG,)\nG->@.,)\n\" ];\nI33[label=\"I33\nG->-T.G,)\nG->.+TG,)\nG->.-TG,)\nG->@.,)\n\" ];\nI34[label=\"I34\nS->*FS.,+|-|#\n\" ];\nI35[label=\"I35\nS->/FS.,+|-|#\n\" ];\nI36[label=\"I36\nG->+TG.,#\n\" ];\nI37[label=\"I37\nG->-TG.,#\n\" ];\nI38[label=\"I38\nS->*FS.,)|+|-\n\" ];\nI39[label=\"I39\nS->/FS.,)|+|-\n\" ];\nI40[label=\"I40\nG->+TG.,)\n\" ];\nI41[label=\"I41\nG->-TG.,)\n\" ];\nI0 -> I1[label=\"(\"];I0 -> I2[label=\"E\"];I0 -> I3[label=\"F\"];I0 -> I4[label=\"T\"];I0 -> I5[label=\"i\"];I1 -> I6[label=\"(\"];I1 -> I7[label=\"E\"];I1 -> I8[label=\"F\"];I1 -> I9[label=\"T\"];I1 -> I10[label=\"i\"];I3 -> I11[label=\"*\"];I3 -> I12[label=\"/\"];I3 -> I13[label=\"S\"];I4 -> I14[label=\"+\"];I4 -> I15[label=\"-\"];I4 -> I16[label=\"G\"];I6 -> I6[label=\"(\"];I6 -> I17[label=\"E\"];I6 -> I8[label=\"F\"];I6 -> I9[label=\"T\"];I6 -> I10[label=\"i\"];I7 -> I18[label=\")\"];I8 -> I19[label=\"*\"];I8 -> I20[label=\"/\"];I8 -> I21[label=\"S\"];I9 -> I22[label=\"+\"];I9 -> I23[label=\"-\"];I9 -> I24[label=\"G\"];I11 -> I1[label=\"(\"];I11 -> I25[label=\"F\"];I11 -> I5[label=\"i\"];I12 -> I1[label=\"(\"];I12 -> I26[label=\"F\"];I12 -> I5[label=\"i\"];I14 -> I1[label=\"(\"];I14 -> I3[label=\"F\"];I14 -> I27[label=\"T\"];I14 -> I5[label=\"i\"];I15 -> I1[label=\"(\"];I15 -> I3[label=\"F\"];I15 -> I28[label=\"T\"];I15 -> I5[label=\"i\"];I17 -> I29[label=\")\"];I19 -> I6[label=\"(\"];I19 -> I30[label=\"F\"];I19 -> I10[label=\"i\"];I20 -> I6[label=\"(\"];I20 -> I31[label=\"F\"];I20 -> I10[label=\"i\"];I22 -> I6[label=\"(\"];I22 -> I8[label=\"F\"];I22 -> I32[label=\"T\"];I22 -> I10[label=\"i\"];I23 -> I6[label=\"(\"];I23 -> I8[label=\"F\"];I23 -> I33[label=\"T\"];I23 -> I10[label=\"i\"];I25 -> I11[label=\"*\"];I25 -> I12[label=\"/\"];I25 -> I34[label=\"S\"];I26 -> I11[label=\"*\"];I26 -> I12[label=\"/\"];I26 -> I35[label=\"S\"];I27 -> I14[label=\"+\"];I27 -> I15[label=\"-\"];I27 -> I36[label=\"G\"];I28 -> I14[label=\"+\"];I28 -> I15[label=\"-\"];I28 -> I37[label=\"G\"];I30 -> I19[label=\"*\"];I30 -> I20[label=\"/\"];I30 -> I38[label=\"S\"];I31 -> I19[label=\"*\"];I31 -> I20[label=\"/\"];I31 -> I39[label=\"S\"];I32 -> I22[label=\"+\"];I32 -> I23[label=\"-\"];I32 -> I40[label=\"G\"];I33 -> I22[label=\"+\"];I33 -> I23[label=\"-\"];I33 -> I41[label=\"G\"];Grammar -> I0[style=invis];}" 52 | , "Simple": "digraph simple {node [shape = circle style=filled];Grammar[shape=box style=rounded label=\"Grammar\nE->TG\nG->+TG\nG->-TG\nG->@\nT->FS\nS->*FS\nS->/FS\nS->@\nF->(E)\nF->i\n\" ];\nI0[tooltip=\"I0\nE'->.E,#\nE->.TG,#\nT->.FS,+|-|#\nF->.(E),*|+|-|/|#\nF->.i,*|+|-|/|#\n\" ];\nI1[tooltip=\"I1\nF->(.E),*|+|-|/|#\nE->.TG,)\nT->.FS,)|+|-\nF->.(E),)|*|+|-|/\nF->.i,)|*|+|-|/\n\" ];\nI2[tooltip=\"I2\nE'->E.,#\n\" ];\nI3[tooltip=\"I3\nT->F.S,+|-|#\nS->.*FS,+|-|#\nS->./FS,+|-|#\nS->@.,+|-|#\n\" ];\nI4[tooltip=\"I4\nE->T.G,#\nG->.+TG,#\nG->.-TG,#\nG->@.,#\n\" ];\nI5[tooltip=\"I5\nF->i.,*|+|-|/|#\n\" ];\nI6[tooltip=\"I6\nF->(.E),)|*|+|-|/\nE->.TG,)\nT->.FS,)|+|-\nF->.(E),)|*|+|-|/\nF->.i,)|*|+|-|/\n\" ];\nI7[tooltip=\"I7\nF->(E.),*|+|-|/|#\n\" ];\nI8[tooltip=\"I8\nT->F.S,)|+|-\nS->.*FS,)|+|-\nS->./FS,)|+|-\nS->@.,)|+|-\n\" ];\nI9[tooltip=\"I9\nE->T.G,)\nG->.+TG,)\nG->.-TG,)\nG->@.,)\n\" ];\nI10[tooltip=\"I10\nF->i.,)|*|+|-|/\n\" ];\nI11[tooltip=\"I11\nS->*.FS,+|-|#\nF->.(E),*|+|-|/|#\nF->.i,*|+|-|/|#\n\" ];\nI12[tooltip=\"I12\nS->/.FS,+|-|#\nF->.(E),*|+|-|/|#\nF->.i,*|+|-|/|#\n\" ];\nI13[tooltip=\"I13\nT->FS.,+|-|#\n\" ];\nI14[tooltip=\"I14\nG->+.TG,#\nT->.FS,+|-|#\nF->.(E),*|+|-|/|#\nF->.i,*|+|-|/|#\n\" ];\nI15[tooltip=\"I15\nG->-.TG,#\nT->.FS,+|-|#\nF->.(E),*|+|-|/|#\nF->.i,*|+|-|/|#\n\" ];\nI16[tooltip=\"I16\nE->TG.,#\n\" ];\nI17[tooltip=\"I17\nF->(E.),)|*|+|-|/\n\" ];\nI18[tooltip=\"I18\nF->(E).,*|+|-|/|#\n\" ];\nI19[tooltip=\"I19\nS->*.FS,)|+|-\nF->.(E),)|*|+|-|/\nF->.i,)|*|+|-|/\n\" ];\nI20[tooltip=\"I20\nS->/.FS,)|+|-\nF->.(E),)|*|+|-|/\nF->.i,)|*|+|-|/\n\" ];\nI21[tooltip=\"I21\nT->FS.,)|+|-\n\" ];\nI22[tooltip=\"I22\nG->+.TG,)\nT->.FS,)|+|-\nF->.(E),)|*|+|-|/\nF->.i,)|*|+|-|/\n\" ];\nI23[tooltip=\"I23\nG->-.TG,)\nT->.FS,)|+|-\nF->.(E),)|*|+|-|/\nF->.i,)|*|+|-|/\n\" ];\nI24[tooltip=\"I24\nE->TG.,)\n\" ];\nI25[tooltip=\"I25\nS->*F.S,+|-|#\nS->.*FS,+|-|#\nS->./FS,+|-|#\nS->@.,+|-|#\n\" ];\nI26[tooltip=\"I26\nS->/F.S,+|-|#\nS->.*FS,+|-|#\nS->./FS,+|-|#\nS->@.,+|-|#\n\" ];\nI27[tooltip=\"I27\nG->+T.G,#\nG->.+TG,#\nG->.-TG,#\nG->@.,#\n\" ];\nI28[tooltip=\"I28\nG->-T.G,#\nG->.+TG,#\nG->.-TG,#\nG->@.,#\n\" ];\nI29[tooltip=\"I29\nF->(E).,)|*|+|-|/\n\" ];\nI30[tooltip=\"I30\nS->*F.S,)|+|-\nS->.*FS,)|+|-\nS->./FS,)|+|-\nS->@.,)|+|-\n\" ];\nI31[tooltip=\"I31\nS->/F.S,)|+|-\nS->.*FS,)|+|-\nS->./FS,)|+|-\nS->@.,)|+|-\n\" ];\nI32[tooltip=\"I32\nG->+T.G,)\nG->.+TG,)\nG->.-TG,)\nG->@.,)\n\" ];\nI33[tooltip=\"I33\nG->-T.G,)\nG->.+TG,)\nG->.-TG,)\nG->@.,)\n\" ];\nI34[tooltip=\"I34\nS->*FS.,+|-|#\n\" ];\nI35[tooltip=\"I35\nS->/FS.,+|-|#\n\" ];\nI36[tooltip=\"I36\nG->+TG.,#\n\" ];\nI37[tooltip=\"I37\nG->-TG.,#\n\" ];\nI38[tooltip=\"I38\nS->*FS.,)|+|-\n\" ];\nI39[tooltip=\"I39\nS->/FS.,)|+|-\n\" ];\nI40[tooltip=\"I40\nG->+TG.,)\n\" ];\nI41[tooltip=\"I41\nG->-TG.,)\n\" ];\nI0 -> I1[label=\"(\"];I0 -> I2[label=\"E\"];I0 -> I3[label=\"F\"];I0 -> I4[label=\"T\"];I0 -> I5[label=\"i\"];I1 -> I6[label=\"(\"];I1 -> I7[label=\"E\"];I1 -> I8[label=\"F\"];I1 -> I9[label=\"T\"];I1 -> I10[label=\"i\"];I3 -> I11[label=\"*\"];I3 -> I12[label=\"/\"];I3 -> I13[label=\"S\"];I4 -> I14[label=\"+\"];I4 -> I15[label=\"-\"];I4 -> I16[label=\"G\"];I6 -> I6[label=\"(\"];I6 -> I17[label=\"E\"];I6 -> I8[label=\"F\"];I6 -> I9[label=\"T\"];I6 -> I10[label=\"i\"];I7 -> I18[label=\")\"];I8 -> I19[label=\"*\"];I8 -> I20[label=\"/\"];I8 -> I21[label=\"S\"];I9 -> I22[label=\"+\"];I9 -> I23[label=\"-\"];I9 -> I24[label=\"G\"];I11 -> I1[label=\"(\"];I11 -> I25[label=\"F\"];I11 -> I5[label=\"i\"];I12 -> I1[label=\"(\"];I12 -> I26[label=\"F\"];I12 -> I5[label=\"i\"];I14 -> I1[label=\"(\"];I14 -> I3[label=\"F\"];I14 -> I27[label=\"T\"];I14 -> I5[label=\"i\"];I15 -> I1[label=\"(\"];I15 -> I3[label=\"F\"];I15 -> I28[label=\"T\"];I15 -> I5[label=\"i\"];I17 -> I29[label=\")\"];I19 -> I6[label=\"(\"];I19 -> I30[label=\"F\"];I19 -> I10[label=\"i\"];I20 -> I6[label=\"(\"];I20 -> I31[label=\"F\"];I20 -> I10[label=\"i\"];I22 -> I6[label=\"(\"];I22 -> I8[label=\"F\"];I22 -> I32[label=\"T\"];I22 -> I10[label=\"i\"];I23 -> I6[label=\"(\"];I23 -> I8[label=\"F\"];I23 -> I33[label=\"T\"];I23 -> I10[label=\"i\"];I25 -> I11[label=\"*\"];I25 -> I12[label=\"/\"];I25 -> I34[label=\"S\"];I26 -> I11[label=\"*\"];I26 -> I12[label=\"/\"];I26 -> I35[label=\"S\"];I27 -> I14[label=\"+\"];I27 -> I15[label=\"-\"];I27 -> I36[label=\"G\"];I28 -> I14[label=\"+\"];I28 -> I15[label=\"-\"];I28 -> I37[label=\"G\"];I30 -> I19[label=\"*\"];I30 -> I20[label=\"/\"];I30 -> I38[label=\"S\"];I31 -> I19[label=\"*\"];I31 -> I20[label=\"/\"];I31 -> I39[label=\"S\"];I32 -> I22[label=\"+\"];I32 -> I23[label=\"-\"];I32 -> I40[label=\"G\"];I33 -> I22[label=\"+\"];I33 -> I23[label=\"-\"];I33 -> I41[label=\"G\"];Grammar -> I0[style=invis];}"}, 53 | "parser": [ 54 | {"statusStack": " 0 ", "parseStack": "", "inStrStack": "i+i*i#", "action": "SHIFT"} 55 | , {"statusStack": " 0 5 ", "parseStack": "i", "inStrStack": "+i*i#", "action": "REDUCE F->i"} 56 | , {"statusStack": " 0 3 ", "parseStack": "F", "inStrStack": "+i*i#", "action": "REDUCE S->@"} 57 | , {"statusStack": " 0 3 13 ", "parseStack": "FS", "inStrStack": "+i*i#", "action": "REDUCE T->FS"} 58 | , {"statusStack": " 0 4 ", "parseStack": "T", "inStrStack": "+i*i#", "action": "SHIFT"} 59 | , {"statusStack": " 0 4 14 ", "parseStack": "T+", "inStrStack": "i*i#", "action": "SHIFT"} 60 | , {"statusStack": " 0 4 14 5 ", "parseStack": "T+i", "inStrStack": "*i#", "action": "REDUCE F->i"} 61 | , {"statusStack": " 0 4 14 3 ", "parseStack": "T+F", "inStrStack": "*i#", "action": "SHIFT"} 62 | , {"statusStack": " 0 4 14 3 11 ", "parseStack": "T+F*", "inStrStack": "i#", "action": "SHIFT"} 63 | , {"statusStack": " 0 4 14 3 11 5 ", "parseStack": "T+F*i", "inStrStack": "#", "action": "REDUCE F->i"} 64 | , {"statusStack": " 0 4 14 3 11 25 ", "parseStack": "T+F*F", "inStrStack": "#", "action": "REDUCE S->@"} 65 | , {"statusStack": " 0 4 14 3 11 25 34 ", "parseStack": "T+F*FS", "inStrStack": "#", "action": "REDUCE S->*FS"} 66 | , {"statusStack": " 0 4 14 3 13 ", "parseStack": "T+FS", "inStrStack": "#", "action": "REDUCE T->FS"} 67 | , {"statusStack": " 0 4 14 27 ", "parseStack": "T+T", "inStrStack": "#", "action": "REDUCE G->@"} 68 | , {"statusStack": " 0 4 14 27 36 ", "parseStack": "T+TG", "inStrStack": "#", "action": "REDUCE G->+TG"} 69 | , {"statusStack": " 0 4 16 ", "parseStack": "TG", "inStrStack": "#", "action": "REDUCE E->TG"} 70 | , {"statusStack": " 0 2 ", "parseStack": "E", "inStrStack": "#", "action": "ACCEPT"}] 71 | } 72 | -------------------------------------------------------------------------------- /LR/LR.cpp: -------------------------------------------------------------------------------- 1 | /************************************************************************* 2 | > File Name: LR.cpp 3 | > Author: Netcan 4 | > Blog: http://www.netcan666.com 5 | > Mail: 1469709759@qq.com 6 | > Created Time: 2016-10-17 一 21:03:17 CST 7 | 8 | __----~~~~~~~~~~~------___ 9 | . . ~~//====...... __--~ ~~ 10 | -. \_|// |||\\ ~~~~~~::::... /~ 11 | ___-==_ _-~o~ \/ ||| \\ _/~~- 12 | __---~~~.==~||\=_ -_--~/_-~|- |\\ \\ _/~ 13 | _-~~ .=~ | \\-_ '-~7 /- / || \ / 14 | .~ .~ | \\ -_ / /- / || \ / 15 | / ____ / | \\ ~-_/ /|- _/ .|| \ / 16 | |~~ ~~|--~~~~--_ \ ~==-/ | \~--===~~ .\ 17 | ' ~-| /| |-~\~~ __--~~ 18 | |-~~-_/ | | ~\_ _-~ /\ 19 | / \ \__ \/~ \__ 20 | _--~ _/ | .-~~____--~-/ ~~==. 21 | ((->/~ '.|||' -_| ~~-/ , . _|| 22 | -_ ~\ ~~---l__i__i__i--~~_/ 23 | _-~-__ ~) \--______________--~~ 24 | //.-~~~-~_--~- |-------~~~~~~~~ 25 | //.-~~~--\ 26 | 神兽保佑,代码无BUG! 27 | ************************************************************************/ 28 | 29 | #include "LR.h" 30 | setItem::Vn; // 全局静态变量 31 | setItem::Vt; 32 | setItem::Symbol; 33 | const char*LR::actionStatStr[] = { 34 | "acc", 35 | "s", 36 | "r" 37 | }; 38 | 39 | string Prod::displayStr() const{ 40 | string p = string(1, noTerminal) + "->" + right.c_str(); 41 | int i = 0; 42 | for(const auto& c:additionalVt) 43 | if(c != '#') p += string(1, i++==0?',':'|') + c; // #放到最后显示 44 | if(additionalVt.find('#') != additionalVt.end()) p += string(1, i++==0?',':'|') + "#"; 45 | return p; 46 | } 47 | 48 | Prod::Prod(const string &in) { 49 | // printf("%s\n", in.c_str()); 50 | noTerminal = in[0]; 51 | right = cut(in, 3, in.length()); // A->X1X2X3X4 52 | } 53 | 54 | void Item::add(const string &prod) { 55 | if(prod.length() < 4) return; 56 | char noTerminal; 57 | if(Prod::cut(prod, 1, 3) == "->" && (isupper(prod[0]))) // A->...则noTerminal = A 58 | noTerminal = prod[0]; 59 | else return; 60 | 61 | for(unsigned int i=0; i' && ++i)) { 68 | Vt.insert(c); 69 | Symbol.insert(c); 70 | } 71 | } 72 | 73 | for(unsigned int i=3; i"+Prod::cut(prod, i, j)); 77 | if(find(prods.begin(), prods.end(), p) == prods.end()) // 去重 78 | prods.push_back(p); 79 | i = j; 80 | } 81 | } 82 | 83 | void Item::display() const { 84 | for(const auto& prod: prods) 85 | cout << prod.displayStr() << endl; 86 | } 87 | 88 | void LR::add(const string &s) { 89 | G.add(s); 90 | } 91 | 92 | void LR::loadStr(const string &in) { 93 | inStr.push_back('#'); 94 | status.push_back(0); 95 | for(int i = in.length() - 1; i>=0; --i) 96 | inStr.push_back(in[i]); 97 | } 98 | 99 | void LR::showStrStack() { 100 | for(vector::reverse_iterator it = inStr.rbegin(); it != inStr.rend(); ++it) 101 | printf("%c", *it); 102 | } 103 | 104 | 105 | void LR::showStatusStack() { 106 | for(vector::iterator it = status.begin(); it != status.end(); ++it) { 107 | if(*it < 10) printf(" %d ", *it); 108 | else printf(" %d ", *it); 109 | } 110 | } 111 | 112 | void LR::showParseStack() { 113 | for(vector::iterator it = parse.begin(); it != parse.end(); ++it) 114 | printf("%c", *it); 115 | } 116 | 117 | void LR::parser() { 118 | printf("\"parser\": ["); 119 | 120 | bool success = false; 121 | int step = 0; 122 | while(! success) { 123 | // printf("%d\t", step); 124 | printf("%s{", step == 0?"\n":"\n, "); 125 | printf("\"statusStack\": \""); 126 | showStatusStack(); 127 | printf("\", \"parseStack\": \""); 128 | showParseStack(); 129 | printf("\", \"inStrStack\": \""); 130 | showStrStack(); 131 | printf("\", \"action\": "); 132 | 133 | int sTop = status.size() - 1; // 栈顶 134 | int iTop = inStr.size() - 1; 135 | pair p = make_pair(status[sTop], inStr[iTop]); 136 | if(ACTION.find(p) == ACTION.end()) // 出错! 137 | break; 138 | pair act = ACTION[p]; 139 | if(act.first == SHIFT) { // 移进 140 | printf("\"SHIFT\"}"); 141 | 142 | status.push_back(act.second); 143 | parse.push_back(inStr[iTop]); 144 | inStr.pop_back(); 145 | } else if(act.first == REDUCE){ 146 | Prod p = G.prods[act.second]; 147 | printf("\"REDUCE %c->%s\"}", p.noTerminal, p.right.c_str()); 148 | 149 | if(p.right != "@") // 空串,无需出栈,直接规约 150 | for(unsigned i=0; ia.Bc,d 182 | char X = prod.right[pointLoc + 1]; 183 | if(G.Vt.find(X) != G.Vt.end()) { // 终结符 184 | if(X == '@') // @特殊处理 185 | swap(I.prods[i].right[pointLoc], I.prods[i].right[pointLoc + 1]); 186 | continue; 187 | } 188 | 189 | string f = Prod::cut(prod.right, pointLoc+2, prod.right.length()); 190 | // prod.display(); 191 | // printf("f: %s\n", f.c_str()); 192 | // printf("===================="); 193 | set ff = {}; 194 | for(const auto& c: prod.additionalVt) { 195 | set fs = first(f + c); 196 | ff.insert(fs.begin(), fs.end()); 197 | } 198 | 199 | // if(ff == set{'#'} && prod.noTerminal != EXTENSION_NOTERMINAL) // 只含#,那么把Follow集加进来 200 | // ff.insert(FOLLOW[prod.noTerminal].begin(), FOLLOW[prod.noTerminal].end()); 201 | 202 | 203 | for(vector::iterator it = G.prods.begin(); it != G.prods.end(); ++it) { 204 | if(*it == X) { // 找到产生式 205 | Prod p = *it; 206 | if(p.right[0] == '@') { // 特殊处理.@ => @. 207 | p.right = '.' + p.right; 208 | swap(p.right[0], p.right[1]); 209 | } else 210 | p.right = '.' + p.right; 211 | 212 | vector::iterator Iit = find(I.prods.begin(), I.prods.end(), p); // 找I中是否存在产生式 213 | if(Iit != I.prods.end()) // 找到 214 | Iit->additionalVt.insert(ff.begin(), ff.end()); 215 | else { 216 | p.additionalVt.insert(ff.begin(), ff.end()); 217 | I.prods.push_back(p); 218 | } 219 | } 220 | } 221 | } 222 | } 223 | // } 224 | return I; 225 | } 226 | 227 | Item LR::Goto(const Item& I, char X) { 228 | Item J; 229 | if(I.prods.size() == 0 || X == '@') return J; // 项目集为空或者@则返回空项目 230 | 231 | for(const auto& p: I.prods) {// I中的每个项目 232 | string right = p.right; 233 | unsigned long pointLoc = right.find('.'); 234 | if(right[pointLoc + 1] == X) { 235 | swap(right[pointLoc], right[pointLoc + 1]); 236 | J.prods.push_back(Prod(p.noTerminal, right, p.additionalVt)); 237 | } 238 | } 239 | return closure(J); 240 | } 241 | 242 | void LR::items() {// 求项目集状态机DFA!! 243 | Item initial; 244 | initial.prods.push_back(Prod(EXTENSION_NOTERMINAL, '.' + string(1, G.prods[0].noTerminal), {'#'})); // 初值,^->.S,# 245 | C.push_back(closure(initial)); // 置C初值 246 | size_t size = 0; 247 | while(size != C.size()) { // 当没有项目集加入C中 248 | size = C.size(); 249 | // for(auto &I: C) { // C的每个项目集,这样写有坑!! 250 | for(unsigned int i=0; i({'#'})) // S'->S.,# acction[i, #] = acc 288 | ACTION[make_pair(i, '#')] = make_pair(ACCEPT, 0); 289 | else if(prod.noTerminal != EXTENSION_NOTERMINAL) { 290 | string right = prod.right; 291 | right.erase(pointLoc, 1); // 删除. 292 | for(const auto& X: prod.additionalVt) { // A->a.,b,枚举b 293 | vector::iterator it = find(G.prods.begin(), G.prods.end(), Prod(prod.noTerminal, right, set{})); 294 | if(it != G.prods.end()) // 找到了 295 | ACTION[make_pair(i, X)] = make_pair(REDUCE, it - G.prods.begin()); 296 | } 297 | } 298 | } 299 | } 300 | } 301 | if(G.Vt.find('@') != G.Vt.end()) { // 删除@,移进# 302 | G.Vt.erase(G.Vt.find('@')); 303 | G.Symbol.erase(G.Symbol.find('@')); 304 | } 305 | G.Vt.insert('#'); 306 | G.Symbol.insert('#'); 307 | } 308 | 309 | void LR::showTable() { 310 | printf("\"parseTable\": {\n"); 311 | printf("\"Vt\": ["); 312 | 313 | for(const auto & X: G.Vt) { 314 | if(X != '#') 315 | printf("\"%c\", ", X); 316 | } 317 | printf("\"%c\"", '#'); // #放到最后一列显示,美观 318 | printf("],\n\"Vn\": ["); 319 | 320 | int firstComma = 0; // 处理第一个逗号 321 | for(const auto & X: G.Vn) 322 | printf("%s\"%c\"", firstComma++ == 0?" ":", ",X); 323 | printf("],\n\"Body\": [\n"); 324 | 325 | for(unsigned int i=0; i p = make_pair(i, X); 331 | if(ACTION.find(p) != ACTION.end()) { 332 | pair res = ACTION[p]; 333 | printf("%s\"%s%d\"", firstComma++ == 0?" ":", ", actionStatStr[res.first], res.second); 334 | } 335 | else printf("%s\"\"", firstComma++ == 0?" ":", "); 336 | } 337 | } 338 | 339 | pair p = make_pair(i, '#'); 340 | if(ACTION.find(p) != ACTION.end()) { 341 | pair res = ACTION[p]; 342 | printf("%s\"%s", firstComma++ == 0?" ":", ", actionStatStr[res.first]); 343 | if(res.first != ACCEPT) 344 | printf("%d\"", res.second); 345 | else printf("\""); 346 | } 347 | else printf("%s\"\"", firstComma++ == 0?" ":", "); 348 | 349 | for(const auto & X: G.Vn) { 350 | pair p = make_pair(i, X); 351 | if(GOTO.find(p) != GOTO.end()) 352 | printf("%s%d", firstComma++ == 0?" ":", ", GOTO[make_pair(i, X)]); 353 | else printf("%s\"\"", firstComma++ == 0?" ":", "); 354 | } 355 | puts("]"); 356 | } 357 | 358 | printf("]}\n"); 359 | } 360 | 361 | set LR::first(const string &s) { // s不为产生式! 362 | if(s.length() == 0) 363 | return set({'@'}); 364 | else if(s.length() == 1) { 365 | if(G.Vt.find(s[0]) != G.Vt.end() || s[0] == '#') // 终结符 366 | return set({s[0]}); 367 | else 368 | if(FIRST[s[0]].size() != 0) return FIRST[s[0]]; 369 | else { 370 | for(vector::iterator it = G.prods.begin(); it != G.prods.end(); ++it) 371 | if(*it == s[0]) { 372 | // 防止直接左递归 373 | size_t xPos = it->right.find(it->noTerminal); 374 | // printf("prod: %s right: %s\n", it->displayStr().c_str(), it->right.c_str()); 375 | if(xPos != string::npos) { // 找到X->aXb 376 | if(xPos == 0) continue; // X->Xb 377 | else { // X->aXb 378 | string a = Prod::cut(it->right, 0, xPos); 379 | if(first(a) == set{'@'}) continue; 380 | } 381 | } 382 | set f = first(it->right); 383 | FIRST[s[0]].insert(f.begin(), f.end()); 384 | } 385 | // printf("first(%s) = ", s.c_str()); 386 | // for(auto c: FIRST[s[0]]) 387 | // printf("%c, ", c); 388 | // puts(""); 389 | 390 | return FIRST[s[0]]; 391 | } 392 | } else { // first(X1X2X3X4)... 393 | set ret; 394 | for(unsigned int i=0; i f = first(string(1, s[i])); // 逐个符号求first(Xi)集 396 | if(f.find('@') != f.end() && s.length() - 1 != i) { // 发现@ 397 | f.erase(f.find('@')); // 减去@ 398 | ret.insert(f.begin(), f.end()); // 放入first集合 399 | } else { // 无@或者最后一个Xi,则不需要求下去了 400 | ret.insert(f.begin(), f.end()); 401 | break; 402 | } 403 | } 404 | return ret; 405 | } 406 | } 407 | 408 | 409 | void LR::follow() { 410 | FOLLOW[G.prods[0].noTerminal].insert('#'); // 开始符号放'#' 411 | for(auto pp: G.prods) { // 直到follow(X)不在增大 412 | unsigned int size = 0; 413 | while(size != FOLLOW[pp.noTerminal].size()) { 414 | size = FOLLOW[pp.noTerminal].size(); 415 | for(auto prod: G.prods) { // 求出所有非终结符的follow集合 416 | char X = prod.noTerminal; 417 | for(auto p: G.prods) {// 求出X的follow集合 418 | string s = p.right; 419 | unsigned long loc = 0; 420 | if((loc = s.find(X)) != string::npos) { // 找到非终结符X 421 | set f = first(string(s.begin() + loc + 1, s.end())); // 求first(b) 422 | FOLLOW[X].insert(f.begin(), f.end()); // 加入到follow(X)中 423 | if(f.find('@') != f.end()) {// 找到@ 424 | FOLLOW[X].erase(FOLLOW[X].find('@')); // 删除@ 425 | set fw = FOLLOW[p.noTerminal]; // 把follow(A)放入follow(X) 426 | FOLLOW[X].insert(fw.begin(), fw.end()); 427 | } 428 | } 429 | } 430 | } 431 | } 432 | } 433 | } 434 | 435 | void LR::debug() { 436 | string in; 437 | while(cin >> in && in != "#") 438 | add(in); 439 | 440 | puts("=====Proj:======"); 441 | for(auto pro: G.prods) 442 | printf("%s\n", (string(1, pro.noTerminal) + "->" + pro.right).c_str()); 443 | puts("=====Vt:======"); 444 | for(auto vt: G.Vt) 445 | printf("%c, ", vt); 446 | puts("\n=====Vn:======"); 447 | for(auto vn: G.Vn) 448 | printf("%c, ", vn); 449 | // puts("\n=====FIRST:======"); 450 | // set f = first("S"); 451 | // for(auto c: f) 452 | // printf("%c, ", c); 453 | puts(""); 454 | // puts("\n=====Item:======"); 455 | // Item I; 456 | // I.prods.push_back(Prod('B', "b.B", {'b', 'a'})); 457 | // I = closure(I); 458 | // for(auto prod: I.prods) 459 | // prod.display(); 460 | build(); 461 | showGrammar(); 462 | 463 | in = ""; 464 | cin >> in; 465 | if(in == "#" || in.size() == 0) return; 466 | loadStr(in); 467 | parser(); 468 | puts(""); 469 | } 470 | 471 | void LR::showGrammar() { 472 | printf("\"Grammar\": [\n"); 473 | for(const auto & p: G.prods) 474 | printf("%s\"%c->%s\"", (&p - &G.prods[0]) == 0?" ":", ", p.noTerminal, p.right.c_str()); 475 | printf("\n]\n"); 476 | } 477 | 478 | string Prod::replaceAll(const string &in, const string from, const string to) { 479 | size_t replacePos = in.find(from); 480 | string res = in; 481 | if(replacePos != string::npos) 482 | res.replace(replacePos, from.length(), to); 483 | return res; 484 | } 485 | 486 | void LR::drawGraph() { 487 | printf("\"Graph\": {"); 488 | // 图的全部信息 489 | printf("\"All\": \""); 490 | printf("digraph all{" 491 | "node [shape=box style=filled];" 492 | ); 493 | // 文法信息 494 | printf("Grammar[style=rounded label=\\\"Grammar\\n"); 495 | for(const auto &prod: G.prods) 496 | printf("%s\\n", prod.displayStr().c_str()); 497 | printf("\\\" ];\\n"); 498 | 499 | // 画节点 500 | for(const auto &I: C) { // 遍历项目集 501 | int i = &I - &C[0]; 502 | printf("I%d[label=\\\"I%d\\n", i, i); 503 | for(const auto &p: I.prods) { // 列出项目 504 | string res = p.displayStr(); 505 | if(res.find('^') != string::npos) 506 | res = Prod::replaceAll(res, "^", string(1, G.prods[0].noTerminal)+"'"); 507 | printf("%s\\n", res.c_str()); 508 | } 509 | printf("\\\" ];\\n"); 510 | } 511 | 512 | // 画边 513 | for(const auto &link: GOTO) { 514 | int i = link.first.first; 515 | string X = string(1, link.first.second); 516 | int j = link.second; 517 | printf("I%d -> I%d[label=\\\"%s\\\"];", i, j, X.c_str()); 518 | } 519 | printf("Grammar -> I0[style=invis];"); 520 | printf("}\"\n, "); 521 | 522 | // 图的简要信息 523 | printf("\"Simple\": \""); 524 | printf("digraph simple {" 525 | "node [shape = circle style=filled];" 526 | ); 527 | // 文法信息 528 | printf("Grammar[shape=box style=rounded label=\\\"Grammar\\n"); 529 | for(const auto &prod: G.prods) 530 | printf("%s\\n", prod.displayStr().c_str()); 531 | printf("\\\" ];\\n"); 532 | 533 | // 画节点 534 | for(const auto &I: C) { // 遍历项目集 535 | int i = &I - &C[0]; 536 | printf("I%d[tooltip=\\\"I%d\\n", i, i); 537 | for(const auto &p: I.prods) { // 列出项目 538 | string res = p.displayStr(); 539 | if(res.find('^') != string::npos) 540 | res = Prod::replaceAll(res, "^", string(1, G.prods[0].noTerminal)+"'"); 541 | printf("%s\\n", res.c_str()); 542 | } 543 | printf("\\\" ];\\n"); 544 | } 545 | // 画边 546 | for(const auto &link: GOTO) { 547 | int i = link.first.first; 548 | string X = string(1, link.first.second); 549 | int j = link.second; 550 | printf("I%d -> I%d[label=\\\"%s\\\"];", i, j, X.c_str()); 551 | } 552 | printf("Grammar -> I0[style=invis];"); 553 | 554 | printf("}\""); 555 | printf("}"); 556 | 557 | } 558 | 559 | void LR::generateDot() { 560 | printf("digraph all{\n" 561 | "node [shape=box style=filled];\n" 562 | ); 563 | // 文法信息 564 | printf("Grammar[style=rounded label=\"Grammar\n"); 565 | for(const auto &prod: G.prods) 566 | printf("%s\n", prod.displayStr().c_str()); 567 | printf("\" ];\n"); 568 | 569 | // 画节点 570 | for(const auto &I: C) { // 遍历项目集 571 | int i = &I - &C[0]; 572 | printf("I%d[label=\"I%d\n", i, i); 573 | for(const auto &p: I.prods) { // 列出项目 574 | string res = p.displayStr(); 575 | if(res.find('^') != string::npos) 576 | res = Prod::replaceAll(res, "^", string(1, G.prods[0].noTerminal)+"'"); 577 | printf("%s\n", res.c_str()); 578 | } 579 | printf("\" ];\n"); 580 | } 581 | 582 | // 画边 583 | for(const auto &link: GOTO) { 584 | int i = link.first.first; 585 | string X = string(1, link.first.second); 586 | int j = link.second; 587 | printf("I%d -> I%d[label=\"%s\"];\n", i, j, X.c_str()); 588 | } 589 | printf("Grammar -> I0[style=invis];"); 590 | printf("\n}\n"); 591 | } 592 | 593 | void LR::run() { 594 | string in; 595 | while(cin >> in && in != "#") 596 | add(in); 597 | in = ""; 598 | 599 | printf("{"); 600 | showGrammar(); 601 | printf(","); 602 | 603 | build(); 604 | showTable(); 605 | printf(","); 606 | 607 | drawGraph(); 608 | printf(",\n"); 609 | 610 | cin >> in; 611 | if(in == "#" || in.size() == 0) return; 612 | loadStr(in); 613 | parser(); 614 | printf("}\n"); 615 | } 616 | 617 | #ifndef _GENERATE_DOT_ 618 | int main() { 619 | LR lr; 620 | lr.run(); 621 | 622 | return 0; 623 | } 624 | #endif 625 | 626 | 627 | --------------------------------------------------------------------------------