aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSérgio Queiroz <sqmedeiros@gmail.com>2017-12-18 15:39:00 -0300
committerSérgio Queiroz <sqmedeiros@gmail.com>2017-12-18 15:39:00 -0300
commitc6b98103f0ab2c4afb7216e73f2eacac58cbf952 (patch)
treea98bef21fff8702c66deac2315a6a10d7d1c26df
parent4bdf8d40a9ca5f00e454a38d301a3ab35c9b50d5 (diff)
downloadlpeglabel-c6b98103f0ab2c4afb7216e73f2eacac58cbf952.tar.gz
lpeglabel-c6b98103f0ab2c4afb7216e73f2eacac58cbf952.tar.bz2
lpeglabel-c6b98103f0ab2c4afb7216e73f2eacac58cbf952.zip
Updating code to use the new syntax/semantics of labels
-rw-r--r--lpcode.c5
-rw-r--r--lpprint.c12
-rw-r--r--lptree.c10
-rw-r--r--lpvm.c1
-rw-r--r--relabel.lua15
-rw-r--r--testlabel.lua802
6 files changed, 272 insertions, 573 deletions
diff --git a/lpcode.c b/lpcode.c
index 0b813b8..8a68060 100644
--- a/lpcode.c
+++ b/lpcode.c
@@ -517,7 +517,8 @@ static int addinstruction (CompileState *compst, Opcode op, int aux) {
517static int addoffsetinst (CompileState *compst, Opcode op) { 517static int addoffsetinst (CompileState *compst, Opcode op) {
518 int i = addinstruction(compst, op, 0); /* instruction */ 518 int i = addinstruction(compst, op, 0); /* instruction */
519 addinstruction(compst, (Opcode)0, 0); /* open space for offset */ 519 addinstruction(compst, (Opcode)0, 0); /* open space for offset */
520 assert(op == ITestSet || sizei(&getinstr(compst, i)) == 2); 520 assert(op == ITestSet || sizei(&getinstr(compst, i)) == 2 ||
521 op == IThrowRec); /* labeled failure */
521 return i; 522 return i;
522} 523}
523 524
@@ -527,13 +528,13 @@ static void codethrow (CompileState *compst, TTree *throw) {
527 int recov, aux; 528 int recov, aux;
528 if (throw->u.s.ps != 0) { 529 if (throw->u.s.ps != 0) {
529 recov = addoffsetinst(compst, IThrowRec); 530 recov = addoffsetinst(compst, IThrowRec);
531 assert(sib2(throw)->tag == TRule);
530 } else { 532 } else {
531 recov = addinstruction(compst, IThrow, 0); 533 recov = addinstruction(compst, IThrow, 0);
532 } 534 }
533 aux = nextinstruction(compst); 535 aux = nextinstruction(compst);
534 getinstr(compst, aux).i.key = throw->key; /* next instruction keeps only rule name */ 536 getinstr(compst, aux).i.key = throw->key; /* next instruction keeps only rule name */
535 getinstr(compst, recov).i.key = sib2(throw)->cap; /* rule number */ 537 getinstr(compst, recov).i.key = sib2(throw)->cap; /* rule number */
536 assert(sib2(throw)->tag == TRule);
537} 538}
538/* labeled failure */ 539/* labeled failure */
539 540
diff --git a/lpprint.c b/lpprint.c
index 342a2b6..8d5e087 100644
--- a/lpprint.c
+++ b/lpprint.c
@@ -111,11 +111,6 @@ void printinst (const Instruction *op, const Instruction *p) {
111 printf("%d", p->i.aux); 111 printf("%d", p->i.aux);
112 break; 112 break;
113 } 113 }
114 case IRecov: case ILabChoice: { /* labeled failure */
115 printjmp(op, p);
116 printcharset((p+2)->buff);
117 break;
118 }
119 default: break; 114 default: break;
120 } 115 }
121 printf("\n"); 116 printf("\n");
@@ -217,16 +212,15 @@ void printtree (TTree *tree, int ident) {
217 break; 212 break;
218 } 213 }
219 case TThrow: { /* labeled failure */ 214 case TThrow: { /* labeled failure */
215 if (tree->u.s.ps != 0)
216 assert(sib2(tree)->tag == TRule);
217 printf(" key: %d (rule: %d)\n", tree->key, sib2(tree)->cap);
220 printf(" labels: %d\n", tree->u.label); 218 printf(" labels: %d\n", tree->u.label);
221 break; 219 break;
222 } 220 }
223 default: { 221 default: {
224 int sibs = numsiblings[tree->tag]; 222 int sibs = numsiblings[tree->tag];
225 printf("\n"); 223 printf("\n");
226 if (tree->tag == TRecov || tree->tag == TLabChoice) { /* labeled failure */
227 printcharset(treelabelset(tree));
228 printf("\n");
229 }
230 if (sibs >= 1) { 224 if (sibs >= 1) {
231 printtree(sib1(tree), ident + 2); 225 printtree(sib1(tree), ident + 2);
232 if (sibs >= 2) 226 if (sibs >= 2)
diff --git a/lptree.c b/lptree.c
index 6d6b399..ba091d6 100644
--- a/lptree.c
+++ b/lptree.c
@@ -1204,8 +1204,16 @@ static int lp_match (lua_State *L) {
1204 r = match(L, s, s + i, s + l, code, capture, ptop, &labelf, &sfail); /* labeled failure */ 1204 r = match(L, s, s + i, s + l, code, capture, ptop, &labelf, &sfail); /* labeled failure */
1205 if (r == NULL) { /* labeled failure begin */ 1205 if (r == NULL) { /* labeled failure begin */
1206 lua_pushnil(L); 1206 lua_pushnil(L);
1207 if (labelf) 1207 if (labelf) {
1208 int isnum;
1209 lua_Integer lInt;
1208 lua_rawgeti(L, ktableidx(ptop), labelf); 1210 lua_rawgeti(L, ktableidx(ptop), labelf);
1211 lInt = lua_tointegerx(L, -1, &isnum);
1212 if (isnum) {
1213 lua_pop(L, 1);
1214 lua_pushinteger(L, lInt);
1215 }
1216 }
1209 else 1217 else
1210 lua_pushstring(L, "fail"); 1218 lua_pushstring(L, "fail");
1211 lua_pushinteger(L, sfail - (s + i) + 1); /* subject position related to the error */ 1219 lua_pushinteger(L, sfail - (s + i) + 1); /* subject position related to the error */
diff --git a/lpvm.c b/lpvm.c
index 251fa0a..20bc545 100644
--- a/lpvm.c
+++ b/lpvm.c
@@ -301,6 +301,7 @@ const char *match (lua_State *L, const char *o, const char *s, const char *e,
301 luaL_error(L, "labelf is %d", *labelf); 301 luaL_error(L, "labelf is %d", *labelf);
302 *sfail = s; 302 *sfail = s;
303 stack = getstackbase(L, ptop); 303 stack = getstackbase(L, ptop);
304 stack++;
304 goto fail; 305 goto fail;
305 } 306 }
306 case IThrowRec: { /* labeled failure */ 307 case IThrowRec: { /* labeled failure */
diff --git a/relabel.lua b/relabel.lua
index abb3c7f..6a676b9 100644
--- a/relabel.lua
+++ b/relabel.lua
@@ -241,12 +241,6 @@ local function choicerec (...)
241 return p 241 return p
242end 242end
243 243
244local function getlab (f)
245 if not tlabels[f] then
246 error("undefined label: " .. f)
247 end
248 return tlabels[f]
249end
250 244
251local exp = m.P{ "Exp", 245local exp = m.P{ "Exp",
252 Exp = S * ( m.V"Grammar" 246 Exp = S * ( m.V"Grammar"
@@ -278,7 +272,7 @@ local exp = m.P{ "Exp",
278 + "=>" * expect(S * m.Cg(Def / getdef * m.Cc(m.Cmt)), 272 + "=>" * expect(S * m.Cg(Def / getdef * m.Cc(m.Cmt)),
279 "ExpName1") 273 "ExpName1")
280 ) 274 )
281 )^0, function (a,b,f) if f == "lab" then return a + mm.T(getlab(b)) else return f(a,b) end end ); 275 )^0, function (a,b,f) if f == "lab" then return a + mm.T(b) else return f(a,b) end end );
282 Primary = "(" * expect(m.V"Exp", "ExpPatt4") * expect(S * ")", "MisClose1") 276 Primary = "(" * expect(m.V"Exp", "ExpPatt4") * expect(S * ")", "MisClose1")
283 + String / mm.P 277 + String / mm.P
284 + Class 278 + Class
@@ -301,7 +295,7 @@ local exp = m.P{ "Exp",
301 + m.P"." * m.Cc(any) 295 + m.P"." * m.Cc(any)
302 + (name * -arrow + "<" * expect(name, "ExpName3") 296 + (name * -arrow + "<" * expect(name, "ExpName3")
303 * expect(">", "MisClose6")) * m.Cb("G") / NT; 297 * expect(">", "MisClose6")) * m.Cb("G") / NT;
304 Label = num + name / function (f) return getlab(f) end; 298 Label = num + name;
305 Definition = name * arrow * expect(m.V"Exp", "ExpPatt8"); 299 Definition = name * arrow * expect(m.V"Exp", "ExpPatt8");
306 Grammar = m.Cg(m.Cc(true), "G") 300 Grammar = m.Cg(m.Cc(true), "G")
307 * m.Cf(m.V"Definition" / firstdef * (S * m.Cg(m.V"Definition"))^0, 301 * m.Cf(m.V"Definition" / firstdef * (S * m.Cg(m.V"Definition"))^0,
@@ -342,7 +336,7 @@ end
342local function compile (p, defs) 336local function compile (p, defs)
343 if mm.type(p) == "pattern" then return p end -- already compiled 337 if mm.type(p) == "pattern" then return p end -- already compiled
344 p = p .. " " -- for better reporting of column numbers in errors when at EOF 338 p = p .. " " -- for better reporting of column numbers in errors when at EOF
345 local ok, cp, label, suffix = pcall(function() return pattern:match(p, 1, defs) end) 339 local ok, cp, label, poserr = pcall(function() return pattern:match(p, 1, defs) end)
346 if not ok and cp then 340 if not ok and cp then
347 if type(cp) == "string" then 341 if type(cp) == "string" then
348 cp = cp:gsub("^[^:]+:[^:]+: ", "") 342 cp = cp:gsub("^[^:]+:[^:]+: ", "")
@@ -351,8 +345,7 @@ local function compile (p, defs)
351 end 345 end
352 if not cp then 346 if not cp then
353 local lines = splitlines(p) 347 local lines = splitlines(p)
354 local line, col = lineno(p, #p - #suffix + 1) 348 local line, col = lineno(p, poserr)
355 --local line, col = calcline(p, #p - #suffix + 1)
356 local err = {} 349 local err = {}
357 tinsert(err, "L" .. line .. ":C" .. col .. ": " .. errmsgs[label]) 350 tinsert(err, "L" .. line .. ":C" .. col .. ": " .. errmsgs[label])
358 tinsert(err, lines[line]) 351 tinsert(err, lines[line])
diff --git a/testlabel.lua b/testlabel.lua
index 9e2a586..b834be3 100644
--- a/testlabel.lua
+++ b/testlabel.lua
@@ -84,12 +84,12 @@ print"+"
84p = m.T(1) 84p = m.T(1)
85s = "abc" 85s = "abc"
86r, l, poserr = p:match(s) 86r, l, poserr = p:match(s)
87assert(r == nil and l == '1' and poserr == 1) 87assert(r == nil and l == 1 and poserr == 1)
88 88
89-- throws a label, choice does not catch labels 89-- throws a label, choice does not catch labels
90p = m.T(1) + m.P"a" 90p = m.T(1) + m.P"a"
91r, l, poserr = p:match(s) 91r, l, poserr = p:match(s)
92assert(r == nil and l == '1' and poserr == 1) 92assert(r == nil and l == 1 and poserr == 1)
93 93
94-- again throws a label that is not caught by choice 94-- again throws a label that is not caught by choice
95local g = m.P{ 95local g = m.P{
@@ -99,15 +99,15 @@ local g = m.P{
99 B = m.P"a" 99 B = m.P"a"
100} 100}
101r, l, poserr = g:match(s) 101r, l, poserr = g:match(s)
102assert(r == nil and l == '1' and poserr == 1) 102assert(r == nil and l == 1 and poserr == 1)
103 103
104-- throws a label in a position that is not the farthest one 104-- throws a label in a position that is not the farthest one
105-- but it is the position that should be reported 105-- but it is the position that should be reported
106p = m.P(1) * m.P"a" + m.T(11) 106p = m.P(1) * m.P"a" + m.T(11)
107checklabeq({3, nil, nil}, p:match("bac")) 107checklabeq({3, nil, nil}, p:match("bac"))
108checklabeq({nil, '11', 1}, p:match("c")) 108checklabeq({nil, 11, 1}, p:match("c"))
109checklabeq({nil, '11', 1}, p:match("x")) 109checklabeq({nil, 11, 1}, p:match("x"))
110checklabeq({nil, '11', 1}, p:match("kx")) 110checklabeq({nil, 11, 1}, p:match("kx"))
111 111
112 112
113-- throws a label without a corresponding recovery rule 113-- throws a label without a corresponding recovery rule
@@ -127,7 +127,7 @@ p = m.P{
127 [2] = m.P"a" 127 [2] = m.P"a"
128} 128}
129r, l, poserr = p:match("abc") 129r, l, poserr = p:match("abc")
130assert(r == nil and l == '2' and poserr == 1) 130assert(r == nil and l == 2 and poserr == 1)
131 131
132-- throws a label with a corresponding recovery rule 132-- throws a label with a corresponding recovery rule
133p = m.P{ 133p = m.P{
@@ -198,23 +198,23 @@ assert(r == nil and l == 'fail' and poserr == 1)
198-- tests related to predicates 198-- tests related to predicates
199p = #m.T(1) + m.P"a" 199p = #m.T(1) + m.P"a"
200r, l, poserr = p:match("abc") 200r, l, poserr = p:match("abc")
201assert(r == nil and l == '1' and poserr == 1) 201assert(r == nil and l == 1 and poserr == 1)
202 202
203p = ##m.T(1) + m.P"a" 203p = ##m.T(1) + m.P"a"
204r, l, poserr = p:match("abc") 204r, l, poserr = p:match("abc")
205assert(r == nil and l == '1' and poserr == 1) 205assert(r == nil and l == 1 and poserr == 1)
206 206
207p = -m.T(1) * m.P"a" 207p = -m.T(1) * m.P"a"
208r, l, poserr = p:match("abc") 208r, l, poserr = p:match("abc")
209assert(r == nil and l == '1' and poserr == 1) 209assert(r == nil and l == 1 and poserr == 1)
210 210
211p = -m.T(1) * m.P"a" 211p = -m.T(1) * m.P"a"
212r, l, poserr = p:match("bbc") 212r, l, poserr = p:match("bbc")
213assert(r == nil and l == '1' and poserr == 1) 213assert(r == nil and l == 1 and poserr == 1)
214 214
215p = -(-m.T(1)) * m.P"a" 215p = -(-m.T(1)) * m.P"a"
216r, l, poserr = p:match("abc") 216r, l, poserr = p:match("abc")
217assert(r == nil and l == '1' and poserr == 1) 217assert(r == nil and l == 1 and poserr == 1)
218 218
219p = m.P{ 219p = m.P{
220 "S", 220 "S",
@@ -254,7 +254,7 @@ p = m.P{
254 ["22"] = m.T(15) 254 ["22"] = m.T(15)
255} 255}
256r, l, poserr = p:match("abc") 256r, l, poserr = p:match("abc")
257assert(r == nil and l == '15' and poserr == 1) 257assert(r == nil and l == 15 and poserr == 1)
258 258
259p = m.P{ 259p = m.P{
260 "S", 260 "S",
@@ -262,17 +262,17 @@ p = m.P{
262 ["22"] = m.T(15) 262 ["22"] = m.T(15)
263} 263}
264r, l, poserr = p:match("abc") 264r, l, poserr = p:match("abc")
265assert(r == nil and l == '15' and poserr == 2) 265assert(r == nil and l == 15 and poserr == 2)
266 266
267 267
268-- tests related to repetition 268-- tests related to repetition
269p = m.T(1)^0 269p = m.T(1)^0
270r, l, poserr = p:match("ab") 270r, l, poserr = p:match("ab")
271assert(r == nil and l == '1' and poserr == 1) 271assert(r == nil and l == 1 and poserr == 1)
272 272
273p = (m.P"a" + m.T(1))^0 273p = (m.P"a" + m.T(1))^0
274r, l, poserr = p:match("aa") 274r, l, poserr = p:match("aa")
275assert(r == nil and l == '1' and poserr == 3) 275assert(r == nil and l == 1 and poserr == 3)
276 276
277 277
278-- Bug reported by Matthew Allen 278-- Bug reported by Matthew Allen
@@ -327,7 +327,7 @@ g = m.P{
327assert(g:match("a;a;") == 5) 327assert(g:match("a;a;") == 5)
328 328
329r, l, poserr = g:match("a;a") 329r, l, poserr = g:match("a;a")
330assert(r == nil and l == '2' and poserr == 4) 330assert(r == nil and l == 2 and poserr == 4)
331 331
332 332
333p = m.P{ 333p = m.P{
@@ -383,23 +383,18 @@ local eq = sp * m.P"="
383 383
384g = m.P{ 384g = m.P{
385 "S", 385 "S",
386 S = m.Rec( 386 S = m.V"S0" + m.T'L5', -- error
387 m.Rec( 387 S0 = m.V"S1" + m.V"S2" + #m.V"I" * m.T'L3',
388 m.Rec( 388 S1 = #(m.V"ID" * eq) * m.T'L2' + sp * #(m.V"ID" * -m.P(1)) * m.T'L1' + #m.V"ID" * m.T'L4',
389 m.Rec(m.V"S0", m.V"ID", 1), 389 S2 = #(m.V"U"^1 * m.V"ID") * m.T'L4' + #(m.V"U"^1 * m.V"I") * m.T'L3',
390 m.V"ID" * eq * m.V"Exp", 2
391 ),
392 m.V"U"^0 * m.V"I" * m.V"ID", 3
393 ),
394 m.V"U"^0 * m.V"ID" * m.V"ID", 4)
395 + m.T(5), -- error
396 S0 = m.V"S1" + m.V"S2" + #m.V"I" * m.T(3),
397 S1 = #(m.V"ID" * eq) * m.T(2) + sp * #(m.V"ID" * -m.P(1)) * m.T(1) + #m.V"ID" * m.T(4),
398 S2 = #(m.V"U"^1 * m.V"ID") * m.T(4) + #(m.V"U"^1 * m.V"I") * m.T(3),
399 ID = sp * m.P"a", 390 ID = sp * m.P"a",
400 U = sp * m.P"unsigned", 391 U = sp * m.P"unsigned",
401 I = sp * m.P"int", 392 I = sp * m.P"int",
402 Exp = sp * m.P"E", 393 Exp = sp * m.P"E",
394 L1 = m.V"ID",
395 L2 = m.V"ID" * eq * m.V"Exp",
396 L3 = m.V"U"^0 * m.V"I" * m.V"ID",
397 L4 = m.V"U"^0 * m.V"ID" * m.V"ID",
403} 398}
404 399
405local s = "a" 400local s = "a"
@@ -415,19 +410,19 @@ assert(g:match(s) == #s + 1) --4
415 410
416s = "b" 411s = "b"
417r, l, poserr = g:match(s) 412r, l, poserr = g:match(s)
418assert(r == nil and l == 5 and poserr == 1) 413assert(r == nil and l == 'L5' and poserr == 1)
419 414
420s = "unsigned" 415s = "unsigned"
421r, l, poserr = g:match(s) 416r, l, poserr = g:match(s)
422assert(r == nil and l == 5 and poserr == 1) 417assert(r == nil and l == 'L5' and poserr == 1)
423 418
424s = "unsigned a" 419s = "unsigned a"
425r, l, poserr = g:match(s) 420r, l, poserr = g:match(s)
426assert(r == nil and l == 5 and poserr == 1) 421assert(r == nil and l == 'L5' and poserr == 1)
427 422
428s = "unsigned int" 423s = "unsigned int"
429r, l, poserr = g:match(s) 424r, l, poserr = g:match(s)
430assert(r == nil and l == 5 and poserr == 1) 425assert(r == nil and l == 'L5' and poserr == 1)
431 426
432 427
433print("+") 428print("+")
@@ -435,42 +430,61 @@ print("+")
435 430
436local re = require 'relabel' 431local re = require 'relabel'
437 432
438g = re.compile[['a' //{4,9} [a-z] 433g = re.compile[['a' / %{l1}
439]] 434]]
440assert(g:match("a") == 2) 435assert(g:match("a") == 2)
441r, l, poserr = g:match("b") 436r, l, poserr = g:match("b")
442assert(r == nil and l == 0 and poserr == 1) 437assert(r == nil and l == 'l1' and poserr == 1)
443 438
444g = re.compile[['a' //{4,9} [a-f] //{5, 7} [a-z] 439g = re.compile[['a'^l1
445]] 440]]
446assert(g:match("a") == 2) 441assert(g:match("a") == 2)
447r, l, poserr = g:match("b") 442r, l, poserr = g:match("b")
448assert(r == nil and l == 0 and poserr == 1) 443assert(r == nil and l == 'l1' and poserr == 1)
449 444
450g = re.compile[[%{1} //{4,9} [a-z] 445g = re.compile[[A <- 'a'^B
446 B <- [a-f]^C
447 C <- [a-z]
451]] 448]]
452r, l, poserr = g:match("a") 449assert(g:match("a") == 2)
453assert(r == nil and l == 1 and poserr == 1) 450assert(g:match("a") == 2)
451assert(g:match("f") == 2)
452assert(g:match("g") == 2)
453assert(g:match("z") == 2)
454r, l, poserr = g:match("A")
455assert(r == nil and l == 'fail' and poserr == 1)
454 456
457g = re.compile[[A <- %{C}
458 B <- [a-z]
459]]
460r, l, poserr = g:match("a")
461assert(r == nil and l == 'C' and poserr == 1)
455 462
456g = re.compile[[%{1} //{4,1} [a-f] 463g = re.compile[[A <- %{B}
464 B <- [a-z]
457]] 465]]
466r, l, poserr = g:match("a")
458assert(g:match("a") == 2) 467assert(g:match("a") == 2)
459r, l, poserr = g:match("h") 468r, l, poserr = g:match("U")
460assert(r == nil and l == 0 and poserr == 1) 469assert(r == nil and l == 'fail' and poserr == 1)
470
471
472g = re.compile[[A <- [a-f] %{B}
473 B <- [a-c] %{C}
474 C <- [a-z]
475]]
461 476
462g = re.compile[[[a-f]%{9} //{4,9} [a-c]%{7} //{5, 7} [a-z] ]]
463r, l, poserr = g:match("a") 477r, l, poserr = g:match("a")
464assert(r == nil and l == 0 and poserr == 2) 478assert(r == nil and l == 'fail' and poserr == 2)
465r, l, poserr = g:match("aa") 479r, l, poserr = g:match("aa")
466assert(r == nil and l == 0 and poserr == 3) 480assert(r == nil and l == 'fail' and poserr == 3)
467assert(g:match("aaa") == 4) 481assert(g:match("aaa") == 4)
468 482
469r, l, poserr = g:match("ad") 483r, l, poserr = g:match("ad")
470assert(r == nil and l == 0 and poserr == 2) 484assert(r == nil and l == 'fail' and poserr == 2)
471 485
472r, l, poserr = g:match("g") 486r, l, poserr = g:match("g")
473assert(r == nil and l == 0 and poserr == 1) 487assert(r == nil and l == 'fail' and poserr == 1)
474 488
475 489
476--[[ grammar based on Figure 8 of paper submitted to SCP (using the recovery operator) 490--[[ grammar based on Figure 8 of paper submitted to SCP (using the recovery operator)
@@ -481,143 +495,18 @@ S2 -> &('unsigned'+ ID) %4 / & ('unsigned'+ 'int') %3
481]] 495]]
482 496
483g = re.compile([[ 497g = re.compile([[
484 S <- S0 //{1} ID //{2} ID %s* '=' Exp //{3} U* Int ID //{4} U ID ID / %{5} 498 S <- S0 / %{L5}
485 S0 <- S1 / S2 / &Int %{3} 499 S0 <- S1 / S2 / &Int %{L3}
486 S1 <- &(ID %s* '=') %{2} / &(ID !.) %{1} / &ID %{4} 500 S1 <- &(ID %s* '=') %{L2} / &(ID !.) %{L1} / &ID %{L4}
487 S2 <- &(U+ ID) %{4} / &(U+ Int) %{3} 501 S2 <- &(U+ ID) %{L4} / &(U+ Int) %{L3}
488 ID <- %s* 'a'
489 U <- %s* 'unsigned'
490 Int <- %s* 'int'
491 Exp <- %s* 'E'
492]])
493
494local s = "a"
495assert(g:match(s) == #s + 1) --1
496s = "a = E"
497assert(g:match(s) == #s + 1) --2
498s = "int a"
499assert(g:match(s) == #s + 1) --3
500s = "unsigned int a"
501assert(g:match(s) == #s + 1) --3
502s = "unsigned a a"
503assert(g:match(s) == #s + 1) --4
504s = "b"
505r, l, poserr = g:match(s)
506assert(r == nil and l == 5 and poserr == 1)
507s = "unsigned"
508r, l, poserr = g:match(s)
509assert(r == nil and l == 5 and poserr == 1)
510s = "unsigned a"
511r, l, poserr = g:match(s)
512assert(r == nil and l == 5 and poserr == 1)
513s = "unsigned int"
514r, l, poserr = g:match(s)
515assert(r == nil and l == 5 and poserr == 1)
516
517
518------------------------------------------
519-- Tests related to labeled ordered choice
520------------------------------------------
521
522-- throws a label that is not caught by labeled choice
523s = "abc"
524p = m.Lc(m.T(2), m.P"a", 1, 3)
525r, l, poserr = p:match(s)
526assert(r == nil and l == 2 and poserr == 1)
527
528-- modifies previous pattern
529-- adds another labeled choice to catch label "2"
530p = m.Lc(p, m.P"a", 2)
531assert(p:match(s) == 2)
532
533-- throws a label that is caught by labeled choice
534p = m.Lc(m.T(25), m.P"a", 25)
535assert(p:match(s) == 2)
536
537-- "fail" is label "0"
538-- throws the "fail" label that is not caught by the labeled choice
539s = "bola"
540r, l, poserr = p:match("bola")
541assert(r == nil and l == 0 and poserr == 1)
542
543-- labeled choice does not catch "fail"
544p = m.Lc(m.P"b", m.P"a", 1)
545
546r, l, poserr = p:match("abc")
547assert(r == nil and l == 0 and poserr == 1)
548assert(p:match("bola") == 2)
549
550-- labeled choice catches "1" or "3"
551p = m.Lc(-m.P"a" * m.T(1) + m.P"a" * m.T(3), m.P"a" + m.P"b", 1, 3)
552assert(p:match("abc") == 2)
553assert(p:match("bac") == 2)
554
555-- associativity
556-- (p1 / %1) /{1} (p2 / %2) /{2} p3
557-- left-associativity
558-- ("a" /{1} "b") /{2} "c"
559p = m.Lc(m.Lc(m.P"a" + m.T(1), m.P"b" + m.T(2), 1), m.P"c", 2)
560assert(p:match("abc") == 2)
561assert(p:match("bac") == 2)
562assert(p:match("cab") == 2)
563r, l, poserr = p:match("dab")
564assert(r == nil and l == 0 and poserr == 1)
565
566
567-- righ-associativity
568-- "a" /{1} ("b" /{2} "c")
569p = m.Lc(m.P"a" + m.T(1), m.Lc(m.P"b" + m.T(2), m.P"c", 2), 1)
570assert(p:match("abc") == 2)
571assert(p:match("bac") == 2)
572assert(p:match("cab") == 2)
573r, l, poserr = p:match("dab")
574assert(r == nil and l == 0 and poserr == 1)
575
576
577-- associativity -> in this case the error thrown by p1 is only
578-- recovered when we have a left-associative operator
579-- (p1 / %2) /{1} (p2 / %2) /{2} p3
580-- left-associativity
581-- ("a" /{1} "b") /{2} "c"
582p = m.Lc(m.Lc(m.P"a" + m.T(2), m.P"b" + m.T(2), 1), m.P"c", 2)
583assert(p:match("abc") == 2)
584r, l, poserr = p:match("bac")
585assert(r == nil and l == 0 and poserr == 1)
586assert(p:match("cab") == 2)
587r, l, poserr = p:match("dab")
588assert(r == nil and l == 0 and poserr == 1)
589
590
591-- righ-associativity
592-- "a" /{1} ("b" /{2} "c")
593p = m.Lc(m.P"a" + m.T(2), m.Lc(m.P"b" + m.T(2), m.P"c", 2), 1)
594assert(p:match("abc") == 2)
595r, l, poserr = p:match("bac")
596assert(r == nil and l == 2 and poserr == 1)
597r, l, poserr = p:match("cab")
598assert(r == nil and l == 2 and poserr == 1)
599r, l, poserr = p:match("dab")
600assert(r == nil and l == 2 and poserr == 1)
601
602
603
604--[[ grammar based on Figure 8 of paper submitted to SCP (using labeled choice)
605S -> S0 /{1} ID /{2} ID '=' Exp /{3} 'unsigned'* 'int' ID /{4} 'unsigned'* ID ID / %error
606S0 -> ID S1 / 'unsigned' S2 / 'int' %3
607S1 -> '=' %2 / !. %1 / ID %4
608S2 -> 'unsigned' S2 / ID %4 / 'int' %3
609]]
610
611
612g = re.compile([[
613 S <- S0 /{1} ID /{2} ID %s* '=' Exp /{3} U* Int ID /{4} U ID ID / %{5}
614 S0 <- ID S1 / U S2 / Int %{3}
615 S1 <- %s* '=' %{2} / !. %{1} / ID %{4}
616 S2 <- U S2 / ID %{4} / Int %{3}
617 ID <- %s* 'a' 502 ID <- %s* 'a'
618 U <- %s* 'unsigned' 503 U <- %s* 'unsigned'
619 Int <- %s* 'int' 504 Int <- %s* 'int'
620 Exp <- %s* 'E' 505 Exp <- %s* 'E'
506 L1 <- ID
507 L2 <- ID %s* '=' Exp
508 L3 <- U* Int ID
509 L4 <- U ID ID
621]]) 510]])
622 511
623local s = "a" 512local s = "a"
@@ -632,57 +521,52 @@ s = "unsigned a a"
632assert(g:match(s) == #s + 1) --4 521assert(g:match(s) == #s + 1) --4
633s = "b" 522s = "b"
634r, l, poserr = g:match(s) 523r, l, poserr = g:match(s)
635assert(r == nil and l == 5 and poserr == 1) 524assert(r == nil and l == 'L5' and poserr == 1)
636s = "unsigned" 525s = "unsigned"
637r, l, poserr = g:match(s) 526r, l, poserr = g:match(s)
638assert(r == nil and l == 5 and poserr == 1) 527assert(r == nil and l == 'L5' and poserr == 1)
639s = "unsigned a" 528s = "unsigned a"
640r, l, poserr = g:match(s) 529r, l, poserr = g:match(s)
641assert(r == nil and l == 5 and poserr == 1) 530assert(r == nil and l == 'L5' and poserr == 1)
642s = "unsigned int" 531s = "unsigned int"
643r, l, poserr = g:match(s) 532r, l, poserr = g:match(s)
644assert(r == nil and l == 5 and poserr == 1) 533assert(r == nil and l == 'L5' and poserr == 1)
645 534
646 535
647 536
648local terror = { ['cmdSeq'] = "Missing ';' in CmdSeq", 537local terror = { cmdSeq = "Missing ';' in CmdSeq",
649 ['ifExp'] = "Error in expresion of 'if'", 538 ifExp = "Error in expresion of 'if'",
650 ['ifThen'] = "Error matching 'then' keyword", 539 ifThen = "Error matching 'then' keyword",
651 ['ifThenCmdSeq'] = "Error matching CmdSeq of 'then' branch", 540 ifThenCmdSeq = "Error matching CmdSeq of 'then' branch",
652 ['ifElseCmdSeq'] = "Error matching CmdSeq of 'else' branch", 541 ifElseCmdSeq = "Error matching CmdSeq of 'else' branch",
653 ['ifEnd'] = "Error matching 'end' keyword of 'if'", 542 ifEnd = "Error matching 'end' keyword of 'if'",
654 ['repeatCmdSeq'] = "Error matching CmdSeq of 'repeat'", 543 repeatCmdSeq = "Error matching CmdSeq of 'repeat'",
655 ['repeatUntil'] = "Error matching 'until' keyword", 544 repeatUntil = "Error matching 'until' keyword",
656 ['repeatExp'] = "Error matching expression of 'until'", 545 repeatExp = "Error matching expression of 'until'",
657 ['assignOp'] = "Error matching ':='", 546 assignOp = "Error matching ':='",
658 ['assignExp'] = "Error matching expression of assignment", 547 assignExp = "Error matching expression of assignment",
659 ['readName'] = "Error matching 'NAME' after 'read'", 548 readName = "Error matching 'NAME' after 'read'",
660 ['writeExp'] = "Error matching expression after 'write'", 549 writeExp = "Error matching expression after 'write'",
661 ['simpleExp'] = "Error matching 'SimpleExp'", 550 simpleExp = "Error matching 'SimpleExp'",
662 ['term'] = "Error matching 'Term'", 551 term = "Error matching 'Term'",
663 ['factor'] = "Error matching 'Factor'", 552 factor = "Error matching 'Factor'",
664 ['openParExp'] = "Error matching expression after '('", 553 openParExp = "Error matching expression after '('",
665 ['closePar'] = "Error matching ')'", 554 closePar = "Error matching ')'",
666 ['undefined'] = "Undefined Error"} 555 undefined = "Undefined Error"}
667 556
668g = re.compile([[ 557g = re.compile([[
669 Tiny <- CmdSeq //{1} '' -> cmdSeq //{2} '' -> ifExp //{3} '' -> ifThen //{4} '' -> ifThenCmdSeq 558 Tiny <- CmdSeq
670 //{5} '' -> ifElseCmdSeq //{6} '' -> ifEnd //{7} '' -> repeatCmdSeq 559 CmdSeq <- (Cmd SEMICOLON^cmdSeq) (Cmd SEMICOLON^cmdSeq)*
671 //{8} '' -> repeatUntil //{9} '' -> repeatExp //{10} '' -> assignOp
672 //{11} '' -> assignExp //{12} '' -> readName //{13} '' -> writeExp
673 //{14} '' -> simpleExp //{15} '' -> term //{16} '' -> factor
674 //{17} '' -> openParExp //{18} '' -> closePar / '' -> undefined
675 CmdSeq <- (Cmd (SEMICOLON / %{1})) (Cmd (SEMICOLON / %{1}))*
676 Cmd <- IfCmd / RepeatCmd / ReadCmd / WriteCmd / AssignCmd 560 Cmd <- IfCmd / RepeatCmd / ReadCmd / WriteCmd / AssignCmd
677 IfCmd <- IF (Exp / %{2}) (THEN / %{3}) (CmdSeq / %{4}) (ELSE (CmdSeq / %{5}) / '') (END / %{6}) 561 IfCmd <- IF Exp^ifExp THEN^ifThen CmdSeq^ifThenCmdSeq (ELSE CmdSeq^ifElseCmdSeq / '') END^ifEnd
678 RepeatCmd <- REPEAT (CmdSeq / %{7}) (UNTIL / %{8}) (Exp / %{9}) 562 RepeatCmd <- REPEAT CmdSeq^repeatCmdSeq UNTIL^repeatUntil Exp^repeatExp
679 AssignCmd <- NAME (ASSIGNMENT / %{10}) (Exp / %{11}) 563 AssignCmd <- NAME ASSIGNMENT^assignOp Exp^assignExp
680 ReadCmd <- READ (NAME / %{12}) 564 ReadCmd <- READ NAME^readName
681 WriteCmd <- WRITE (Exp / %{13}) 565 WriteCmd <- WRITE Exp^writeExp
682 Exp <- SimpleExp ((LESS / EQUAL) (SimpleExp / %{14}) / '') 566 Exp <- SimpleExp ((LESS / EQUAL) SimpleExp^simpleExp / '')
683 SimpleExp <- Term ((ADD / SUB) (Term / %{15}))* 567 SimpleExp <- Term ((ADD / SUB) Term^term)*
684 Term <- Factor ((MUL / DIV) (Factor / %{16}))* 568 Term <- Factor ((MUL / DIV) Factor^factor)*
685 Factor <- OPENPAR (Exp / %{17}) (CLOSEPAR / %{18}) / NUMBER / NAME 569 Factor <- OPENPAR Exp^openParExp CLOSEPAR^closePar / NUMBER / NAME
686 ADD <- Sp '+' 570 ADD <- Sp '+'
687 ASSIGNMENT <- Sp ':=' 571 ASSIGNMENT <- Sp ':='
688 CLOSEPAR <- Sp ')' 572 CLOSEPAR <- Sp ')'
@@ -724,7 +608,8 @@ assert(g:match(s) == #s + 1)
724-- a ';' is missing in 'read a' 608-- a ';' is missing in 'read a'
725s = [[ 609s = [[
726read a]] 610read a]]
727assert(g:match(s) == terror['cmdSeq']) 611r, l, poserr = g:match(s)
612assert(l == 'cmdSeq')
728 613
729 614
730-- a ';' is missing in 'n := n - 1' 615-- a ';' is missing in 'n := n - 1'
@@ -736,7 +621,8 @@ repeat
736 n := n - 1 621 n := n - 1
737until (n < 1); 622until (n < 1);
738write f;]] 623write f;]]
739assert(g:match(s) == terror['cmdSeq']) 624r, l, poserr = g:match(s)
625assert(l == 'cmdSeq')
740 626
741 627
742-- IF expression 628-- IF expression
@@ -744,6 +630,7 @@ s = [[
744if a then a := a + 1; end;]] 630if a then a := a + 1; end;]]
745assert(g:match(s) == #s + 1) 631assert(g:match(s) == #s + 1)
746 632
633
747-- IF expression 634-- IF expression
748s = [[ 635s = [[
749if a then a := a + 1; else write 2; end;]] 636if a then a := a + 1; else write 2; end;]]
@@ -752,114 +639,136 @@ assert(g:match(s) == #s + 1)
752-- Error in expression of 'if'. 'A' is not a valida name 639-- Error in expression of 'if'. 'A' is not a valida name
753s = [[ 640s = [[
754if A then a := a + 1; else write 2; end;]] 641if A then a := a + 1; else write 2; end;]]
755assert(g:match(s) == terror['ifExp']) 642r, l, poserr = g:match(s)
643assert(l == 'ifExp')
756 644
757-- Error matching the 'then' keyword 645-- Error matching the 'then' keyword
758s = [[ 646s = [[
759if a a := a + 1; else write 2; end;]] 647if a a := a + 1; else write 2; end;]]
760assert(g:match(s) == terror['ifThen']) 648r, l, poserr = g:match(s)
649assert(l == 'ifThen')
761 650
762-- Error matching the CmdSeq inside of 'then' branch 651-- Error matching the CmdSeq inside of 'then' branch
763s = [[ 652s = [[
764if a then 3 := 2; else write 2; end;]] 653if a then 3 := 2; else write 2; end;]]
765assert(g:match(s) == terror['ifThenCmdSeq']) 654r, l, poserr = g:match(s)
655assert(l == 'ifThenCmdSeq')
766 656
767-- Error matching the CmdSeq inside of 'else' branch 657-- Error matching the CmdSeq inside of 'else' branch
768s = [[ 658s = [[
769if a then b := 2; else A := 2; end;]] 659if a then b := 2; else A := 2; end;]]
770assert(g:match(s) == terror['ifElseCmdSeq']) 660r, l, poserr = g:match(s)
661assert(l == 'ifElseCmdSeq')
771 662
772-- Error matching 'end' of 'if' 663-- Error matching 'end' of 'if'
773s = [[ 664s = [[
774if a then b := 2; else a := 2; 77;]] 665if a then b := 2; else a := 2; 77;]]
775assert(g:match(s) == terror['ifEnd']) 666r, l, poserr = g:match(s)
667assert(l == 'ifEnd')
776 668
777-- Error matching the CmdSeq of 'repeat' 669-- Error matching the CmdSeq of 'repeat'
778s = [[repeat 670s = [[repeat
779 F := f * n; 671 F := f * n;
780 n := n - 1; 672 n := n - 1;
781until (n < 1);]] 673until (n < 1);]]
782assert(g:match(s) == terror['repeatCmdSeq']) 674r, l, poserr = g:match(s)
675assert(l == 'repeatCmdSeq')
783 676
784-- Error matching 'until' 677-- Error matching 'until'
785s = [[repeat 678s = [[repeat
786 f := f * n; 679 f := f * n;
787 n := n - 1; 680 n := n - 1;
78888 (n < 1);]] 68188 (n < 1);]]
789assert(g:match(s) == terror['repeatUntil']) 682r, l, poserr = g:match(s)
683assert(l == 'repeatUntil')
790 684
791-- Error matching expression of 'until' 685-- Error matching expression of 'until'
792s = [[repeat 686s = [[repeat
793 f := f * n; 687 f := f * n;
794 n := n - 1; 688 n := n - 1;
795until ; (n < 1);]] 689until ; (n < 1);]]
796assert(g:match(s) == terror['repeatExp']) 690r, l, poserr = g:match(s)
691assert(l == 'repeatExp')
797 692
798-- Error matching ':=' 693-- Error matching ':='
799s = [[ 694s = [[
800f = f * n;]] 695f = f * n;]]
801assert(g:match(s) == terror['assignOp']) 696r, l, poserr = g:match(s)
697assert(l == 'assignOp')
802 698
803-- Error matching expression of assignment 699-- Error matching expression of assignment
804s = [[ 700s = [[
805f := A * n;]] 701f := A * n;]]
806assert(g:match(s) == terror['assignExp']) 702r, l, poserr = g:match(s)
703assert(l == 'assignExp')
807 704
808-- Error matching 'name' 705-- Error matching 'name'
809s = [[ 706s = [[
810read 2;]] 707read 2;]]
811assert(g:match(s) == terror['readName']) 708r, l, poserr = g:match(s)
709assert(l == 'readName')
812 710
813-- Error matching expression after 'write' 711-- Error matching expression after 'write'
814s = [[ 712s = [[
815write [a] := 2;]] 713write [a] := 2;]]
816assert(g:match(s) == terror['writeExp']) 714r, l, poserr = g:match(s)
715assert(l == 'writeExp')
817 716
818-- Error matching 'SimpleExp' 717-- Error matching 'SimpleExp'
819s = [[ 718s = [[
820a := a < A;]] 719a := a < A;]]
821assert(g:match(s) == terror['simpleExp']) 720r, l, poserr = g:match(s)
721assert(l == 'simpleExp')
822 722
823-- Error matching 'Term' 723-- Error matching 'Term'
824s = [[ 724s = [[
825a := a + A;]] 725a := a + A;]]
826assert(g:match(s) == terror['term']) 726r, l, poserr = g:match(s)
727assert(l == 'term')
827 728
828-- Error matching 'Factor' 729-- Error matching 'Factor'
829s = [[ 730s = [[
830a := a * A;]] 731a := a * A;]]
831assert(g:match(s) == terror['factor']) 732r, l, poserr = g:match(s)
733assert(l == 'factor')
832 734
833-- Error matching expression after '(' 735-- Error matching expression after '('
834s = [[ 736s = [[
835a := (A);]] 737a := (A);]]
836assert(g:match(s) == terror['openParExp']) 738r, l, poserr = g:match(s)
739assert(l == 'openParExp')
837 740
838-- Error matching ')' 741-- Error matching ')'
839s = [[ 742s = [[
840a := (a];]] 743a := (a];]]
841assert(g:match(s) == terror['closePar']) 744r, l, poserr = g:match(s)
745assert(l == 'closePar')
842 746
843-- Error undefined 747-- Error undefined
844s = [[ 748s = [[
845A := a;]] 749A := a;]]
846assert(g:match(s) == terror['undefined']) 750r, l, poserr = g:match(s)
751assert(l == 'fail')
847 752
848 753
849print("+") 754print("+")
850 755
851 756
852p = m.Rec("a", "b", 3) 757p = m.P{
758 "A",
759 A = m.P"a",
760 B = m.P"b"
761}
853assert(p:match("a") == 2) 762assert(p:match("a") == 2)
854checklabeq({nil, 0, 1}, p:match("b")) 763checklabeq({nil, 0, 1}, p:match("b"))
855checklabeq({nil, 0, 1}, p:match("c")) 764checklabeq({nil, 0, 1}, p:match("c"))
856 765
857p = m.Rec(m.T(3), "b", 1) 766p = m.P{
858checklabeq({nil, 3, 1}, p:match("a")) 767 "A",
859checklabeq({nil, 3, 1}, p:match("b")) 768 A = m.T"B",
860 769 B = m.P"b"
861p = m.Rec(m.T(3), "b", 3) 770}
862checklabeq({nil, 0, 1}, p:match("a")) 771checklabeq({nil, 'fail', 1}, p:match("a"))
863assert(p:match("b") == 2) 772assert(p:match("b") == 2)
864 773
865--[[ 774--[[
@@ -869,9 +778,10 @@ C -> c+
869]] 778]]
870g = m.P{ 779g = m.P{
871 "S", 780 "S",
872 S = m.Rec(m.V"A", (-m.P"c" * m.P(1))^0, 128) * m.V"C", 781 S = m.V"A" * m.V"C",
873 A = m.P"a"^0 * "b" + m.T(128), 782 A = m.P"a"^0 * "b" + m.T'Rec',
874 C = m.P"c"^1, 783 C = m.P"c"^1,
784 Rec = (-m.P"c" * m.P(1))^0
875} 785}
876 786
877assert(g:match("abc") == 4) 787assert(g:match("abc") == 4)
@@ -892,9 +802,10 @@ C -> c+
892]] 802]]
893g = m.P{ 803g = m.P{
894 "S", 804 "S",
895 S = m.Rec(m.V"A", (-m.P"c" * m.P(1))^0, 99) * m.V"C", 805 S = m.V"A" * m.V"C",
896 A = m.P"a"^1 * ("b" + m.T(99)), 806 A = m.P"a"^1 * ("b" + m.T'Rec'),
897 C = m.P"c"^1, 807 C = m.P"c"^1,
808 Rec = (-m.P"c" * m.P(1))^0
898} 809}
899 810
900assert(g:match("abc") == 4) 811assert(g:match("abc") == 4)
@@ -916,34 +827,24 @@ lpeg = m
916 827
917local R, S, P, V = lpeg.R, lpeg.S, lpeg.P, lpeg.V 828local R, S, P, V = lpeg.R, lpeg.S, lpeg.P, lpeg.V
918local C, Cc, Ct, Cmt = lpeg.C, lpeg.Cc, lpeg.Ct, lpeg.Cmt 829local C, Cc, Ct, Cmt = lpeg.C, lpeg.Cc, lpeg.Ct, lpeg.Cmt
919local T, Lc = lpeg.T, lpeg.Lc 830local T = lpeg.T
920 831
921local labels = { 832local labels = {
922 {"NoExp", "no expression found"}, 833 NoExp = "no expression found",
923 {"Extra", "extra characters found after the expression"}, 834 Extra = "extra characters found after the expression",
924 {"ExpTerm", "expected a term after the operator"}, 835 ExpTerm = "expected a term after the operator",
925 {"ExpExp", "expected an expression after the parenthesis"}, 836 ExpExp = "expected an expression after the parenthesis",
926 {"MisClose", "missing a closing ')' after the expression"}, 837 MisClose = "missing a closing ')' after the expression",
927} 838}
928 839
929local function labelindex(labname)
930 for i, elem in ipairs(labels) do
931 if elem[1] == labname then
932 return i
933 end
934 end
935 error("could not find label: " .. labname)
936end
937
938local errors = {} 840local errors = {}
939 841
940local function expect(patt, labname) 842local function expect(patt, labname)
941 local i = labelindex(labname)
942 function recorderror(input, pos) 843 function recorderror(input, pos)
943 table.insert(errors, {i, pos}) 844 table.insert(errors, {labname, pos})
944 return true 845 return true
945 end 846 end
946 return patt + Cmt("", recorderror) * T(i) 847 return patt + Cmt("", recorderror) * T(labname)
947end 848end
948 849
949local num = R("09")^1 / tonumber 850local num = R("09")^1 / tonumber
@@ -969,12 +870,14 @@ end
969 870
970local g = P { 871local g = P {
971 "Exp", 872 "Exp",
972 Exp = Ct(V"Term" * (C(op) * V"OpRecov")^0) / compute; 873 Exp = Ct(V"Term" * (C(op) * V"Operand")^0) / compute;
973 OpRecov = m.Rec(V"Operand", Cc(0), labelindex("ExpTerm"));
974 Operand = expect(V"Term", "ExpTerm"); 874 Operand = expect(V"Term", "ExpTerm");
975 Term = num + V"Group"; 875 Term = num + V"Group";
976 Group = "(" * V"InnerExp" * m.Rec(expect(")", "MisClose"), P"", labelindex("MisClose")); 876 Group = "(" * V"InnerExp" * expect(")", "MisClose");
977 InnerExp = m.Rec(expect(V"Exp", "ExpExp"), (P(1) - ")")^0 * Cc(0), labelindex("ExpExp")); 877 InnerExp = expect(V"Exp", "ExpExp");
878 ExpTerm = Cc(0);
879 MisClose = P"";
880 ExpExp = (P(1) - ")")^0 * Cc(0);
978} 881}
979 882
980g = expect(g, "NoExp") * expect(-P(1), "Extra") 883g = expect(g, "NoExp") * expect(-P(1), "Extra")
@@ -987,7 +890,7 @@ local function eval(input)
987 local out = {} 890 local out = {}
988 for i, err in ipairs(errors) do 891 for i, err in ipairs(errors) do
989 local pos = err[2] 892 local pos = err[2]
990 local msg = labels[err[1]][2] 893 local msg = labels[err[1]]
991 table.insert(out, "syntax error: " .. msg .. " (at index " .. pos .. ")") 894 table.insert(out, "syntax error: " .. msg .. " (at index " .. pos .. ")")
992 end 895 end
993 errors = {} 896 errors = {}
@@ -1022,51 +925,66 @@ assert(e == nil and msg == "syntax error: expected a term after the operator (at
1022 925
1023print("+") 926print("+")
1024 927
1025local g = m.P{ 928local g1 = {
1026 "S", 929 "S1",
1027 S = V"End" + V'A' * V'S', 930 S1 = V"End" + V'A' * V'S1',
1028 A = P'a' + T(1), 931 A = P'a' + T'Ea',
1029 End = P"." * (-P(1) + T(2)), 932 End = P"." * (-P(1) + T'Eend'),
1030} 933}
1031 934
1032assert(g:match("a.") == 3) 935local p1 = m.P(g1)
1033assert(g:match("aa.") == 4)
1034assert(g:match(".") == 2)
1035checklabeq({nil, 1, 1}, g:match("ba."))
1036checklabeq({nil, 1, 2}, g:match("aba."))
1037checklabeq({nil, 1, 1}, g:match("cba."))
1038checklabeq({nil, 2, 3}, g:match("a.a"))
1039 936
937assert(p1:match("a.") == 3)
938assert(p1:match("aa.") == 4)
939assert(p1:match(".") == 2)
940checklabeq({nil, 'Ea', 1}, p1:match("ba."))
941checklabeq({nil, 'Ea', 2}, p1:match("aba."))
942checklabeq({nil, 'Ea', 1}, p1:match("cba."))
943checklabeq({nil, 'Eend', 3}, p1:match("a.a"))
1040 944
1041local g2 = m.P{ 945local g2 = {
1042 "S", 946 "S2",
1043 S = m.Rec(g, V"B", 1), 947 S2 = m.V"S1",
1044 B = P'b'^1 + T(3) 948 Ea = P'b'^1 + T'Eb',
1045} 949}
1046 950
1047assert(g2:match("a.") == 3) 951g1[1] = nil -- start rule
1048assert(g2:match("aa.") == 4) 952for k, v in pairs(g1) do
1049assert(g2:match(".") == 2) 953 g2[k] = v
1050assert(g2:match("ba.") == 4) 954end
1051assert(g2:match("aba.") == 5)
1052checklabeq({nil, 3, 1}, g2:match("cba."))
1053checklabeq({nil, 2, 3}, g2:match("a.a"))
1054 955
1055local g3 = m.P{ 956local p2 = m.P(g2)
1056 "S", 957
1057 S = m.Rec(g2, V"C", 2, 3), 958assert(p2:match("a.") == 3)
1058 C = P'c'^1 + T(4) 959assert(p2:match("aa.") == 4)
960assert(p2:match(".") == 2)
961assert(p2:match("ba.") == 4)
962assert(p2:match("aba.") == 5)
963checklabeq({nil, 'Eb', 1}, p2:match("cba."))
964checklabeq({nil, 'Eend', 3}, p2:match("a.a"))
965
966local g3 = {
967 "S3",
968 S3 = V'S2',
969 Eb = P'c'^1 + T'Ec',
970 Eend = V'Eb',
1059} 971}
972g2[1] = nil -- start rule
973for k, v in pairs(g2) do
974 g3[k] = v
975end
976
977local p3 = m.P(g3)
1060 978
1061assert(g3:match("a.") == 3) 979assert(p3:match("a.") == 3)
1062assert(g3:match("aa.") == 4) 980assert(p3:match("aa.") == 4)
1063assert(g3:match(".") == 2) 981assert(p3:match(".") == 2)
1064assert(g3:match("ba.") == 4) 982assert(p3:match("ba.") == 4)
1065assert(g3:match("aba.") == 5) 983assert(p3:match("aba.") == 5)
1066assert(g3:match("cba.") == 5) 984assert(p3:match("cba.") == 5)
1067checklabeq({nil, 4, 3}, g3:match("a.a")) 985checklabeq({nil, 'Ec', 3}, p3:match("a.a"))
1068checklabeq({nil, 4, 1}, g3:match("dc")) 986checklabeq({nil, 'Ec', 1}, p3:match("dc"))
1069checklabeq({nil, 4, 2}, g3:match(".d")) 987checklabeq({nil, 'Ec', 2}, p3:match(".d"))
1070 988
1071 989
1072-- testing more captures 990-- testing more captures
@@ -1078,7 +996,11 @@ local g = re.compile[[
1078checkeq({"523", "624", "346", "888"} , {g:match("523 624 346\n888")}) 996checkeq({"523", "624", "346", "888"} , {g:match("523 624 346\n888")})
1079checkeq({nil, 5, 4}, {g:match("44 a 123")}) 997checkeq({nil, 5, 4}, {g:match("44 a 123")})
1080 998
1081local g2 = m.Rec(g, ((-m.R("09") * m.P(1))^0) / "58", 5) 999local g2 = re.compile[[
1000 S <- ( %s* &. {A} )*
1001 A <- [0-9]+ / %{Rec}
1002 Rec <- ((![0-9] .)*) -> "58"
1003]]
1082 1004
1083checkeq({"523", "624", "346", "888"} , {g2:match("523 624 346\n888")}) 1005checkeq({"523", "624", "346", "888"} , {g2:match("523 624 346\n888")})
1084checkeq({"44", "a ", "58", "123"}, {g2:match("44 a 123")}) 1006checkeq({"44", "a ", "58", "123"}, {g2:match("44 a 123")})
@@ -1092,7 +1014,11 @@ local g = re.compile[[
1092checkeq({"523", "624", "346", "888"} , {g:match("523 624 346\n888")}) 1014checkeq({"523", "624", "346", "888"} , {g:match("523 624 346\n888")})
1093checkeq({nil, 5, 4}, {g:match("44 a 123")}) 1015checkeq({nil, 5, 4}, {g:match("44 a 123")})
1094 1016
1095local g2 = m.Rec(g, ((-m.R("09") * m.P(1))^0) / "58", 5) 1017local g2 = re.compile[[
1018 S <- ( %s* &. A )*
1019 A <- {[0-9]+} / %{Rec}
1020 Rec <- ((![0-9] .)*) -> "58"
1021]]
1096 1022
1097checkeq({"523", "624", "346", "888"} , {g2:match("523 624 346\n888")}) 1023checkeq({"523", "624", "346", "888"} , {g2:match("523 624 346\n888")})
1098checkeq({"44", "58", "123"}, {g2:match("44 a 123")}) 1024checkeq({"44", "58", "123"}, {g2:match("44 a 123")})
@@ -1100,7 +1026,7 @@ checkeq({"44", "58", "123"}, {g2:match("44 a 123")})
1100 1026
1101local R, S, P, V = lpeg.R, lpeg.S, lpeg.P, lpeg.V 1027local R, S, P, V = lpeg.R, lpeg.S, lpeg.P, lpeg.V
1102local C, Cc, Ct, Cmt = lpeg.C, lpeg.Cc, lpeg.Ct, lpeg.Cmt 1028local C, Cc, Ct, Cmt = lpeg.C, lpeg.Cc, lpeg.Ct, lpeg.Cmt
1103local T, Lc, Rec = lpeg.T, lpeg.Lc, lpeg.Rec 1029local T = lpeg.T
1104 1030
1105local labels = { 1031local labels = {
1106 {"NoExp", "no expression found"}, 1032 {"NoExp", "no expression found"},
@@ -1110,26 +1036,16 @@ local labels = {
1110 {"MisClose", "missing a closing ')' after the expression"}, 1036 {"MisClose", "missing a closing ')' after the expression"},
1111} 1037}
1112 1038
1113local function labelindex(labname)
1114 for i, elem in ipairs(labels) do
1115 if elem[1] == labname then
1116 return i
1117 end
1118 end
1119 error("could not find label: " .. labname)
1120end
1121
1122local errors = {} 1039local errors = {}
1123 1040
1124local function expect(patt, labname, recpatt) 1041local function expect(patt, labname, recpatt)
1125 local i = labelindex(labname)
1126 function recorderror(input, pos) 1042 function recorderror(input, pos)
1127 table.insert(errors, {i, pos}) 1043 table.insert(errors, {labname, pos})
1128 return true 1044 return true
1129 end 1045 end
1130 if not recpatt then recpatt = P"" end 1046 if not recpatt then recpatt = P"" end
1131 --return Rec(patt, Cmt("", recorderror) * recpatt) 1047 --return Rec(patt, Cmt("", recorderror) * recpatt)
1132 return patt + T(i) 1048 return patt + T(labname)
1133end 1049end
1134 1050
1135local num = R("09")^1 / tonumber 1051local num = R("09")^1 / tonumber
@@ -1155,22 +1071,22 @@ end
1155 1071
1156 1072
1157local g = P { 1073local g = P {
1158"Exp", 1074 "Exp",
1159Exp = Ct(V"Term" * (C(op) * V"Operand")^0) / compute, 1075 Exp = Ct(V"Term" * (C(op) * V"Operand")^0) / compute,
1160Operand = expect(V"Term", "ExpTerm"), 1076 Operand = expect(V"Term", "ExpTerm"),
1161Term = num, 1077 Term = num,
1078 ExpTerm = Cc(3)
1162} 1079}
1163local rg = Rec(g, Cc(3), labelindex("ExpTerm"))
1164 1080
1165local function eval(input) 1081local function eval(input)
1166 local result, label, suffix = rg:match(input) 1082 local result, label, suffix = g:match(input)
1167 if #errors == 0 then 1083 if #errors == 0 then
1168 return result 1084 return result
1169 else 1085 else
1170 local out = {} 1086 local out = {}
1171 for i, err in ipairs(errors) do 1087 for i, err in ipairs(errors) do
1172 local pos = err[2] 1088 local pos = err[2]
1173 local msg = labels[err[1]][2] 1089 local msg = labels[err[1]]
1174 table.insert(out, "syntax error: " .. msg .. " (at index " .. pos .. ")") 1090 table.insert(out, "syntax error: " .. msg .. " (at index " .. pos .. ")")
1175 end 1091 end
1176 errors = {} 1092 errors = {}
@@ -1184,218 +1100,4 @@ assert(eval("98-76*54/32") == 37.125)
1184assert(eval("1+") == 4) 1100assert(eval("1+") == 4)
1185--> syntax error: expected a term after the operator (at index 3) 1101--> syntax error: expected a term after the operator (at index 3)
1186 1102
1187
1188-- tests related to the use of '^' in relabel to throw labels
1189local errinfo = {
1190 { 'cmdSeq', "Missing ';' in CmdSeq"},
1191 { 'ifExp', "Error in expresion of 'if'"},
1192 { 'ifThen', "Error matching 'then' keyword"},
1193 { 'ifThenCmdSeq', "Error matching CmdSeq of 'then' branch"},
1194 { 'ifElseCmdSeq', "Error matching CmdSeq of 'else' branch"},
1195 { 'ifEnd', "Error matching 'end' keyword of 'if'"},
1196 { 'repeatCmdSeq', "Error matching CmdSeq of 'repeat'"},
1197 { 'repeatUntil', "Error matching 'until' keyword"},
1198 { 'repeatExp', "Error matching expression of 'until'"},
1199 { 'assignOp', "Error matching ':='"},
1200 { 'assignExp', "Error matching expression of assignment"},
1201 { 'readName', "Error matching 'NAME' after 'read'"},
1202 { 'writeExp', "Error matching expression after 'write'"},
1203 { 'simpleExp', "Error matching 'SimpleExp'"},
1204 { 'term', "Error matching 'Term'"},
1205 { 'factor', "Error matching 'Factor'"},
1206 { 'openParExp', "Error matching expression after '('"},
1207 { 'closePar', "Error matching ')'"},
1208 { 'undefined', "Undefined Error" }
1209}
1210
1211
1212local errmsgs = {}
1213local labels = {}
1214
1215for i, err in ipairs(errinfo) do
1216 errmsgs[i] = err[2]
1217 labels[err[1]] = i
1218end
1219
1220re.setlabels(labels)
1221
1222g = re.compile([[
1223 Tiny <- CmdSeq
1224 CmdSeq <- (Cmd SEMICOLON^cmdSeq) (Cmd SEMICOLON^cmdSeq)*
1225 Cmd <- IfCmd / RepeatCmd / ReadCmd / WriteCmd / AssignCmd
1226 IfCmd <- IF Exp^ifExp THEN^ifThen CmdSeq^ifThenCmdSeq (ELSE CmdSeq^ifElseCmdSeq / '') END^ifEnd
1227 RepeatCmd <- REPEAT CmdSeq^repeatCmdSeq UNTIL^repeatUntil Exp^repeatExp
1228 AssignCmd <- NAME ASSIGNMENT^assignOp Exp^assignExp
1229 ReadCmd <- READ NAME^readName
1230 WriteCmd <- WRITE Exp^writeExp
1231 Exp <- SimpleExp ((LESS / EQUAL) SimpleExp^simpleExp / '')
1232 SimpleExp <- Term ((ADD / SUB) Term^term)*
1233 Term <- Factor ((MUL / DIV) Factor^factor)*
1234 Factor <- OPENPAR Exp^openParExp CLOSEPAR^closePar / NUMBER / NAME
1235 ADD <- Sp '+'
1236 ASSIGNMENT <- Sp ':='
1237 CLOSEPAR <- Sp ')'
1238 DIV <- Sp '/'
1239 IF <- Sp 'if'
1240 ELSE <- Sp 'else'
1241 END <- Sp 'end'
1242 EQUAL <- Sp '='
1243 LESS <- Sp '<'
1244 MUL <- Sp '*'
1245 NAME <- !RESERVED Sp [a-z]+
1246 NUMBER <- Sp [0-9]+
1247 OPENPAR <- Sp '('
1248 READ <- Sp 'read'
1249 REPEAT <- Sp 'repeat'
1250 SEMICOLON <- Sp ';'
1251 SUB <- Sp '-'
1252 THEN <- Sp 'then'
1253 UNTIL <- Sp 'until'
1254 WRITE <- Sp 'write'
1255 RESERVED <- (IF / ELSE / END / READ / REPEAT / THEN / UNTIL / WRITE) ![a-z]+
1256 Sp <- (%s / %nl)*
1257]])
1258
1259s = [[
1260n := 5;]]
1261assert(g:match(s) == #s + 1)
1262
1263s = [[
1264n := 5;
1265f := 1;
1266repeat
1267 f := f * n;
1268 n := n - 1;
1269until (n < 1);
1270write f;]]
1271assert(g:match(s) == #s + 1)
1272
1273-- a ';' is missing in 'read a'
1274s = [[
1275read a]]
1276assert(table.pack(g:match(s))[2] == labels['cmdSeq'])
1277
1278
1279-- a ';' is missing in 'n := n - 1'
1280s = [[
1281n := 5;
1282f := 1;
1283repeat
1284 f := f * n;
1285 n := n - 1
1286until (n < 1);
1287write f;]]
1288assert(table.pack(g:match(s))[2] == labels['cmdSeq'])
1289
1290
1291-- IF expression
1292s = [[
1293if a then a := a + 1; end;]]
1294assert(g:match(s) == #s + 1)
1295
1296-- IF expression
1297s = [[
1298if a then a := a + 1; else write 2; end;]]
1299assert(g:match(s) == #s + 1)
1300
1301-- Error in expression of 'if'. 'A' is not a valida name
1302s = [[
1303if A then a := a + 1; else write 2; end;]]
1304assert(table.pack(g:match(s))[2] == labels['ifExp'])
1305
1306-- Error matching the 'then' keyword
1307s = [[
1308if a a := a + 1; else write 2; end;]]
1309assert(table.pack(g:match(s))[2] == labels['ifThen'])
1310
1311-- Error matching the CmdSeq inside of 'then' branch
1312s = [[
1313if a then 3 := 2; else write 2; end;]]
1314assert(table.pack(g:match(s))[2] == labels['ifThenCmdSeq'])
1315
1316-- Error matching the CmdSeq inside of 'else' branch
1317s = [[
1318if a then b := 2; else A := 2; end;]]
1319assert(table.pack(g:match(s))[2] == labels['ifElseCmdSeq'])
1320
1321-- Error matching 'end' of 'if'
1322s = [[
1323if a then b := 2; else a := 2; 77;]]
1324assert(table.pack(g:match(s))[2] == labels['ifEnd'])
1325
1326-- Error matching the CmdSeq of 'repeat'
1327s = [[repeat
1328 F := f * n;
1329 n := n - 1;
1330until (n < 1);]]
1331assert(table.pack(g:match(s))[2] == labels['repeatCmdSeq'])
1332
1333-- Error matching 'until'
1334s = [[repeat
1335 f := f * n;
1336 n := n - 1;
133788 (n < 1);]]
1338assert(table.pack(g:match(s))[2] == labels['repeatUntil'])
1339
1340-- Error matching expression of 'until'
1341s = [[repeat
1342 f := f * n;
1343 n := n - 1;
1344until ; (n < 1);]]
1345assert(table.pack(g:match(s))[2] == labels['repeatExp'])
1346
1347-- Error matching ':='
1348s = [[
1349f = f * n;]]
1350assert(table.pack(g:match(s))[2] == labels['assignOp'])
1351
1352-- Error matching expression of assignment
1353s = [[
1354f := A * n;]]
1355assert(table.pack(g:match(s))[2] == labels['assignExp'])
1356
1357-- Error matching 'name'
1358s = [[
1359read 2;]]
1360assert(table.pack(g:match(s))[2] == labels['readName'])
1361
1362-- Error matching expression after 'write'
1363s = [[
1364write [a] := 2;]]
1365assert(table.pack(g:match(s))[2] == labels['writeExp'])
1366
1367-- Error matching 'SimpleExp'
1368s = [[
1369a := a < A;]]
1370assert(table.pack(g:match(s))[2] == labels['simpleExp'])
1371
1372-- Error matching 'Term'
1373s = [[
1374a := a + A;]]
1375assert(table.pack(g:match(s))[2] == labels['term'])
1376
1377-- Error matching 'Factor'
1378s = [[
1379a := a * A;]]
1380assert(table.pack(g:match(s))[2] == labels['factor'])
1381
1382-- Error matching expression after '('
1383s = [[
1384a := (A);]]
1385assert(table.pack(g:match(s))[2] == labels['openParExp'])
1386
1387-- Error matching ')'
1388s = [[
1389a := (a];]]
1390assert(table.pack(g:match(s))[2] == labels['closePar'])
1391
1392-- Error undefined
1393s = [[
1394A := a;]]
1395assert(table.pack(g:match(s))[2] == 0)
1396
1397
1398
1399
1400
1401print("OK") 1103print("OK")