例子:select * from a left join b where a.id = 1 and (b.id = a.id or a.num*3 = 7)
首先,我们需要构建文法的产生式集合:
- S’ -> S
- S -> SELECT FROM TABLE WHERE
- SELECT -> select *
- FROM -> from TABLE
- TABLE -> table1 left join table2
- WHERE -> EXP and EXP
- WHERE -> (EXP or EXP)
- EXP -> TABLE PROPERTY OP VALUE
- EXP -> TABLE PROPERTY OP TABLE PROPERTY
- EXP -> EXP and EXP
- EXP -> (EXP or EXP)
- TABLE -> a
- TABLE -> b
- PROPERTY -> id
- PROPERTY -> num
- OP -> *
- OP -> =
接下来,我们构建项目集族和LR(1)分析表。
首先,计算项目集族的闭包:
I0:
S’ -> . S
S -> . SELECT FROM TABLE WHERE
S -> . SELECT FROM TABLE
S -> . SELECT FROM
S -> . SELECT
SELECT -> . select *
FROM -> . from TABLE
TABLE -> . table1 left join table2
TABLE -> . a
TABLE -> . b
PROPERTY -> . id
PROPERTY -> . num
OP -> . *
OP -> . =
WHERE -> . EXP and EXP
WHERE -> . (EXP or EXP)
EXP -> . TABLE PROPERTY OP VALUE
EXP -> . TABLE PROPERTY OP TABLE PROPERTY
EXP -> . EXP and EXP
EXP -> . (EXP or EXP)
根据闭包操作,我们可以得到以下项目集:
I0:
S’ -> . S
S -> . SELECT FROM TABLE WHERE
S -> . SELECT FROM TABLE
S -> . SELECT FROM
S -> . SELECT
SELECT -> . select *
FROM -> . from TABLE
TABLE -> . table1 left join table2
TABLE -> . a
TABLE -> . b
PROPERTY -> . id
PROPERTY -> . num
OP -> . *
OP -> . =
WHERE -> . EXP and EXP
WHERE -> . (EXP or EXP)
EXP -> . TABLE PROPERTY OP VALUE
EXP -> . TABLE PROPERTY OP TABLE PROPERTY
EXP -> . EXP and EXP
EXP -> . (EXP or EXP)
I1:
S’ -> S .
I2:
S -> SELECT . FROM TABLE WHERE
S -> SELECT . FROM TABLE
I3:
FROM -> from . TABLE
I4:
TABLE -> table1 . left join table2
I5:
TABLE -> a .
I6:
TABLE -> b .
I7:
PROPERTY -> id .
I8:
PROPERTY -> num .
I9:
OP -> * .
I10:
OP -> = .
I11:
WHERE -> EXP . and EXP
WHERE -> EXP . and EXP
I12:
WHERE -> ( EXP . or EXP
I13:
EXP -> TABLE . PROPERTY OP VALUE
EXP -> TABLE . PROPERTY OP TABLE PROPERTY
EXP -> EXP . and EXP
EXP -> EXP . and EXP
I14:
EXP -> ( EXP . or EXP
I15:
EXP -> TABLE PROPERTY . OP VALUE
EXP -> TABLE PROPERTY . OP TABLE PROPERTY
I16:
EXP -> ( EXP . or EXP
I17:
EXP -> TABLE PROPERTY OP . VALUE
EXP -> TABLE PROPERTY OP . TABLE PROPERTY
I18:
EXP -> TABLE PROPERTY OP VALUE .
EXP -> TABLE PROPERTY OP TABLE PROPERTY .
I19:
WHERE -> EXP and . EXP
I20:
WHERE -> EXP and EXP .
I21:
WHERE -> ( EXP . or EXP
I22:
EXP -> ( EXP . or EXP
I23:
EXP -> ( EXP or . EXP
I24:
EXP -> ( EXP or EXP .
然后,我们可以根据项目集的转移操作,构建LR(1)分析表:
Action表:
select | * | from | table1 | left | join | table2 | a | b | id | num | = | ( | ) | and | or | $ | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | s3 | s4 | |||||||||||||||
1 | r3 | r3 | r3 | r3 | r3 | r3 | r3 | r3 | |||||||||
2 | r5 | r5 | r5 | r5 | r5 | r5 | r5 | r5 | |||||||||
3 | s6 | s7 | |||||||||||||||
4 | r7 | r7 | r7 | r7 | r7 | r7 | r7 | r7 | |||||||||
5 | r1 | ||||||||||||||||
6 | r4 | ||||||||||||||||
7 | r6 | ||||||||||||||||
8 | |||||||||||||||||
9 | s12 | ||||||||||||||||
10 | |||||||||||||||||
11 | s13 | ||||||||||||||||
12 | |||||||||||||||||
13 | s14 | ||||||||||||||||
14 | |||||||||||||||||
15 | r8 | ||||||||||||||||
16 | r9 |
Goto表:
select | * | from | table1 | left | join | table2 | a | b | id | num | = | ( | ) | and | or | $ | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | s3 | s4 | |||||||||||||||
1 | |||||||||||||||||
2 | |||||||||||||||||
3 | s6 | s7 | |||||||||||||||
4 | r7 | ||||||||||||||||
5 | r1 | ||||||||||||||||
6 | r4 | ||||||||||||||||
7 | r6 | ||||||||||||||||
8 | |||||||||||||||||
9 | s12 | ||||||||||||||||
10 | |||||||||||||||||
11 | s13 | ||||||||||||||||
12 | |||||||||||||||||
13 | s14 | ||||||||||||||||
14 | |||||||||||||||||
15 | r8 | ||||||||||||||||
16 | r9 |
接下来我们根据输入的符号进行移进和规约操作:
输入: select * from table1 left join table2 a on b.id = a.id and b.num = a.num
当前状态: 0
接下来的输入符号: select
根据Goto表,在状态0下,输入select,我们需要移进到状态3。
移进到状态3。
输入: * from table1 left join table2 a on b.id = a.id and b.num = a.num
当前状态: 3
接下来的输入符号: *
根据Goto表,在状态3下,输入*,我们需要移进到状态6。
移进到状态6。
输入: from table1 left join table2 a on b.id = a.id and b.num = a.num
当前状态: 6
接下来的输入符号: from
根据Goto表,在状态6下,输入from,我们需要移进到状态7。
移进到状态7。
输入: table1 left join table2 a on b.id = a.id and b.num = a.num
当前状态: 7
接下来的输入符号: table1
根据Goto表,在状态7下,输入table1,我们需要移进到状态12。
移进到状态12。
输入: left join table2 a on b.id = a.id and b.num = a.num
当前状态: 12
接下来的输入符号: left
根据Goto表,在状态12下,输入left,我们需要移进到状态13。
移进到状态13。
输入: join table2 a on b.id = a.id and b.num = a.num
当前状态: 13
接下来的输入符号: join
根据Goto表,在状态13下,输入join,我们需要移进到状态14。
移进到状态14。
输入: table2 a on b.id = a.id and b.num = a.num
当前状态: 14
接下来的输入符号: table2
根据Goto表,在状态14下,输入table2,我们需要移进到状态5。
移进到状态5。
输入: a on b.id = a.id and b.num = a.num
当前状态: 5
接下来的输入符号: a
根据Goto表,在状态5下,输入a,我们需要移进到状态8。
移进到状态8。
输入: on b.id = a.id and b.num = a.num
当前状态: 8
接下来的输入符号: on
根据Goto表,在状态8下,输入on,我们需要移进到状态9。
移进到状态9。
输入: b.id = a.id and b.num = a.num
当前状态: 9
接下来的输入符号: b.id
根据Goto表,在状态9下,输入b.id,我们需要移进到状态10。
移进到状态10。
输入: = a.id and b.num = a.num
当前状态: 10
接下来的输入符号: =
根据Goto表,在状态10下,输入=,我们需要移进到状态11。
移进到状态11。
输入: a.id and b.num = a.num
当前状态: 11
接下来的输入符号: a.id
根据Goto表,在状态11下,输入a.id,我们需要移进到状态15。
移进到状态15。
输入: and b.num = a.num
当前状态: 15
接下来的输入符号: and
根据Goto表,在状态15下,输入and,我们需要移进到状态16。
移进到状态16。
输入: b.num = a.num
当前状态: 16
接下来的输入符号: b.num
根据Goto表,在状态16下,输入b.num,我们需要移进到状态17。
移进到状态17。
输入: = a.num
当前状态: 17
接下来的输入符号: =
根据Goto表,在状态17下,输入=,我们需要移进到状态18。
移进到状态18。
输入: a.num
当前状态: 18
接下来的输入符号: a.num
根据Goto表,在状态18下,输入a.num,我们需要移进到状态19。
移进到状态19。
输入:
当前状态: 19
接下来的输入符号:
根据Goto表,在状态19下,输入空符号,我们需要进行规约操作。
根据规约动作表,我们使用规则R10,将状态19中的符号归约为expression。
当前状态: 9
接下来的输入符号: b.id
根据Goto表,在状态9下,输入b.id,我们需要移进到状态10。
移进到状态10。
输入: = a.id and b.num = a.num
当前状态: 10
接下来的输入符号: =
根据Goto表,在状态10下,输入=,我们需要移进到状态11。
移进到状态11。
输入: a.id and b.num = a.num
当前状态: 11
接下来的输入符号: a.id
根据Goto表,在状态11下,输入a.id,我们需要移进到状态15。
移进到状态15。
输入: and b.num = a.num
当前状态: 15
接下来的输入符号: and
根据Goto表,在状态15下,输入and,我们需要移进到状态16。
移进到状态16。
输入: b.num = a.num
当前状态: 16
接下来的输入符号: b.num
根据Goto表,在状态16下,输入b.num,我们需要移进到状态17。
移进到状态17。
输入: = a.num
当前状态: 17
接下来的输入符号: =
根据Goto表,在状态17下,输入=,我们需要移进到状态18。
移进到状态18。
输入: a.num
当前状态: 18
接下来的输入符号: a.num
根据Goto表,在状态18下,输入a.num,我们需要移进到状态19。
移进到状态19。
输入:
当前状态: 19
接下来的输入符号:
根据Goto表,在状态19下,输入空符号,我们需要进行规约操作。
根据规约动作表,我们使用规则R10,将状态19中的符号归约为expression。
当前状态: 10
接下来的输入符号:
根据Goto表,在状态10下,输入空符号,我们需要进行规约操作。
根据规约动作表,我们使用规则R8,将状态10中的符号归约为condition。
当前状态: 11
接下来的输入符号:
根据Goto表,在状态11下,输入空符号,我们需要进行规约操作。
根据规约动作表,我们使用规则R7,将状态11中的符号归约为expression。
当前状态: 15
接下来的输入符号:
根据Goto表,在状态15下,输入空符号,我们需要进行规约操作。
根据规约动作表,我们使用规则R6,将状态15中的符号归约为condition。
当前状态: 8
接下来的输入符号:
根据Goto表,在状态8下,输入空符号,我们需要进行规约操作。
根据规约动作表,我们使用规则R5,将状态8中的符号归约为expression。
当前状态: 5
接下来的输入符号:
根据Goto表,在状态5下,输入空符号,我们需要进行规约操作。
根据规约动作表,我们使用规则R4,将状态5中的符号归约为expression。
当前状态: 4
接下来的输入符号:
根据Goto表,在状态4下,输入空符号,我们需要进行规约操作。
根据规约动作表,我们使用规则R3,将状态4中的符号归约为expression。
当前状态: 3
接下来的输入符号:
根据Goto表,在状态3下,输入空符号,我们需要进行规约操作。
根据规约动作表,我们使用规则R2,将状态3中的符号归约为statement。
当前状态: 2
接下来的输入符号:
根据Goto表,在状态2下,输入空符号,我们需要进行规约操作。
根据规约动作表,我们使用规则R1,将状态2中的符号归约为program。
最后,我们得到了完整的语法分析树,输入的查询语句被成功解析。
#include <iostream>
#include <stack>
#include <unordered_map>
#include <vector>
using namespace std;
// Token 类型枚举
enum class TokenType {
SELECT, FROM, JOIN, WHERE, ID, EQUAL, NUM, AND, OR, LPAREN, RPAREN, END
};
// Token 类
struct Token {
TokenType type;
string lexeme;
};
// 产生式类
struct Production {
TokenType left;
vector<TokenType> right;
};
// Action 表
unordered_map<int, unordered_map<TokenType, int>> actionTable = {
{0, {{TokenType::SELECT, 1}}},
{1, {{TokenType::ID, 4}}},
{2, {{TokenType::FROM, 6}}},
{3, {{TokenType::ID, 5}}},
{4, {{TokenType::FROM, -5}}},
{5, {{TokenType::JOIN, 7}}},
{6, {{TokenType::JOIN, -6}, {TokenType::WHERE, 10}}},
{7, {{TokenType::ID, 8}}},
{8, {{TokenType::WHERE, 10}}},
{9, {{TokenType::AND, 16}, {TokenType::OR, 17}, {TokenType::RPAREN, 16}, {TokenType::END, -3}}},
{10, {{TokenType::ID, 11}}},
{11, {{TokenType::EQUAL, 12}}},
{12, {{TokenType::NUM, 13}, {TokenType::LPAREN, 14}}},
{13, {{TokenType::RPAREN, -4}, {TokenType::AND, -4}, {TokenType::OR, -4}, {TokenType::END, -4}}},
{14, {{TokenType::ID, 15}}},
{15, {{TokenType::EQUAL, 12}}},
{16, {{TokenType::ID, 11}}},
{17, {{TokenType::ID, 11}}}
};
// Goto 表
unordered_map<int, unordered_map<TokenType, int>> gotoTable = {
{0, {{TokenType::SELECT, 1}, {TokenType::FROM, 2}, {TokenType::JOIN, 3}}},
{4, {{TokenType::FROM, 5}}},
{6, {{TokenType::JOIN, 14}}},
{10, {{TokenType::WHERE, 15}}},
{12, {{TokenType::LPAREN, 18}}},
{16, {{TokenType::RPAREN, 19}}}
};
// LR(1) 语法分析器类
class LRParser {
public:
LRParser(const vector<Token>& tokens) : tokens(tokens) {}
void parse() {
stack<int> stateStack;
stack<Token> symbolStack;
stateStack.push(0);
int i = 0;
while (true) {
int currentState = stateStack.top();
Token currentToken = tokens[i];
int action = actionTable[currentState][currentToken.type];
if (action == 0) {
cout << "Accepted" << endl;
break;
} else if (action > 0) {
// 移进
stateStack.push(action);
symbolStack.push(currentToken);
i++;
cout<< currentToken.lexeme << endl;
} else if (action < 0) {
// 规约
Production production = grammar[-action];
TokenType nonterminal = production.left;
cout << "Reduce: ";
for (auto token : production.right) {
stateStack.pop();
symbolStack.pop();
}
cout<< currentToken.lexeme << endl;
int newState = gotoTable[stateStack.top()][nonterminal];
stateStack.push(newState);
symbolStack.push(Token{nonterminal, ""});
}
}
}
private:
vector<Token> tokens;
unordered_map<int, Production> grammar = {
{-1, {TokenType::SELECT, {TokenType::ID}}},
{-2, {TokenType::FROM, {TokenType::ID}}},
{-3, {TokenType::JOIN, {TokenType::ID}}},
{-4, {TokenType::WHERE, {TokenType::ID, TokenType::EQUAL, TokenType::NUM}}},
};
};
int main() {
vector<Token> tokens = {
{TokenType::SELECT, "select"},
{TokenType::ID, "*"},
{TokenType::FROM, "from"},
{TokenType::ID, "a"},
{TokenType::JOIN, "left join"},
{TokenType::ID, "b"},
{TokenType::WHERE, "where"},
{TokenType::ID, "a.id"},
{TokenType::NUM, "3"},
};
LRParser parser(tokens);
parser.parse();
return 0;
}