{"id":32985715,"url":"https://github.com/sqmedeiros/lpeglabel","last_synced_at":"2025-11-16T16:01:05.302Z","repository":{"id":22599347,"uuid":"25941396","full_name":"sqmedeiros/lpeglabel","owner":"sqmedeiros","description":"An extension of LPeg that supports labeled failures","archived":false,"fork":false,"pushed_at":"2023-05-02T17:27:51.000Z","size":429,"stargazers_count":136,"open_issues_count":3,"forks_count":17,"subscribers_count":11,"default_branch":"master","last_synced_at":"2024-06-24T04:55:56.951Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"C","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/sqmedeiros.png","metadata":{"files":{"readme":"README.md","changelog":"HISTORY","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null}},"created_at":"2014-10-29T21:07:12.000Z","updated_at":"2024-06-22T20:00:24.000Z","dependencies_parsed_at":"2024-01-08T20:19:18.338Z","dependency_job_id":null,"html_url":"https://github.com/sqmedeiros/lpeglabel","commit_stats":null,"previous_names":[],"tags_count":11,"template":false,"template_full_name":null,"purl":"pkg:github/sqmedeiros/lpeglabel","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sqmedeiros%2Flpeglabel","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sqmedeiros%2Flpeglabel/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sqmedeiros%2Flpeglabel/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sqmedeiros%2Flpeglabel/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/sqmedeiros","download_url":"https://codeload.github.com/sqmedeiros/lpeglabel/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sqmedeiros%2Flpeglabel/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":284734138,"owners_count":27054622,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-11-16T02:00:05.974Z","response_time":65,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2025-11-13T08:00:33.767Z","updated_at":"2025-11-16T16:01:05.296Z","avatar_url":"https://github.com/sqmedeiros.png","language":"C","funding_links":[],"categories":["资源","Resources"],"sub_categories":["Parsing and Serialization","Libraries"],"readme":"\u003cp align=\"center\"\u003e\u003cimg src=\"https://github.com/sqmedeiros/lpeglabel/raw/master/lpeglabel-logo.png\" alt=\"LPegLabel\" width=\"150px\"\u003e\u003c/p\u003e\n\n## LPegLabel - Parsing Expression Grammars (with Labels) for Lua \n\n---\n\n### Introduction\n\nLPegLabel is a conservative extension of the\n[LPeg](http://www.inf.puc-rio.br/~roberto/lpeg)\nlibrary that provides an implementation of Parsing\nExpression Grammars (PEGs) with labeled failures.\nLabels can be used to signal different kinds of errors\nand to specify which recovery pattern should handle a\ngiven label. Labels can also be combined with the standard\npatterns of LPeg. \n\nBesides that, LPegLabel also reports the farthest\nfailure position in case of an ordinary failure\n(which is represented by label **fail**).\n\nThis document describes the new functions available\nin LpegLabel and presents some examples of usage.\n\nWith labeled failures it is possible to distinguish\nbetween an ordinary failure and an error. Usually, an\nordinary failure is produced when the matching of a\ncharacter fails, and this failure is caught by ordered choice.\nAn error (a non-ordinary failure), by its turn, is produced\nby the throw operator and may be caught by a recovery rule. \n\nIn LPegLabel, the result of an unsuccessful matching\nis a triple **nil, lab, errpos**, where **lab**\nis the label associated with the failure (a string or\nan integer), and **errpos** is the input position being\nmatched when **lab** was thrown. \n\nWhen **lab** is an ordinary failure and no error was thrown before,\n**errpos** is the farthest position where an ordinary failure occurred. \nIn case **lab** is an ordinary failure and an error\nwas thrown before, **errpos** is the farthest input position\nwhere an ordinary failure occurred after the last error. \n \nBelow there is a brief summary of the new functions provided by LpegLabel: \n\n\u003ctable border=\"1\"\u003e\n\u003ctbody\u003e\u003ctr\u003e\u003ctd\u003e\u003cb\u003eFunction\u003c/b\u003e\u003c/td\u003e\u003ctd\u003e\u003cb\u003eDescription\u003c/b\u003e\u003c/td\u003e\u003c/tr\u003e\n\u003ctr\u003e\u003ctd\u003e\u003ca href=\"#f-t\"\u003e\u003ccode\u003elpeglabel.T (l)\u003c/code\u003e\u003c/a\u003e\u003c/td\u003e\n  \u003ctd\u003eThrows a label \u003ccode\u003el\u003c/code\u003e to signal an error\u003c/td\u003e\u003c/tr\u003e\n\u003ctr\u003e\u003ctd\u003e\u003ca href=\"#re-t\"\u003e\u003ccode\u003e%{l}\u003c/code\u003e\u003c/a\u003e\u003c/td\u003e\n  \u003ctd\u003eSyntax of \u003cem\u003erelabel\u003c/em\u003e module. Equivalent to \u003ccode\u003elpeglabel.T(l)\u003c/code\u003e\n      \u003c/td\u003e\u003c/tr\u003e\n\u003ctr\u003e\u003ctd\u003e\u003ca href=\"#re-pow\"\u003e\u003ccode\u003ep^l\u003c/code\u003e\u003c/a\u003e\u003c/td\u003e\n  \u003ctd\u003eSyntax sugar available at \u003cem\u003erelabel\u003c/em\u003e for \u003ccode\u003ep / %{l}\u003c/code\u003e\n      \u003c/td\u003e\u003c/tr\u003e\n\u003ctr\u003e\u003ctd\u003e\u003ca href=\"#re-line\"\u003e\u003ccode\u003erelabel.calcline(subject, i)\u003c/code\u003e\u003c/a\u003e\u003c/td\u003e\n  \u003ctd\u003eCalculates line and column information regarding position \u003ci\u003ei\u003c/i\u003e of the subject\u003c/code\u003e\n      \u003c/td\u003e\u003c/tr\u003e\n\u003c/tbody\u003e\u003c/table\u003e\n\n\n### Functions\n\n\n#### \u003ca name=\"f-t\"\u003e\u003c/a\u003e\u003ccode\u003elpeglabel.T(l)\u003c/code\u003e\n\nReturns a pattern that throws the label `l`, which\ncan be an integer or a string.\n\nWhen a label is thrown, the current subject position \nis used to set **errpos**, no matter whether it is the\nfartherst failure position or not.\n\nIn case the PEG grammar has a rule `l`, after a label is thrown\nthis rule will be used as a recovery rule, otherwise the whole\nmatching fails.\n \nThe recovery rule will try to match the input from the subject\nposition where `l` was thrown. In case the matching of the recovery\nrule succeeds, the regular matching is resumed. Otherwise, the\nresult of the recovery rule is the matching result.\n \nWhen we have a predicate such as `-p` or `#p` and a label `l` is thrown\nduring the matching of `p`, this causes the failure of `p`, but does\nnot propagate `l`, or calls its associated recovery rule.\n\n\n#### \u003ca name=\"re-t\"\u003e\u003c/a\u003e\u003ccode\u003e%{l}\u003c/code\u003e\n\nSyntax of *relabel* module. Equivalent to `lpeglabel.T(l)`.\n\nLabel `l` must be a valid identifier name.\n\n#### \u003ca name=\"re-pow\"\u003e\u003c/a\u003e\u003ccode\u003ep^l\u003c/code\u003e\n\nSyntax of *relabel* module. The pattern `p^l` is equivalent\nto `p + lpeglabel.T(l)`.\n\nLabel `l` must be a valid identifier name.\n\n\n#### \u003ca name=\"re-line\"\u003e\u003c/a\u003e\u003ccode\u003erelabel.calcline (subject, i)\u003c/code\u003e\n\nReturns line and column information regarding position \u003ci\u003ei\u003c/i\u003e of the subject.\n\n\n\n### Examples\n\nBelow there a few examples of usage of LPegLabel.\nThe code of these and of other examples is available\nin the *examples* directory. \n\n\n#### Reporting the farthest failure\n\nThis example illustrates the new values returned\nby the *match* function in case of an unsuccessful\nmatching. As no error is thrown in this example,\nwhen the matching fails *errpos* represents the\nfarthest suffix where an ordinary failure occurred.\n\n```lua\nlocal m = require'lpeglabel'\n\nfunction matchPrint(p, s)\n  local r, lab, errpos = p:match(s)\n  print(\"r: \", r, \"lab: \", lab, \"errpos: \", errpos)\nend\n\nlocal p = m.P\"a\"^0 * m.P\"b\" + m.P\"c\"\nmatchPrint(p, \"abc\")  --\u003e r: 3    lab: nil   errpos: nil\nmatchPrint(p, \"c\")    --\u003e r: 2    lab: nil   errpos: nil\nmatchPrint(p, \"aac\")  --\u003e r: nil  lab: fail  errpos: 3\nmatchPrint(p, \"xxc\")  --\u003e r: nil  lab: fail  errpos: 1\n```\n\n\n#### Matching a list of identifiers separated by commas\n\nThe following example defines a grammar that matches\na (possibly empty) list of identifiers separated by commas.\nA label is thrown when there is no identifier after a comma,\nor when the whole input is not matched.\n\n\n```lua\nlocal m = require'lpeglabel'\nlocal re = require'relabel'\n\nlocal terror = {\n  ErrId   =  \"expecting an identifier\",\n  ErrEnd  =  \"expecting EOF\",\n  fail    =  \"undefined\"\n}\n\nlocal id = m.R'az'^1\n\nlocal g = m.P{\n  'S',\n  S      =  m.V'List' * (-m.P(1) + m.T'ErrEnd'),\n  List   =  m.V'Id' * (m.V'Comma' * (m.V'Id' + m.T'ErrId'))^0,\n  Id     =  m.V'Sp' * id,\n  Comma  =  m.V'Sp' * ',',\n  Sp     =  m.S' \\n\\t'^0,\n}\n\n\nfunction mymatch (g, s)\n  local r, e, pos = g:match(s)\n  if not r then\n    local line, col = re.calcline(s, pos)\n    local msg = \"Error at line \" .. line .. \" (col \" .. col .. \"): \"\n    return r, msg .. terror[e] .. \" before '\" .. s:sub(pos) .. \"'\"\n  end\n  return r\nend\n  \nprint(mymatch(g, \"one,two\"))              --\u003e 8\nprint(mymatch(g, \"one two\"))              --\u003e nil  Error at line 1 (col 4): expecting EOF before ' two'\nprint(mymatch(g, \"one,\\n two,\\nthree,4\")) --\u003e nil  Error at line 3 (col 7): expecting an identifier before '4'\n```\n\nIn this example we could think about writing rule \u003cem\u003eList\u003c/em\u003e as follows:\n```lua\nList = m.V'Id' * ((m.V'Comma' + m.T'ErrComma') * (m.V'Id' + m.T'ErrId'))^0,\n```\n\nbut when matching \u003ccode\u003em.V'Comma' + m.T'ErrComma'\u003c/code\u003e against the end of input\nwe would get a failure whose associated label would be **errComma**,\nand this would cause the failure of the *whole* repetition.\n\nBelow we rewrite the previous grammar to indicate an error when there is no\ncomma after an identifer. Before tyring to match a comma, we check if\nwe have reached the end of input:\n\n```lua\nlocal m = require'lpeglabel'\nlocal re = require'relabel'\n\nlocal terror = {\n  ErrId     =  \"expecting an identifier\",\n  ErrComma  =  \"expecting ','\",\n  fail      =  \"undefined\"\n}\n\nlocal id = m.R'az'^1\n\nlocal g = m.P{\n  'S',\n  S      =  m.V'List',\n  List   =  m.V'Id' * (#m.P(1) * m.V'Comma' * (m.V'Id' + m.T'ErrId'))^0,\n  Id     =  m.V'Sp' * id,\n  Comma  =  m.V'Sp' * ',' + m.T'ErrComma',\n  Sp     =  m.S' \\n\\t'^0,\n}\n\n\nfunction mymatch (g, s)\n  local r, e, pos = g:match(s)\n  if not r then\n    local line, col = re.calcline(s, pos)\n    local msg = \"Error at line \" .. line .. \" (col \" .. col .. \"): \"\n    return r, msg .. terror[e] .. \" before '\" .. s:sub(pos) .. \"'\"\n  end\n  return r\nend\n  \nprint(mymatch(g, \"one,two\"))               --\u003e 8\nprint(mymatch(g, \"one two\"))               --\u003e nil  Error at line 1 (col 4): expecting ',' before ' two'\nprint(mymatch(g, \"one,\\n two,\\nthree,4\"))  --\u003e nil  Error at line 3 (col 7): expecting an identifier before '4'\nprint(mymatch(g, \" 1,2\"))                  --\u003e nil  Error at line 1 (col 2): undefined before '1,2'\n```\n\n\n#### Error Recovery\n\nWe can specify a recovery rule that should\nbe matched when a label is thrown. After matching\nthe recovery rule, and possibly recording the error,\nthe parser will resume the \u003cem\u003eregular\u003c/em\u003e matching.\nThe recovery rule must have the same name (or number)\nof the label that was thrown. \n\n\nFor example, in the example below we expect to match rule *A*,\nbut when a failure occur the label `Err` is thrown and then we\nwill try to match rule *Err*:\n```lua\nlocal m = require'lpeglabel'\n\nlocal recp = m.P\"oast\"\n\nlocal g = m.P{\n  'S',\n  S    =  m.V'A' * '.',\n  A    =  m.P't' * (m.P'est' + m.T'Err'),\n  Err  =  m.P'oast'\n}\n\nprint(g:match(\"test.\"))   --\u003e 6\nprint(g:match(\"toast.\"))  --\u003e 7\nprint(g:match(\"oast.\"))   --\u003e nil  fail  oast.\nprint(g:match(\"toward.\")) --\u003e nil  fail  ward.\n```\nWhen trying to match subject 'toast.', in rule *A* the first\n't' is matched, then the matching of `m.P\"est\"` fails and label\n`Err` is thrown, with the associated inpux suffix 'oast.'. \nThe recovery rule *Err* successfully matches 'oast', so\nthe regular matching continues, and pattern `'.'` matches\nthe rest of the input.\n\nWhen matching subject 'oast.', pattern `m.P\"t\"` fails, and\nthe result of the matching is \u003cb\u003enil,  fail, 1\u003c/b\u003e.\n\nWhen matching 'toward.', label `Err` is thrown after matching 't',\nwith the associated input suffix 'oward.'. As the matching of the\nrecovery pattern fails, the result is \u003cb\u003enil, fail, 3\u003c/b\u003e.\n\nUsually, the recovery pattern is an expression that does not fail.\nIn the previous example, we could have used `(m.P(1) - m.P\".\")^0`\nas the recovery pattern.\n\nBelow we rewrite the grammar that describes a list of identifiers\nto use a recovery strategy, with the help of some auxiliary functions.\nFunction `record`, plus function `recorderror`, will help\nus to save the input position where a label was thrown,\nwhile function `sync` will give us a synchronization pattern,\nthat consumes the input while it is not possible to match a given\npattern `p`.   \n\nWhen the matching of an identifier fails, a defaul value ('NONE')\nis provided.\n\n```lua\nlocal m = require'lpeglabel'\nlocal re = require'relabel'\n\nlocal terror = {\n  ErrId     =  \"expecting an identifier\",\n  ErrComma  =  \"expecting ','\",\n  ErrList   =  \"expecting a list of identifiers\",\n  fail      =  \"undefined\"\n}\n\nlocal subject, errors\n\nfunction recorderror(pos, lab)\n  local line, col = re.calcline(subject, pos)\n  table.insert(errors, { line = line, col = col, msg = terror[lab] })\nend\n\nfunction record (lab)\n  return (m.Cp() * m.Cc(lab)) / recorderror\nend\n\nfunction sync (p)\n  return (-p * m.P(1))^0\nend\n\nfunction defaultValue ()\n  return m.Cc\"NONE\" \nend\n\nlocal id = m.R'az'^1\n\nlocal g = m.P{\n  \"S\",\n  S         =  m.V\"List\" + (m.P(1) * m.T'ErrList'),\n  List      =  m.V'Id' * (#m.P(1) * m.V'Comma' * (m.V'Id' + m.T'ErrId'))^0,\n  Id        =  m.V'Sp' * m.C(id),\n  Comma     =  m.V'Sp' * ',' + m.T'ErrComma',\n  Sp        =  m.S' \\n\\t'^0,\n  ErrId     =  record'ErrId' * sync(m.P\",\") * defaultValue(), \n  ErrComma  =  record'ErrComma' * sync(id),\n  ErrList   =  record'ErrList' * sync(m.P(-1)) * defaultValue()  \n}\n\nfunction mymatch (g, s)\n  errors = {}\n  subject = s  \n  io.write(\"Input: \", s, \"\\n\")\n  local r = { g:match(s) }\n  io.write(\"Captures (separated by ';'): \")\n  for k, v in pairs(r) do\n    io.write(v .. \"; \")\n  end\n  io.write(\"\\nSyntactic errors found: \" .. #errors)\n  if #errors \u003e 0 then\n    io.write(\"\\n\")\n    local out = {}\n    for i, err in ipairs(errors) do\n      local msg = \"Error at line \" .. err.line .. \" (col \" .. err.col .. \"): \" .. err.msg\n      table.insert(out,  msg)\n    end\n    io.write(table.concat(out, \"\\n\"))\n  end\n  print(\"\\n\")\n  return r\nend\n  \nmymatch(g, \"one,two\")                 \n--\u003e Captures (separated by ';'): one; two;\n--\u003e Syntactic errors found: 0\n\nmymatch(g, \"one two three\")           \n--\u003e Captures (separated by ';'): one; two; three;\n--\u003e Syntactic errors found: 2\n--\u003e Error at line 1 (col 4): expecting ','\n--\u003e Error at line 1 (col 8): expecting ','\n\nmymatch(g, \"1,\\n two, \\n3,\")          \n--\u003e Captures (separated by ';'): NONE; \n--\u003e Syntactic errors found: 1\n--\u003e Error at line 1 (col 2): expecting a list of identifiers\n\nmymatch(g, \"one\\n two123, \\nthree,\")\n--\u003e Captures (separated by ';'): one; two; three; NONE; \n--\u003e Syntactic errors found: 3\n--\u003e Error at line 2 (col 1): expecting ','\n--\u003e Error at line 2 (col 5): expecting ','\n--\u003e Error at line 3 (col 6): expecting an identifier\n\n```\n\n##### *relabel* syntax\n\nBelow we write a grammar for a simple programming language \nusing the syntax supported by *relabel*, where `%{}` is the throw\noperator, and the syntax `p^l` is syntatic sugar for\n`p / %{l}` (given that *l* is a valid identifier name):\n\n```lua\nlocal re = require 'relabel'\n\nlocal terror = {\n  cmdSeq        =  \"Missing ';' in CmdSeq\",\n  ifExp         =  \"Error in expresion of 'if'\",\n  ifThen        =  \"Error matching 'then' keyword\",\n  ifThenCmdSeq  =  \"Error matching CmdSeq of 'then' branch\",\n  ifElseCmdSeq  =  \"Error matching CmdSeq of 'else' branch\",\n  ifEnd         =  \"Error matching 'end' keyword of 'if'\",\n  repeatCmdSeq  =  \"Error matching CmdSeq of 'repeat'\",\n  repeatUntil   =  \"Error matching 'until' keyword\",\n  repeatExp     =  \"Error matching expression of 'until'\",\n  assignOp      =  \"Error matching ':='\",\n  assignExp     =  \"Error matching expression of assignment\",\n  readName      =  \"Error matching 'NAME' after 'read'\",\n  writeExp      =  \"Error matching expression after 'write'\",\n  simpleExp     =  \"Error matching 'SimpleExp'\",\n  term          =  \"Error matching 'Term'\",\n  factor        =  \"Error matching 'Factor'\",\n  openParExp    =  \"Error matching expression after '('\",\n  closePar      =  \"Error matching ')'\",\n  eof           =  \"Error, expecting EOF\",\n  undefined     =  \"Undefined Error\"\n}\n\ng = re.compile([[\n  Tiny       \u003c- CmdSeq (!. / %{eof})\n  CmdSeq     \u003c- (Cmd SEMICOLON^cmdSeq) (Cmd SEMICOLON^cmdSeq)*\n  Cmd        \u003c- IfCmd / RepeatCmd / ReadCmd / WriteCmd  / AssignCmd \n  IfCmd      \u003c- IF  Exp^ifExp  THEN^ifThen  CmdSeq^ifThenCmdSeq  (ELSE CmdSeq^ifElseCmdSeq / '')  END^ifEnd\n  RepeatCmd  \u003c- REPEAT  CmdSeq^repeatCmdSeq  UNTIL^repeatUntil  Exp^repeatExp\n  AssignCmd  \u003c- NAME  ASSIGNMENT^assignOp  Exp^assignExp\n  ReadCmd    \u003c- READ  NAME^readName\n  WriteCmd   \u003c- WRITE  Exp^writeExp\n  Exp        \u003c- SimpleExp  ((LESS / EQUAL)  SimpleExp^simpleExp / '')\n  SimpleExp  \u003c- Term  ((ADD / SUB)  Term^term)*\n  Term       \u003c- Factor ((MUL / DIV)  Factor^factor)*\n  Factor     \u003c- OPENPAR  Exp^openParExp  CLOSEPAR^closePar  / NUMBER  / NAME\n  ADD        \u003c- Sp '+'\n  ASSIGNMENT \u003c- Sp ':='\n  CLOSEPAR   \u003c- Sp ')'\n  DIV        \u003c- Sp '/'\n  IF         \u003c- Sp 'if'\n  ELSE       \u003c- Sp 'else'\n  END        \u003c- Sp 'end'\n  EQUAL      \u003c- Sp '='\n  LESS       \u003c- Sp '\u003c'\n  MUL        \u003c- Sp '*'\n  NAME       \u003c- !RESERVED Sp [a-z]+\n  NUMBER     \u003c- Sp [0-9]+\n  OPENPAR    \u003c- Sp '('\n  READ       \u003c- Sp 'read'\n  REPEAT     \u003c- Sp 'repeat'\n  SEMICOLON  \u003c- Sp ';'\n  SUB        \u003c- Sp '-'\n  THEN       \u003c- Sp 'then'\n  UNTIL      \u003c- Sp 'until'\n  WRITE      \u003c- Sp 'write'\n  RESERVED   \u003c- (IF / ELSE / END / READ / REPEAT / THEN / UNTIL / WRITE) ![a-z]+\n  Sp         \u003c- (%s / %nl)*  \n]], terror)\n\n\nlocal function mymatch(g, s)\n  local r, e, pos = g:match(s)\n  if not r then\n    local line, col = re.calcline(s, pos)\n    local msg = \"Error at line \" .. line .. \" (col \" .. col .. \"): \"\n    return r, msg .. terror[e]\n  end \n  return r\nend\n\nlocal s = [[\nn := 5;\nf := 1;\nrepeat\n  f := f + n;\n  n := n - 1\nuntil (n \u003c 1);\nwrite f;]]\nprint(mymatch(g, s))            --\u003e nil  Error at line 6 (col 1): Missing ';' in CmdSeq\n\nprint(mymatch(g, \"a : 2\"))      --\u003e nil  Error at line 1 (col 2): Error matching ':='\nprint(mymatch(g, \"a := 2; 6\"))  --\u003e nil  Error at line 1 (col 8): Error, expecting EOF\n```\n\n### Caveats\n\nDoes not use the number **1** to specify a recovery rule,\nsince that the entry with index 1 in the grammar table defines\nits initial rule.\n\nIn case your grammar has many regular and recovery rules,\nyou may get an error message such as grammar: \u003cem\u003ehas too many rules\u003c/em\u003e.\nIn this case, we need to change *MAXRULES* in `lpltypes.h`.\n  \n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsqmedeiros%2Flpeglabel","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsqmedeiros%2Flpeglabel","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsqmedeiros%2Flpeglabel/lists"}