Skip to content

Commit f4831c6

Browse files
author
Takanori MAEHARA
committed
Earley parser for context-free-grammar
1 parent 4381103 commit f4831c6

1 file changed

Lines changed: 110 additions & 0 deletions

File tree

string/earley.cc

Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
//
2+
// Earley Parser
3+
//
4+
// Description:
5+
// We are given CFG, i.e.,
6+
// A -> B
7+
// A -> aAa|bAb
8+
// B -> aa|bb
9+
// B -> a|b
10+
// It determines that a given string is matched by the CFG.
11+
//
12+
// Algorithm:
13+
// Earley algorithm. It generates all states with memoisation.
14+
// Here, state is given by (rule, pos-in-rule, pos-in-text).
15+
//
16+
// Complexity:
17+
// O(|G|^2 n^3) in the worst case.
18+
// If a grammar is simple, it usually reduced to O(|G|^2 n^2).
19+
//
20+
// Remark:
21+
// Because of simplicity, This implementation does not allow the
22+
// epsilon rule. Please expand epsilon rule by hand.
23+
// (TODO!)
24+
//
25+
//
26+
#include <iostream>
27+
#include <vector>
28+
#include <cstdio>
29+
#include <algorithm>
30+
#include <functional>
31+
32+
using namespace std;
33+
34+
#define fst first
35+
#define snd second
36+
#define all(c) ((c).begin()), ((c).end())
37+
38+
struct earley_parser {
39+
vector<int> terminal;
40+
vector<vector<vector<int>>> grammar;
41+
int add_symbol(char c = 0) {
42+
terminal.push_back(c);
43+
grammar.push_back({});
44+
return grammar.size()-1;
45+
}
46+
void add_grammar(int A, vector<int> As) {
47+
As.push_back(0);
48+
grammar[A].push_back(As);
49+
}
50+
earley_parser() { add_symbol(); add_symbol(); }
51+
bool parse(const char s[], int init) {
52+
int n = strlen(s);
53+
struct state { int a, k, p, i; };
54+
vector<vector<vector<state>>> chart(n+1, vector<vector<state>>(grammar.size()));
55+
auto enqueue = [&](vector<state> &curr, const state &S) {
56+
for (auto &T: curr)
57+
if (T.a == S.a && T.k == S.k && T.p == S.p && T.i == S.i) return;
58+
curr.push_back(S);
59+
};
60+
auto symbol = [&](const state &S) { return grammar[S.a][S.k][S.p]; };
61+
grammar[1] = { {init, 0} };
62+
vector<state> curr = {{1, 0, 0, 0}}, next;
63+
for (int k = 0; k <= n; ++k) {
64+
for (int i = 0; i < curr.size(); ++i) {
65+
state S = curr[i];
66+
int B = symbol(S);
67+
if (B) {
68+
if (!terminal[B]) {
69+
for (int j = 0; j < grammar[B].size(); ++j)
70+
enqueue(curr, {B, j, 0, k});
71+
} else if (terminal[B] == s[k]) {
72+
enqueue(next, {S.a, S.k, S.p+1, S.i});
73+
}
74+
} else {
75+
for (auto &T: chart[S.i][S.a])
76+
enqueue(curr, {T.a, T.k, T.p+1, T.i});
77+
}
78+
}
79+
for (auto &T: curr)
80+
chart[k][symbol(T)].push_back(T);
81+
curr.swap(next);
82+
next.clear();
83+
}
84+
for (auto &T: chart[n][0])
85+
if (T.a == 1) return true;
86+
return false;
87+
}
88+
};
89+
90+
int main() {
91+
earley_parser parser;
92+
// A -> B
93+
// A -> aAa|bAb
94+
// B -> aa|bb
95+
// B -> a|b
96+
int A = parser.add_symbol();
97+
int B = parser.add_symbol();
98+
int a = parser.add_symbol('a');
99+
int b = parser.add_symbol('b');
100+
parser.add_grammar(A, {B});
101+
parser.add_grammar(A, {a,A,a});
102+
parser.add_grammar(A, {b,A,b});
103+
parser.add_grammar(B, {a});
104+
parser.add_grammar(B, {b});
105+
parser.add_grammar(B, {a,a});
106+
parser.add_grammar(B, {b,b});
107+
for (char s[1024]; cin >> s; ) {
108+
cout << parser.parse(s, A) << endl;
109+
}
110+
}

0 commit comments

Comments
 (0)