diff options
| author | Sergio Queiroz <sqmedeiros@gmail.com> | 2016-12-13 13:58:50 -0300 |
|---|---|---|
| committer | Sergio Queiroz <sqmedeiros@gmail.com> | 2016-12-13 13:58:50 -0300 |
| commit | 20cb6e1443f3b79a4db3fedf25bc2eff91ef7d70 (patch) | |
| tree | cd92a87651b851fd95cf47a491aa96e1dc52fe21 | |
| parent | 09fab0decb7df93528ab40fcfd99587e9074c64f (diff) | |
| download | lpeglabel-20cb6e1443f3b79a4db3fedf25bc2eff91ef7d70.tar.gz lpeglabel-20cb6e1443f3b79a4db3fedf25bc2eff91ef7d70.tar.bz2 lpeglabel-20cb6e1443f3b79a4db3fedf25bc2eff91ef7d70.zip | |
Fixing README.md after the merge
| -rw-r--r-- | README.md | 114 |
1 files changed, 0 insertions, 114 deletions
| @@ -74,15 +74,6 @@ Otherwise, the result of the matching of `p1` is the pattern's result. | |||
| 74 | 74 | ||
| 75 | 75 | ||
| 76 | 76 | ||
| 77 | #### <a name="f-rec"></a><code>lpeglabel.Rec(p1, p2 [, l1, ..., ln])</code> | ||
| 78 | |||
| 79 | The *recovery operator* is similar to labeled order choice except | ||
| 80 | that the matching of `p2` is tried from the failure position of `p1`. | ||
| 81 | |||
| 82 | If no label is provided, the regular PEG failure is caught | ||
| 83 | i.e. `lpeg.Rec(p1, p2)` is equivalent to `lpeg.Rec(p1, p2, 0)`. | ||
| 84 | |||
| 85 | |||
| 86 | #### <a name="re-t"></a><code>%{l}</code> | 77 | #### <a name="re-t"></a><code>%{l}</code> |
| 87 | 78 | ||
| 88 | Syntax of *relabelrec* module. Equivalent to `lpeg.T(l)`. | 79 | Syntax of *relabelrec* module. Equivalent to `lpeg.T(l)`. |
| @@ -698,108 +689,3 @@ print(eval "3)") | |||
| 698 | -- syntax error: extra characters found after the expression (at index 2) | 689 | -- syntax error: extra characters found after the expression (at index 2) |
| 699 | -- Result = 3 | 690 | -- Result = 3 |
| 700 | ``` | 691 | ``` |
| 701 | |||
| 702 | #### Error Recovery | ||
| 703 | |||
| 704 | By using labeled ordered choice or the recovery operator, when a label | ||
| 705 | is thrown, the parser may record the error and still continue parsing | ||
| 706 | to find more errors. We can even record the error right away without | ||
| 707 | actually throwing a label (relying on the regular PEG failure instead). | ||
| 708 | Below we rewrite the arithmetic expression example and modify | ||
| 709 | the `expect` function to use the recovery operator for error recovery: | ||
| 710 | |||
| 711 | ```lua | ||
| 712 | local lpeg = require"lpeglabel" | ||
| 713 | |||
| 714 | local R, S, P, V = lpeg.R, lpeg.S, lpeg.P, lpeg.V | ||
| 715 | local C, Cc, Ct, Cmt, Carg = lpeg.C, lpeg.Cc, lpeg.Ct, lpeg.Cmt, lpeg.Carg | ||
| 716 | local T, Lc, Rec = lpeg.T, lpeg.Lc, lpeg.Rec | ||
| 717 | |||
| 718 | local labels = { | ||
| 719 | {"NoExp", "no expression found"}, | ||
| 720 | {"Extra", "extra characters found after the expression"}, | ||
| 721 | {"ExpTerm", "expected a term after the operator"}, | ||
| 722 | {"ExpExp", "expected an expression after the parenthesis"}, | ||
| 723 | {"MisClose", "missing a closing ')' after the expression"}, | ||
| 724 | } | ||
| 725 | |||
| 726 | local function labelindex(labname) | ||
| 727 | for i, elem in ipairs(labels) do | ||
| 728 | if elem[1] == labname then | ||
| 729 | return i | ||
| 730 | end | ||
| 731 | end | ||
| 732 | error("could not find label: " .. labname) | ||
| 733 | end | ||
| 734 | |||
| 735 | local function expect(patt, labname, recpatt) | ||
| 736 | local i = labelindex(labname) | ||
| 737 | local function recorderror(input, pos, errors) | ||
| 738 | table.insert(errors, {i, pos}) | ||
| 739 | return true | ||
| 740 | end | ||
| 741 | if not recpatt then recpatt = P"" end | ||
| 742 | return Rec(patt, Cmt(Carg(1), recorderror) * recpatt) | ||
| 743 | end | ||
| 744 | |||
| 745 | local num = R("09")^1 / tonumber | ||
| 746 | local op = S("+-*/") | ||
| 747 | |||
| 748 | local function compute(tokens) | ||
| 749 | local result = tokens[1] | ||
| 750 | for i = 2, #tokens, 2 do | ||
| 751 | if tokens[i] == '+' then | ||
| 752 | result = result + tokens[i+1] | ||
| 753 | elseif tokens[i] == '-' then | ||
| 754 | result = result - tokens[i+1] | ||
| 755 | elseif tokens[i] == '*' then | ||
| 756 | result = result * tokens[i+1] | ||
| 757 | elseif tokens[i] == '/' then | ||
| 758 | result = result / tokens[i+1] | ||
| 759 | else | ||
| 760 | error('unknown operation: ' .. tokens[i]) | ||
| 761 | end | ||
| 762 | end | ||
| 763 | return result | ||
| 764 | end | ||
| 765 | |||
| 766 | |||
| 767 | local g = P { | ||
| 768 | "Exp", | ||
| 769 | Exp = Ct(V"Term" * (C(op) * V"Operand")^0) / compute; | ||
| 770 | Operand = expect(V"Term", "ExpTerm", Cc(0)); | ||
| 771 | Term = num + V"Group"; | ||
| 772 | Group = "(" * V"InnerExp" * expect(")", "MisClose"); | ||
| 773 | InnerExp = expect(V"Exp", "ExpExp", (P(1) - ")")^0 * Cc(0)); | ||
| 774 | } | ||
| 775 | |||
| 776 | g = expect(g, "NoExp", P(1)^0) * expect(-P(1), "Extra") | ||
| 777 | |||
| 778 | local function eval(input) | ||
| 779 | local errors = {} | ||
| 780 | local result, label, suffix = g:match(input, 1, errors) | ||
| 781 | if #errors == 0 then | ||
| 782 | return result | ||
| 783 | else | ||
| 784 | local out = {} | ||
| 785 | for i, err in ipairs(errors) do | ||
| 786 | local pos = err[2] | ||
| 787 | local msg = labels[err[1]][2] | ||
| 788 | table.insert(out, "syntax error: " .. msg .. " (at index " .. pos .. ")") | ||
| 789 | end | ||
| 790 | return nil, table.concat(out, "\n") | ||
| 791 | end | ||
| 792 | end | ||
| 793 | |||
| 794 | print(eval "98-76*(54/32)") | ||
| 795 | --> 37.125 | ||
| 796 | |||
| 797 | print(eval "-1+(1-(1*2))/2") | ||
| 798 | --> syntax error: no expression found (at index 1) | ||
| 799 | |||
| 800 | print(eval "(1+1-1*(2/2+)-():") | ||
| 801 | --> syntax error: expected a term after the operator (at index 13) | ||
| 802 | --> syntax error: expected an expression after the parenthesis (at index 16) | ||
| 803 | --> syntax error: missing a closing ')' after the expression (at index 17) | ||
| 804 | --> syntax error: extra characters found after the expression (at index 17) | ||
| 805 | ``` | ||
