diff options
author | Sergio Queiroz <sqmedeiros@gmail.com> | 2016-11-29 18:38:55 -0300 |
---|---|---|
committer | Sergio Queiroz <sqmedeiros@gmail.com> | 2016-11-29 18:38:55 -0300 |
commit | a4bdec34353ad1849f99e6ab0e5f2ad5e74c83b1 (patch) | |
tree | a0654a2c516b01d39dbf4b0b978d8207eb045c30 | |
parent | e7e17699870f0bd6ba43b4e946297fb581d28b48 (diff) | |
download | lpeglabel-a4bdec34353ad1849f99e6ab0e5f2ad5e74c83b1.tar.gz lpeglabel-a4bdec34353ad1849f99e6ab0e5f2ad5e74c83b1.tar.bz2 lpeglabel-a4bdec34353ad1849f99e6ab0e5f2ad5e74c83b1.zip |
New example shows how to build recovery grammar semiautomatically
-rw-r--r-- | examples/expressionRecAut.lua | 132 | ||||
-rw-r--r-- | examples/expressionRecovery.lua | 3 |
2 files changed, 134 insertions, 1 deletions
diff --git a/examples/expressionRecAut.lua b/examples/expressionRecAut.lua new file mode 100644 index 0000000..e098078 --- /dev/null +++ b/examples/expressionRecAut.lua | |||
@@ -0,0 +1,132 @@ | |||
1 | local m = require"lpeglabelrec" | ||
2 | local re = require"relabelrec" | ||
3 | |||
4 | local R, S, P, V = m.R, m.S, m.P, m.V | ||
5 | local C, Cc, Ct, Cmt = m.C, m.Cc, m.Ct, m.Cmt | ||
6 | local T, Rec = m.T, m.Rec | ||
7 | |||
8 | local num = R("09")^1 / tonumber | ||
9 | local op = S("+-") | ||
10 | |||
11 | local labels = {} | ||
12 | local nlabels = 0 | ||
13 | |||
14 | local function newError(lab, msg, psync, pcap) | ||
15 | nlabels = nlabels + 1 | ||
16 | psync = psync or m.P(-1) | ||
17 | pcap = pcap or m.P"" | ||
18 | labels[lab] = { id = nlabels, msg = msg, psync = psync, pcap = pcap } | ||
19 | end | ||
20 | |||
21 | newError("ExpTermFirst", "expected an expression", op + ")", m.Cc(1000)) | ||
22 | newError("ExpTermOp", "expected a term after the operator", op + ")", m.Cc(1000)) | ||
23 | newError("MisClose", "missing a closing ')' after the expression", m.P")") | ||
24 | newError("Extra", "extra characters found after the expression") | ||
25 | |||
26 | local errors, subject | ||
27 | |||
28 | local function expect(patt, labname) | ||
29 | local i = labels[labname].id | ||
30 | return patt + T(i) | ||
31 | end | ||
32 | |||
33 | local function compute(tokens) | ||
34 | local result = tokens[1] | ||
35 | for i = 2, #tokens, 2 do | ||
36 | if tokens[i] == '+' then | ||
37 | result = result + tokens[i+1] | ||
38 | elseif tokens[i] == '-' then | ||
39 | result = result - tokens[i+1] | ||
40 | else | ||
41 | error('unknown operation: ' .. tokens[i]) | ||
42 | end | ||
43 | end | ||
44 | return result | ||
45 | end | ||
46 | |||
47 | local g = P { | ||
48 | "Exp", | ||
49 | Exp = Ct(V"OperandFirst" * (C(op) * V"Operand")^0) / compute, | ||
50 | OperandFirst = expect(V"Term", "ExpTermFirst"), | ||
51 | Operand = expect(V"Term", "ExpTermOp"), | ||
52 | Term = num + V"Group", | ||
53 | Group = "(" * V"Exp" * expect(")", "MisClose"), | ||
54 | } | ||
55 | |||
56 | function recorderror(pos, lab) | ||
57 | local line, col = re.calcline(subject, pos) | ||
58 | table.insert(errors, { line = line, col = col, msg = labels[lab].msg }) | ||
59 | end | ||
60 | |||
61 | function record (labname) | ||
62 | return (m.Cp() * m.Cc(labname)) / recorderror | ||
63 | end | ||
64 | |||
65 | function sync (p) | ||
66 | return (-p * m.P(1))^0 | ||
67 | end | ||
68 | |||
69 | function defaultValue (p) | ||
70 | return p or m.Cc(1000) | ||
71 | end | ||
72 | |||
73 | local recg2 = g | ||
74 | for k, v in pairs(labels) do | ||
75 | recg2 = Rec(recg2, record(k) * sync(v.psync) * v.pcap, v.id) | ||
76 | end | ||
77 | |||
78 | local recg = P { | ||
79 | "S", | ||
80 | S = Rec(V"A", V"ErrExpTermFirst", labels["ExpTermFirst"].id), -- default value is 0 | ||
81 | A = Rec(V"Sg", V"ErrExpTermOp", labels["ExpTermOp"].id), | ||
82 | Sg = Rec(g, V"ErrMisClose", labels["MisClose"].id), | ||
83 | ErrExpTermFirst = record("ExpTermFirst") * sync(op + ")") * defaultValue(), | ||
84 | ErrExpTermOp = record("ExpTermOp") * sync(op + ")") * defaultValue(), | ||
85 | ErrMisClose = record("MisClose") * sync(P")") * defaultValue(m.P""), | ||
86 | } | ||
87 | |||
88 | |||
89 | local function eval(input) | ||
90 | errors = {} | ||
91 | subject = input | ||
92 | local result, label, suffix = recg2:match(input) | ||
93 | if #errors > 0 then | ||
94 | local out = {} | ||
95 | for i, err in ipairs(errors) do | ||
96 | local pos = err.col | ||
97 | local msg = err.msg | ||
98 | table.insert(out, "syntax error: " .. msg .. " (at index " .. pos .. ")") | ||
99 | end | ||
100 | print(table.concat(out, "\n")) | ||
101 | end | ||
102 | return result | ||
103 | end | ||
104 | |||
105 | print(eval "90-70*5") | ||
106 | --> 20 | ||
107 | |||
108 | print(eval "2+") | ||
109 | --> 2 + 0 | ||
110 | |||
111 | print(eval "-2") | ||
112 | --> 0 - 2 | ||
113 | |||
114 | print(eval "1+3+-9") | ||
115 | --> 1 + 3 + [0] - 9 | ||
116 | |||
117 | print(eval "1+()3+") | ||
118 | --> 1 + ([0]) [+] 3 + [0] | ||
119 | |||
120 | print(eval "8-(2+)-5") | ||
121 | --> 8 - (2 + [0]) - 5 | ||
122 | |||
123 | print(eval "()") | ||
124 | |||
125 | print(eval "") | ||
126 | |||
127 | print(eval "1+()+") | ||
128 | |||
129 | print(eval "1+(") | ||
130 | |||
131 | print(eval "3)") | ||
132 | |||
diff --git a/examples/expressionRecovery.lua b/examples/expressionRecovery.lua index a4a3288..c5cbcca 100644 --- a/examples/expressionRecovery.lua +++ b/examples/expressionRecovery.lua | |||
@@ -91,7 +91,6 @@ local function eval(input) | |||
91 | for i, err in ipairs(errors) do | 91 | for i, err in ipairs(errors) do |
92 | local pos = err.col | 92 | local pos = err.col |
93 | local msg = err.msg | 93 | local msg = err.msg |
94 | print("sub", subject) | ||
95 | table.insert(out, "syntax error: " .. msg .. " (at index " .. pos .. ")") | 94 | table.insert(out, "syntax error: " .. msg .. " (at index " .. pos .. ")") |
96 | end | 95 | end |
97 | print(table.concat(out, "\n")) | 96 | print(table.concat(out, "\n")) |
@@ -123,5 +122,7 @@ print(eval "") | |||
123 | 122 | ||
124 | print(eval "1+()+") | 123 | print(eval "1+()+") |
125 | 124 | ||
125 | print(eval "1+(") | ||
126 | |||
126 | print(eval "3)") | 127 | print(eval "3)") |
127 | 128 | ||