diff options
| author | Sergio Medeiros <sqmedeiros@gmail.com> | 2015-03-23 15:09:08 -0300 |
|---|---|---|
| committer | Sergio Medeiros <sqmedeiros@gmail.com> | 2015-03-23 15:09:08 -0300 |
| commit | f124b2d4449a13ac21af9581a44b4455d89eaddb (patch) | |
| tree | e0486555ac811c5f712927f110bb7bcda8569adf | |
| parent | 0e93d536ba2d312502737cce2ab0cc21393c4842 (diff) | |
| download | lpeglabel-f124b2d4449a13ac21af9581a44b4455d89eaddb.tar.gz lpeglabel-f124b2d4449a13ac21af9581a44b4455d89eaddb.tar.bz2 lpeglabel-f124b2d4449a13ac21af9581a44b4455d89eaddb.zip | |
Renaming "re.lua" to "relabel.lua".
Adding examples, README and lpeglabel.html
| -rw-r--r-- | README | 5 | ||||
| -rw-r--r-- | examples/listId1.lua | 27 | ||||
| -rw-r--r-- | examples/listId2.lua | 32 | ||||
| -rw-r--r-- | examples/listIdCatch.lua | 25 | ||||
| -rw-r--r-- | examples/listIdCatchRe.lua | 34 | ||||
| -rw-r--r-- | examples/listIdRe1.lua | 27 | ||||
| -rw-r--r-- | examples/listIdRe2.lua | 35 | ||||
| -rw-r--r-- | examples/tiny.lua | 163 | ||||
| -rw-r--r-- | lpeglabel-logo.gif | bin | 0 -> 20757 bytes | |||
| -rw-r--r-- | lpeglabel.html | 574 | ||||
| -rw-r--r-- | relabel.lua (renamed from re.lua) | 0 |
11 files changed, 922 insertions, 0 deletions
| @@ -0,0 +1,5 @@ | |||
| 1 | LPegLabel is an extension of the LPeg library that provides an implementation of Parsing Expression Grammars (PEGs) with labeled failures. | ||
| 2 | |||
| 3 | Labels can be used to signal different kinds of erros and to specify which alternative in a labeled ordered choice should handle a given label. | ||
| 4 | |||
| 5 | Labels can also be combined with the standard patterns of LPeg. | ||
diff --git a/examples/listId1.lua b/examples/listId1.lua new file mode 100644 index 0000000..e075bd1 --- /dev/null +++ b/examples/listId1.lua | |||
| @@ -0,0 +1,27 @@ | |||
| 1 | local m = require'lpeglabel' | ||
| 2 | |||
| 3 | local g = m.P{ | ||
| 4 | "S", | ||
| 5 | S = m.V"Id" * m.V"List", | ||
| 6 | List = -m.P(1) + ("," + m.T(2)) * m.V"Id" * m.V"List", | ||
| 7 | Id = m.R'az'^1 + m.T(1), | ||
| 8 | } | ||
| 9 | |||
| 10 | function mymatch (g, s) | ||
| 11 | local r, e = g:match(s) | ||
| 12 | if not r then | ||
| 13 | if e == 1 then | ||
| 14 | return r, "Error: expecting an identifier" | ||
| 15 | elseif e == 2 then | ||
| 16 | return r, "Error: expecting ','" | ||
| 17 | else | ||
| 18 | return r, "Error" | ||
| 19 | end | ||
| 20 | end | ||
| 21 | return r | ||
| 22 | end | ||
| 23 | |||
| 24 | print(mymatch(g, "a,b")) | ||
| 25 | print(mymatch(g, "a b")) | ||
| 26 | print(mymatch(g, ", b")) | ||
| 27 | |||
diff --git a/examples/listId2.lua b/examples/listId2.lua new file mode 100644 index 0000000..4943368 --- /dev/null +++ b/examples/listId2.lua | |||
| @@ -0,0 +1,32 @@ | |||
| 1 | local m = require'lpeglabel' | ||
| 2 | |||
| 3 | local errUndef = 0 | ||
| 4 | local errId = 1 | ||
| 5 | local errComma = 2 | ||
| 6 | |||
| 7 | local terror = { | ||
| 8 | [errUndef] = "Error", | ||
| 9 | [errId] = "Error: expecting an identifier", | ||
| 10 | [errComma] = "Error: expecting ','", | ||
| 11 | } | ||
| 12 | |||
| 13 | local g = m.P{ | ||
| 14 | "S", | ||
| 15 | S = m.V"Id" * m.V"List", | ||
| 16 | List = -m.P(1) + ("," + m.T(errComma)) * m.V"Id" * m.V"List", | ||
| 17 | Id = m.R'az'^1 + m.T(errId), | ||
| 18 | } | ||
| 19 | |||
| 20 | function mymatch (g, s) | ||
| 21 | local r, e = g:match(s) | ||
| 22 | if not r then | ||
| 23 | return r, terror[e] | ||
| 24 | end | ||
| 25 | return r | ||
| 26 | end | ||
| 27 | |||
| 28 | print(mymatch(g, "a,b")) | ||
| 29 | print(mymatch(g, "a b")) | ||
| 30 | print(mymatch(g, ", b")) | ||
| 31 | |||
| 32 | |||
diff --git a/examples/listIdCatch.lua b/examples/listIdCatch.lua new file mode 100644 index 0000000..38ad2e5 --- /dev/null +++ b/examples/listIdCatch.lua | |||
| @@ -0,0 +1,25 @@ | |||
| 1 | local m = require'lpeglabel' | ||
| 2 | |||
| 3 | local errUndef, errId, errComma = 0, 1, 2 | ||
| 4 | |||
| 5 | local terror = { | ||
| 6 | [errUndef] = "Error", | ||
| 7 | [errId] = "Error: expecting an identifier", | ||
| 8 | [errComma] = "Error: expecting ','", | ||
| 9 | } | ||
| 10 | |||
| 11 | g = m.P{ | ||
| 12 | "S", | ||
| 13 | S = m.Lc(m.Lc(m.V"Id" * m.V"List", m.V"ErrId", errId), | ||
| 14 | m.V"ErrComma", errComma), | ||
| 15 | List = -m.P(1) + m.V"Comma" * m.V"Id" * m.V"List", | ||
| 16 | Id = m.R'az'^1 + m.T(errId), | ||
| 17 | Comma = "," + m.T(errComma), | ||
| 18 | ErrId = m.Cc(errId) / terror, | ||
| 19 | ErrComma = m.Cc(errComma) / terror | ||
| 20 | } | ||
| 21 | |||
| 22 | print(g:match("a,b")) | ||
| 23 | print(g:match("a b")) | ||
| 24 | print(g:match(",b")) | ||
| 25 | |||
diff --git a/examples/listIdCatchRe.lua b/examples/listIdCatchRe.lua new file mode 100644 index 0000000..5d38fec --- /dev/null +++ b/examples/listIdCatchRe.lua | |||
| @@ -0,0 +1,34 @@ | |||
| 1 | local re = require're' | ||
| 2 | |||
| 3 | local terror = {} | ||
| 4 | |||
| 5 | local function newError(l, msg) | ||
| 6 | table.insert(terror, { l = l, msg = msg } ) | ||
| 7 | end | ||
| 8 | |||
| 9 | newError("errId", "Error: expecting an identifier") | ||
| 10 | newError("errComma", "Error: expecting ','") | ||
| 11 | |||
| 12 | local labelCode = {} | ||
| 13 | local labelMsg = {} | ||
| 14 | for k, v in ipairs(terror) do | ||
| 15 | labelCode[v.l] = k | ||
| 16 | labelMsg[v.l] = v.msg | ||
| 17 | end | ||
| 18 | |||
| 19 | re.setlabels(labelCode) | ||
| 20 | |||
| 21 | local p = re.compile([[ | ||
| 22 | S <- Id List /{errId} ErrId /{errComma} ErrComma | ||
| 23 | List <- !. / Comma Id List | ||
| 24 | Id <- [a-z]+ / %{errId} | ||
| 25 | Comma <- ',' / %{errComma} | ||
| 26 | ErrId <- '' -> errId | ||
| 27 | ErrComma <- '' -> errComma | ||
| 28 | ]], labelMsg) | ||
| 29 | |||
| 30 | print(p:match("a,b")) | ||
| 31 | print(p:match("a b")) | ||
| 32 | print(p:match(",b")) | ||
| 33 | |||
| 34 | |||
diff --git a/examples/listIdRe1.lua b/examples/listIdRe1.lua new file mode 100644 index 0000000..c75bb1d --- /dev/null +++ b/examples/listIdRe1.lua | |||
| @@ -0,0 +1,27 @@ | |||
| 1 | local re = require 're' | ||
| 2 | |||
| 3 | local g = re.compile[[ | ||
| 4 | S <- Id List | ||
| 5 | List <- !. / (',' / %{2}) Id List | ||
| 6 | Id <- [a-z] / %{1} | ||
| 7 | ]] | ||
| 8 | |||
| 9 | function mymatch (g, s) | ||
| 10 | local r, e = g:match(s) | ||
| 11 | if not r then | ||
| 12 | if e == 1 then | ||
| 13 | return r, "Error: expecting an identifier" | ||
| 14 | elseif e == 2 then | ||
| 15 | return r, "Error: expecting ','" | ||
| 16 | else | ||
| 17 | return r, "Error" | ||
| 18 | end | ||
| 19 | end | ||
| 20 | return r | ||
| 21 | end | ||
| 22 | |||
| 23 | print(mymatch(g, "a,b")) | ||
| 24 | print(mymatch(g, "a b")) | ||
| 25 | print(mymatch(g, ", b")) | ||
| 26 | |||
| 27 | |||
diff --git a/examples/listIdRe2.lua b/examples/listIdRe2.lua new file mode 100644 index 0000000..67c42f1 --- /dev/null +++ b/examples/listIdRe2.lua | |||
| @@ -0,0 +1,35 @@ | |||
| 1 | local re = require 're' | ||
| 2 | |||
| 3 | local errUndef, errId, errComma = 0, 1, 2 | ||
| 4 | |||
| 5 | local terror = { | ||
| 6 | [errUndef] = "Error", | ||
| 7 | [errId] = "Error: expecting an identifier", | ||
| 8 | [errComma] = "Error: expecting ','", | ||
| 9 | } | ||
| 10 | |||
| 11 | local tlabels = { ["errUndef"] = errUndef, | ||
| 12 | ["errId"] = errId, | ||
| 13 | ["errComma"] = errComma } | ||
| 14 | |||
| 15 | re.setlabels(tlabels) | ||
| 16 | |||
| 17 | local g = re.compile[[ | ||
| 18 | S <- Id List | ||
| 19 | List <- !. / (',' / %{errComma}) Id List | ||
| 20 | Id <- [a-z] / %{errId} | ||
| 21 | ]] | ||
| 22 | |||
| 23 | function mymatch (g, s) | ||
| 24 | local r, e = g:match(s) | ||
| 25 | if not r then | ||
| 26 | return r, terror[e] | ||
| 27 | end | ||
| 28 | return r | ||
| 29 | end | ||
| 30 | |||
| 31 | print(mymatch(g, "a,b")) | ||
| 32 | print(mymatch(g, "a b")) | ||
| 33 | print(mymatch(g, ", b")) | ||
| 34 | |||
| 35 | |||
diff --git a/examples/tiny.lua b/examples/tiny.lua new file mode 100644 index 0000000..aa9dbea --- /dev/null +++ b/examples/tiny.lua | |||
| @@ -0,0 +1,163 @@ | |||
| 1 | local re = require 're' | ||
| 2 | |||
| 3 | local terror = {} | ||
| 4 | |||
| 5 | local function newError(l, msg) | ||
| 6 | table.insert(terror, { l = l, msg = msg} ) | ||
| 7 | end | ||
| 8 | |||
| 9 | newError("errSemi", "Error: missing ';'") | ||
| 10 | newError("errExpIf", "Error: expected expression after 'if'") | ||
| 11 | newError("errThen", "Error: expected 'then' keyword") | ||
| 12 | newError("errCmdSeq1", "Error: expected at least a command after 'then'") | ||
| 13 | newError("errCmdSeq2", "Error: expected at least a command after 'else'") | ||
| 14 | newError("errEnd", "Error: expected 'end' keyword") | ||
| 15 | newError("errCmdSeqRep", "Error: expected at least a command after 'repeat'") | ||
| 16 | newError("errUntil", "Error: expected 'until' keyword") | ||
| 17 | newError("errExpRep", "Error: expected expression after 'until'") | ||
| 18 | newError("errAssignOp", "Error: expected ':=' in assigment") | ||
| 19 | newError("errExpAssign", "Error: expected expression after ':='") | ||
| 20 | newError("errReadName", "Error: expected an identifier after 'read'") | ||
| 21 | newError("errWriteExp", "Error: expected expression after 'write'") | ||
| 22 | newError("errSimpExp", "Error: expected '(', ID, or number after '<' or '='") | ||
| 23 | newError("errTerm", "Error: expected '(', ID, or number after '+' or '-'") | ||
| 24 | newError("errFactor", "Error: expected '(', ID, or number after '*' or '/'") | ||
| 25 | newError("errExpFac", "Error: expected expression after '('") | ||
| 26 | newError("errClosePar", "Error: expected ')' after expression") | ||
| 27 | |||
| 28 | local line | ||
| 29 | |||
| 30 | local function incLine() | ||
| 31 | line = line + 1 | ||
| 32 | return true | ||
| 33 | end | ||
| 34 | |||
| 35 | local function countLine(s, i) | ||
| 36 | line = 1 | ||
| 37 | local p = re.compile([[ | ||
| 38 | S <- (%nl -> incLine / .)* | ||
| 39 | ]], { incLine = incLine}) | ||
| 40 | p:match(s:sub(1, i)) | ||
| 41 | return true | ||
| 42 | end | ||
| 43 | |||
| 44 | local labelCode = {} | ||
| 45 | for k, v in ipairs(terror) do | ||
| 46 | labelCode[v.l] = k | ||
| 47 | end | ||
| 48 | |||
| 49 | re.setlabels(labelCode) | ||
| 50 | |||
| 51 | local g = re.compile([[ | ||
| 52 | Tiny <- CmdSeq | ||
| 53 | CmdSeq <- (Cmd (SEMICOLON / ErrSemi)) (Cmd (SEMICOLON / ErrSemi))* | ||
| 54 | Cmd <- IfCmd / RepeatCmd / ReadCmd / WriteCmd / AssignCmd | ||
| 55 | IfCmd <- IF (Exp / ErrExpIf) (THEN / ErrThen) (CmdSeq / ErrCmdSeq1) (ELSE (CmdSeq / ErrCmdSeq2) / '') (END / ErrEnd) | ||
| 56 | RepeatCmd <- REPEAT (CmdSeq / ErrCmdSeqRep) (UNTIL / ErrUntil) (Exp / ErrExpRep) | ||
| 57 | AssignCmd <- NAME (ASSIGNMENT / ErrAssignOp) (Exp / ErrExpAssign) | ||
| 58 | ReadCmd <- READ (NAME / ErrReadName) | ||
| 59 | WriteCmd <- WRITE (Exp / ErrWriteExp) | ||
| 60 | Exp <- SimpleExp ((LESS / EQUAL) (SimpleExp / ErrSimpExp) / '') | ||
| 61 | SimpleExp <- Term ((ADD / SUB) (Term / ErrTerm))* | ||
| 62 | Term <- Factor ((MUL / DIV) (Factor / ErrFactor))* | ||
| 63 | Factor <- OPENPAR (Exp / ErrExpFac) (CLOSEPAR / ErrClosePar) / NUMBER / NAME | ||
| 64 | ErrSemi <- ErrCount %{errSemi} | ||
| 65 | ErrExpIf <- ErrCount %{errExpIf} | ||
| 66 | ErrThen <- ErrCount %{errThen} | ||
| 67 | ErrCmdSeq1 <- ErrCount %{errCmdSeq1} | ||
| 68 | ErrCmdSeq2 <- ErrCount %{errCmdSeq2} | ||
| 69 | ErrEnd <- ErrCount %{errEnd} | ||
| 70 | ErrCmdSeqRep <- ErrCount %{errCmdSeqRep} | ||
| 71 | ErrUntil <- ErrCount %{errUntil} | ||
| 72 | ErrExpRep <- ErrCount %{errExpRep} | ||
| 73 | ErrAssignOp <- ErrCount %{errAssignOp} | ||
| 74 | ErrExpAssign <- ErrCount %{errExpAssign} | ||
| 75 | ErrReadName <- ErrCount %{errReadName} | ||
| 76 | ErrWriteExp <- ErrCount %{errWriteExp} | ||
| 77 | ErrSimpExp <- ErrCount %{errSimpExp} | ||
| 78 | ErrTerm <- ErrCount %{errTerm} | ||
| 79 | ErrFactor <- ErrCount %{errFactor} | ||
| 80 | ErrExpFac <- ErrCount %{errExpFac} | ||
| 81 | ErrClosePar <- ErrCount %{errClosePar} | ||
| 82 | ErrCount <- '' => countLine | ||
| 83 | ADD <- Sp '+' | ||
| 84 | ASSIGNMENT <- Sp ':=' | ||
| 85 | CLOSEPAR <- Sp ')' | ||
| 86 | DIV <- Sp '/' | ||
| 87 | IF <- Sp 'if' | ||
| 88 | ELSE <- Sp 'else' | ||
| 89 | END <- Sp 'end' | ||
| 90 | EQUAL <- Sp '=' | ||
| 91 | LESS <- Sp '<' | ||
| 92 | MUL <- Sp '*' | ||
| 93 | NAME <- Sp !RESERVED [a-z]+ | ||
| 94 | NUMBER <- Sp [0-9]+ | ||
| 95 | OPENPAR <- Sp '(' | ||
| 96 | READ <- Sp 'read' | ||
| 97 | REPEAT <- Sp 'repeat' | ||
| 98 | SEMICOLON <- Sp ';' | ||
| 99 | SUB <- Sp '-' | ||
| 100 | THEN <- Sp 'then' | ||
| 101 | UNTIL <- Sp 'until' | ||
| 102 | WRITE <- Sp 'write' | ||
| 103 | RESERVED <- (IF / ELSE / END / READ / REPEAT / THEN / UNTIL / WRITE) ![a-z]+ | ||
| 104 | Sp <- %s* | ||
| 105 | ]], { countLine = countLine }) | ||
| 106 | |||
| 107 | |||
| 108 | local function printError(n, e) | ||
| 109 | assert(n == nil) | ||
| 110 | print("Line " .. line .. ": " .. terror[e].msg) | ||
| 111 | end | ||
| 112 | |||
| 113 | local s = [[ | ||
| 114 | n := 5; | ||
| 115 | f := 1; | ||
| 116 | repeat | ||
| 117 | f := f + n; | ||
| 118 | n := n - 1 | ||
| 119 | until (n < 1); | ||
| 120 | write f;]] | ||
| 121 | printError(g:match(s)) | ||
| 122 | |||
| 123 | s = [[ | ||
| 124 | n := 5; | ||
| 125 | f := 1; | ||
| 126 | repeat | ||
| 127 | f := f + n; | ||
| 128 | n := n - 1; | ||
| 129 | until (n < 1); | ||
| 130 | read ;]] | ||
| 131 | printError(g:match(s)) | ||
| 132 | |||
| 133 | s = [[ | ||
| 134 | if a < 1 then | ||
| 135 | b := 2; | ||
| 136 | else | ||
| 137 | b := 3;]] | ||
| 138 | printError(g:match(s)) | ||
| 139 | |||
| 140 | s = [[ | ||
| 141 | n := 5; | ||
| 142 | f := 1; | ||
| 143 | repeat | ||
| 144 | f := f + n; | ||
| 145 | n := n - 1; | ||
| 146 | untill (n < 1); | ||
| 147 | ]] | ||
| 148 | printError(g:match(s)) | ||
| 149 | |||
| 150 | s = [[ | ||
| 151 | n := 5; | ||
| 152 | f := 1; | ||
| 153 | repeat | ||
| 154 | f := f + n; | ||
| 155 | n := n - 1; | ||
| 156 | 3 (n < 1); | ||
| 157 | ]] | ||
| 158 | printError(g:match(s)) | ||
| 159 | |||
| 160 | printError(g:match("a : 2")) | ||
| 161 | printError(g:match("a := (2")) | ||
| 162 | |||
| 163 | |||
diff --git a/lpeglabel-logo.gif b/lpeglabel-logo.gif new file mode 100644 index 0000000..b82e19f --- /dev/null +++ b/lpeglabel-logo.gif | |||
| Binary files differ | |||
diff --git a/lpeglabel.html b/lpeglabel.html new file mode 100644 index 0000000..b38e900 --- /dev/null +++ b/lpeglabel.html | |||
| @@ -0,0 +1,574 @@ | |||
| 1 | <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" | ||
| 2 | "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> | ||
| 3 | <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> | ||
| 4 | <head> | ||
| 5 | <title>LPegLabLabel - Parsing Expression Grammars For Lua</title> | ||
| 6 | <link rel="stylesheet" | ||
| 7 | href="http://www.inf.puc-rio.br/~roberto/lpeg/doc.css" | ||
| 8 | type="text/css"/> | ||
| 9 | <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/> | ||
| 10 | </head> | ||
| 11 | <body> | ||
| 12 | |||
| 13 | <!-- $Id: lpeg.html,v 1.71 2013/04/11 19:17:41 roberto Exp $ --> | ||
| 14 | |||
| 15 | <div id="container"> | ||
| 16 | |||
| 17 | <div id="product"> | ||
| 18 | <div id="product_logo"> | ||
| 19 | <a href="https://github.com/sqmedeiros/lpeglabel"> | ||
| 20 | <img alt="LPeg logo" src="lpeg-128.gif"/></a> | ||
| 21 | |||
| 22 | </div> | ||
| 23 | <div id="product_name"><big><strong>LPegLabel</strong></big></div> | ||
| 24 | <div id="product_description"> | ||
| 25 | Parsing Expression Grammars For Lua with Labels, version 0.1 | ||
| 26 | </div> | ||
| 27 | </div> <!-- id="product" --> | ||
| 28 | |||
| 29 | <div id="main"> | ||
| 30 | |||
| 31 | <div id="navigation"> | ||
| 32 | <h1>LPeg</h1> | ||
| 33 | |||
| 34 | <ul> | ||
| 35 | <li><strong>Home</strong> | ||
| 36 | <ul> | ||
| 37 | <li><a href="#intro">Introduction</a></li> | ||
| 38 | <li><a href="#func">Functions</a></li> | ||
| 39 | <li><a href="#ex">Some Examples</a></li> | ||
| 40 | <li><a href="#download">Download</a></li> | ||
| 41 | <li><a href="#license">License</a></li> | ||
| 42 | </ul> | ||
| 43 | </li> | ||
| 44 | </ul> | ||
| 45 | </div> <!-- id="navigation" --> | ||
| 46 | |||
| 47 | <div id="content"> | ||
| 48 | |||
| 49 | |||
| 50 | <h2><a name="intro">Introduction</a></h2> | ||
| 51 | |||
| 52 | <p> | ||
| 53 | <em>LPegLabel</em> is an extension of the | ||
| 54 | <a href="http://www.inf.puc-rio.br/~roberto/lpeg/">LPeg</a> | ||
| 55 | library that provides an implementation of Parsing Expression | ||
| 56 | Grammars (PEGs) with labeled failures. Labels can be | ||
| 57 | used to signal different kinds of erros and to | ||
| 58 | specify which alternative in a labeled ordered choice | ||
| 59 | should handle a given label. Labels can also be combined | ||
| 60 | with the standard patterns of LPeg. | ||
| 61 | </p> | ||
| 62 | |||
| 63 | <p> | ||
| 64 | This document describes the new functions available | ||
| 65 | in LpegLabel and presents some examples of usage. | ||
| 66 | For a more detailed and formal discussion about | ||
| 67 | PEGs with labels please see | ||
| 68 | <a href="http://www.inf.puc-rio.br/~roberto/docs/sblp2013-1.pdf"> | ||
| 69 | Exception Handling for Error Reporting in Parsing Expression Grammars | ||
| 70 | </a> | ||
| 71 | and | ||
| 72 | <a href="http://arxiv.org/abs/1405.6646">Error Reporting in Parsing Expression Grammars</a>. | ||
| 73 | </p> | ||
| 74 | |||
| 75 | |||
| 76 | <p> | ||
| 77 | Below there is a brief summary of the new functions | ||
| 78 | provided by LpegLabel: | ||
| 79 | </p> | ||
| 80 | <table border="1"> | ||
| 81 | <tbody><tr><td><b>Function</b></td><td><b>Description</b></td></tr> | ||
| 82 | <tr><td><a href="#f-t"><code>lpeglabel.T (l<sub>1</sub>, ..., l<sub>n</sub>)</code></a></td> | ||
| 83 | <td>Throws labels <code>l<sub>1</sub>, ..., l<sub>n</sub></code></td></tr> | ||
| 84 | <tr><td><a href="#f-lc"><code>lpeglabel.Lc (p1, p2, l<sub>1</sub>, ..., l<sub>n</sub>)</code></a></td> | ||
| 85 | <td>Matches <code>p1</code> and tries to match <code>p2</code> | ||
| 86 | if the matching of <code>p1</code> gives one of l<sub>1</sub>, ..., l<sub>n</sub> | ||
| 87 | </td></tr> | ||
| 88 | <tr><td><a href="#re-t"><code>%{l<sub>1</sub>, ..., l<sub>n</sub>}</code></a></td> | ||
| 89 | <td>Syntax of <em>re</em> module. Equivalent to <code>lpeg.T(l<sub>1</sub>, ..., l<sub>n</sub>)</code> | ||
| 90 | </td></tr> | ||
| 91 | <tr><td><a href="#re-lc"><code>p1 /{l<sub>1</sub>, ..., l<sub>n</sub>} p2</code></a></td> | ||
| 92 | <td>Syntax of <em>re</em> module. Equivalent to <code>lpeg.Lc(p1, p2, l<sub>1</sub>, ..., l<sub>n</sub>)</code> | ||
| 93 | </td></tr> | ||
| 94 | <tr><td><a href="#re-setl"><code>re.setlabels (tlabel)</code></a></td> | ||
| 95 | <td>Allows to specicify a table with labels. They keys of | ||
| 96 | <code>tlabel</code> must be integers, and the associated values usually are strings. | ||
| 97 | </td></tr> | ||
| 98 | </tbody></table> | ||
| 99 | |||
| 100 | <p> | ||
| 101 | In case of an unsucessful matching, the <em>match</em> function now returns | ||
| 102 | <code>nil</code> plus a list of labels. These labels may be used to build | ||
| 103 | a good error message. | ||
| 104 | </p> | ||
| 105 | |||
| 106 | <h2><a name="func">Functions</a></h2> | ||
| 107 | |||
| 108 | |||
| 109 | <h3><a name="f-t"></a><code>lpeglabel.T(l<sub>1</sub>, ..., l<sub>n</sub>)</code></h3> | ||
| 110 | <p> | ||
| 111 | Returns a pattern that throws the list of labels <code>l<sub>1</sub>, ..., l<sub>n</sub></code>. | ||
| 112 | A label must be an integer between <code>0</code> and <code>31</code>. | ||
| 113 | |||
| 114 | The label <code>0</code> is equivalent to the regular failure of PEGs. | ||
| 115 | |||
| 116 | |||
| 117 | <h3><a name="f-lc"></a><code>lpeglabel.Lc(p1, p2, l<sub>1</sub>, ..., l<sub>n</sub>)</code></h3> | ||
| 118 | <p> | ||
| 119 | Returns a pattern equivalent to a <em>labeled ordered choice</em>. | ||
| 120 | If the matching of <code>p1</code> gives one of the labels <code>l<sub>1</sub>, ..., l<sub>n</sub></code>, | ||
| 121 | then the matching of <code>p2</code> is tried from the same position. Otherwise, | ||
| 122 | the result of the matching of <code>p1</code> is the pattern's result. | ||
| 123 | </p> | ||
| 124 | |||
| 125 | <p> | ||
| 126 | The labeled ordered choice <code>lpeg.Lc(p1, p2, 0)</code> is equivalent to the | ||
| 127 | regular ordered choice <code>p1 / p2</code>. | ||
| 128 | </p> | ||
| 129 | |||
| 130 | <p> | ||
| 131 | Although PEG's ordered choice is associative, the labeled ordered choice is not. | ||
| 132 | When using this function, the user should take care to build a left-associative | ||
| 133 | labeled ordered choice pattern. | ||
| 134 | </p> | ||
| 135 | |||
| 136 | |||
| 137 | <h3><a name="re-t"></a><code>%{l<sub>1</sub>, ..., l<sub>n</sub>}</code></h3> | ||
| 138 | <p> | ||
| 139 | Syntax of <em>re</em> module. Equivalent to <code>lpeg.T(l<sub>1</sub>, ..., l<sub>n</sub>)</code>. | ||
| 140 | </p> | ||
| 141 | |||
| 142 | |||
| 143 | <h3><a name="re-lc"></a><code>p1 /{l<sub>1</sub>, ..., l<sub>n</sub>} p2</code></h3> | ||
| 144 | <p> | ||
| 145 | Syntax of <em>re</em> module. Equivalent to <code>lpeg.Lc(p1, p2, l<sub>1</sub>, ..., l<sub>n</sub>)</code>. | ||
| 146 | </p> | ||
| 147 | |||
| 148 | <p> | ||
| 149 | The <code>/{}</code> operator is left-associative. | ||
| 150 | </p> | ||
| 151 | |||
| 152 | <p> | ||
| 153 | A grammar can use both choice operators (<code>/</code> and <code>/{}</code>), | ||
| 154 | but a single choice can not mix them. That is, the parser | ||
| 155 | of <code>re</code> module will not recognize a pattern as | ||
| 156 | <code>p1 / p2 /{l<sub>1</sub>} p3</code>. | ||
| 157 | </p> | ||
| 158 | |||
| 159 | |||
| 160 | |||
| 161 | <h2><a name="ex">Some Examples</a></h2> | ||
| 162 | |||
| 163 | <h3>Throwing a label</h3> | ||
| 164 | <p> | ||
| 165 | The following example defines a grammar that matches | ||
| 166 | a list of identifiers separated by commas. A label | ||
| 167 | is thrown when there is an error matching an identifier | ||
| 168 | or a comma: | ||
| 169 | </p> | ||
| 170 | <pre class="example"> | ||
| 171 | local m = require'lpeglabel' | ||
| 172 | |||
| 173 | local g = m.P{ | ||
| 174 | "S", | ||
| 175 | S = m.V"Id" * m.V"List", | ||
| 176 | List = -m.P(1) + ("," + m.T(2)) * m.V"Id" * m.V"List", | ||
| 177 | Id = m.R'az'^1 + m.T(1), | ||
| 178 | } | ||
| 179 | |||
| 180 | function mymatch (g, s) | ||
| 181 | local r, e = g:match(s) | ||
| 182 | if not r then | ||
| 183 | if e == 1 then | ||
| 184 | return r, "Error: expecting an identifier" | ||
| 185 | elseif e == 2 then | ||
| 186 | return r, "Error: expecting ','" | ||
| 187 | else | ||
| 188 | return r, "Error" | ||
| 189 | end | ||
| 190 | end | ||
| 191 | return r | ||
| 192 | end | ||
| 193 | |||
| 194 | print(mymatch(g, "a,b")) | ||
| 195 | print(mymatch(g, "a b")) | ||
| 196 | print(mymatch(g, ", b")) | ||
| 197 | </pre> | ||
| 198 | <p> | ||
| 199 | In this example we could think about writing rule <em>List</em> as follows: | ||
| 200 | <pre class="example"> | ||
| 201 | List = m.P(("," + m.T(2)) * m.V"Id")^0 | ||
| 202 | </pre> | ||
| 203 | but this would give us an expression that when matching | ||
| 204 | the end of input would result in a failure with a label | ||
| 205 | different from 0, that is equivalent to the regular failure, | ||
| 206 | and the result of the repetition would be this label. | ||
| 207 | </p> | ||
| 208 | |||
| 209 | <p> | ||
| 210 | In the previous example we could have also created a table | ||
| 211 | with the error messages to improve the readbility of the PEG. | ||
| 212 | Below we rewrite the grammar following this approach: | ||
| 213 | </p> | ||
| 214 | |||
| 215 | <pre class="example"> | ||
| 216 | local m = require'lpeglabel' | ||
| 217 | |||
| 218 | local errUndef = 0 | ||
| 219 | local errId = 1 | ||
| 220 | local errComma = 2 | ||
| 221 | |||
| 222 | local terror = { | ||
| 223 | [errUndef] = "Error", | ||
| 224 | [errId] = "Error: expecting an identifier", | ||
| 225 | [errComma] = "Error: expecting ','", | ||
| 226 | } | ||
| 227 | |||
| 228 | local g = m.P{ | ||
| 229 | "S", | ||
| 230 | S = m.V"Id" * m.V"List", | ||
| 231 | List = -m.P(1) + ("," + m.T(errComma)) * m.V"Id" * m.V"List", | ||
| 232 | Id = m.R'az'^1 + m.T(errId), | ||
| 233 | } | ||
| 234 | |||
| 235 | function mymatch (g, s) | ||
| 236 | local r, e = g:match(s) | ||
| 237 | if not r then | ||
| 238 | return r, terror[e] | ||
| 239 | end | ||
| 240 | return r | ||
| 241 | end | ||
| 242 | |||
| 243 | print(mymatch(g, "a,b")) | ||
| 244 | print(mymatch(g, "a b")) | ||
| 245 | print(mymatch(g, ", b")) | ||
| 246 | </pre> | ||
| 247 | |||
| 248 | <h3>Throwing a label using the <em>re</em> module</h3> | ||
| 249 | |||
| 250 | <p> | ||
| 251 | We can also rewrite the previous example using the <em>re</em> module | ||
| 252 | as follows: | ||
| 253 | </p> | ||
| 254 | <pre class="example"> | ||
| 255 | local re = require 're' | ||
| 256 | |||
| 257 | local g = re.compile[[ | ||
| 258 | S <- Id List | ||
| 259 | List <- !. / (',' / %{2}) Id List | ||
| 260 | Id <- [a-z] / %{1} | ||
| 261 | ]] | ||
| 262 | |||
| 263 | function mymatch (g, s) | ||
| 264 | local r, e = g:match(s) | ||
| 265 | if not r then | ||
| 266 | if e == 1 then | ||
| 267 | return r, "Error: expecting an identifier" | ||
| 268 | elseif e == 2 then | ||
| 269 | return r, "Error: expecting ','" | ||
| 270 | else | ||
| 271 | return r, "Error" | ||
| 272 | end | ||
| 273 | end | ||
| 274 | return r | ||
| 275 | end | ||
| 276 | |||
| 277 | print(mymatch(g, "a,b")) | ||
| 278 | print(mymatch(g, "a b")) | ||
| 279 | print(mymatch(g, ", b")) | ||
| 280 | </pre> | ||
| 281 | |||
| 282 | <p> | ||
| 283 | Another way to describe the previous example using the <em>re</em> module | ||
| 284 | is by using a table with the description the errors (<em>terror</em>) and | ||
| 285 | another table that associates a name to a given label (<em>tlabel</em>): | ||
| 286 | </p> | ||
| 287 | <pre class="example"> | ||
| 288 | local re = require 're' | ||
| 289 | |||
| 290 | local errUndef, errId, errComma = 0, 1, 2 | ||
| 291 | |||
| 292 | local terror = { | ||
| 293 | [errUndef] = "Error", | ||
| 294 | [errId] = "Error: expecting an identifier", | ||
| 295 | [errComma] = "Error: expecting ','", | ||
| 296 | } | ||
| 297 | |||
| 298 | local tlabels = { ["errUndef"] = errUndef, | ||
| 299 | ["errId"] = errId, | ||
| 300 | ["errComma"] = errComma } | ||
| 301 | |||
| 302 | re.setlabels(tlabels) | ||
| 303 | |||
| 304 | local g = re.compile[[ | ||
| 305 | S <- Id List | ||
| 306 | List <- !. / (',' / %{errComma}) Id List | ||
| 307 | Id <- [a-z] / %{errId} | ||
| 308 | ]] | ||
| 309 | |||
| 310 | function mymatch (g, s) | ||
| 311 | local r, e = g:match(s) | ||
| 312 | if not r then | ||
| 313 | return r, terror[e] | ||
| 314 | end | ||
| 315 | return r | ||
| 316 | end | ||
| 317 | |||
| 318 | print(mymatch(g, "a,b")) | ||
| 319 | print(mymatch(g, "a b")) | ||
| 320 | print(mymatch(g, ", b")) | ||
| 321 | </pre> | ||
| 322 | |||
| 323 | |||
| 324 | |||
| 325 | <h3>Throwing and catching a label</h3> | ||
| 326 | |||
| 327 | <p> | ||
| 328 | When a label is thrown, the grammar itself can handle this label | ||
| 329 | by using the labeled ordered choice. Below we rewrite the example | ||
| 330 | of the list of identifiers to show this feature: | ||
| 331 | </p> | ||
| 332 | <pre class="example"> | ||
| 333 | local m = require'lpeglabel' | ||
| 334 | |||
| 335 | local errUndef, errId, errComma = 0, 1, 2 | ||
| 336 | |||
| 337 | local terror = { | ||
| 338 | [errUndef] = "Error", | ||
| 339 | [errId] = "Error: expecting an identifier", | ||
| 340 | [errComma] = "Error: expecting ','", | ||
| 341 | } | ||
| 342 | |||
| 343 | g = m.P{ | ||
| 344 | "S", | ||
| 345 | S = m.Lc(m.Lc(m.V"Id" * m.V"List", m.V"ErrId", errId), | ||
| 346 | m.V"ErrComma", errComma), | ||
| 347 | List = -m.P(1) + m.V"Comma" * m.V"Id" * m.V"List", | ||
| 348 | Id = m.R'az'^1 + m.T(errId), | ||
| 349 | Comma = "," + m.T(errComma), | ||
| 350 | ErrId = m.Cc(errId) / terror, | ||
| 351 | ErrComma = m.Cc(errComma) / terror | ||
| 352 | } | ||
| 353 | |||
| 354 | print(g:match("a,b")) | ||
| 355 | print(g:match("a b")) | ||
| 356 | print(g:match(",b")) | ||
| 357 | </pre> | ||
| 358 | |||
| 359 | <p> | ||
| 360 | As was pointed out <a href="#f-lc">before</a>, the labeled ordered | ||
| 361 | choice is not associative, so we should impose a left-associative | ||
| 362 | order when using function <code>Lc</code>. | ||
| 363 | </p> | ||
| 364 | <p> | ||
| 365 | Below we use the <em>re</em> module to throw and catch labels. | ||
| 366 | As was pointed out <a href="#re-lc">before</a>, the <code>/{}</code> | ||
| 367 | operator is left-associative, so we do not need to manually impose | ||
| 368 | a left-associative order as we did in the previous example that | ||
| 369 | used <code>Lc</code>: | ||
| 370 | </p> | ||
| 371 | <pre class="example"> | ||
| 372 | local re = require're' | ||
| 373 | |||
| 374 | local terror = {} | ||
| 375 | |||
| 376 | local function newError(l, msg) | ||
| 377 | table.insert(terror, { l = l, msg = msg } ) | ||
| 378 | end | ||
| 379 | |||
| 380 | newError("errId", "Error: expecting an identifier") | ||
| 381 | newError("errComma", "Error: expecting ','") | ||
| 382 | |||
| 383 | local labelCode = {} | ||
| 384 | local labelMsg = {} | ||
| 385 | for k, v in ipairs(terror) do | ||
| 386 | labelCode[v.l] = k | ||
| 387 | labelMsg[v.l] = v.msg | ||
| 388 | end | ||
| 389 | |||
| 390 | re.setlabels(labelCode) | ||
| 391 | |||
| 392 | local p = re.compile([[ | ||
| 393 | S <- Id List /{errId} ErrId /{errComma} ErrComma | ||
| 394 | List <- !. / Comma Id List | ||
| 395 | Id <- [a-z]+ / %{errId} | ||
| 396 | Comma <- ',' / %{errComma} | ||
| 397 | ErrId <- '' -> errId | ||
| 398 | ErrComma <- '' -> errComma | ||
| 399 | ]], labelMsg) | ||
| 400 | |||
| 401 | print(p:match("a,b")) | ||
| 402 | print(p:match("a b")) | ||
| 403 | print(p:match(",b")) | ||
| 404 | </pre> | ||
| 405 | |||
| 406 | |||
| 407 | <h3>Tiny Language</h3> | ||
| 408 | <p> | ||
| 409 | As a more complex example, below we have the grammar | ||
| 410 | for the Tiny language, as described in | ||
| 411 | <a href="http://arxiv.org/abs/1405.6646">this</a> paper. | ||
| 412 | The example below can also how the line where the syntactic | ||
| 413 | error probably happened. | ||
| 414 | </p> | ||
| 415 | <pre class="example"> | ||
| 416 | local re = require 're' | ||
| 417 | |||
| 418 | local terror = {} | ||
| 419 | |||
| 420 | local function newError(l, msg) | ||
| 421 | table.insert(terror, { l = l, msg = msg} ) | ||
| 422 | end | ||
| 423 | |||
| 424 | newError("errSemi", "Error: missing ';'") | ||
| 425 | newError("errExpIf", "Error: expected expression after 'if'") | ||
| 426 | newError("errThen", "Error: expected 'then' keyword") | ||
| 427 | newError("errCmdSeq1", "Error: expected at least a command after 'then'") | ||
| 428 | newError("errCmdSeq2", "Error: expected at least a command after 'else'") | ||
| 429 | newError("errEnd", "Error: expected 'end' keyword") | ||
| 430 | newError("errCmdSeqRep", "Error: expected at least a command after 'repeat'") | ||
| 431 | newError("errUntil", "Error: expected 'until' keyword") | ||
| 432 | newError("errExpRep", "Error: expected expression after 'until'") | ||
| 433 | newError("errAssignOp", "Error: expected ':=' in assigment") | ||
| 434 | newError("errExpAssign", "Error: expected expression after ':='") | ||
| 435 | newError("errReadName", "Error: expected an identifier after 'read'") | ||
| 436 | newError("errWriteExp", "Error: expected expression after 'write'") | ||
| 437 | newError("errSimpExp", "Error: expected '(', ID, or number after '<' or '='") | ||
| 438 | newError("errTerm", "Error: expected '(', ID, or number after '+' or '-'") | ||
| 439 | newError("errFactor", "Error: expected '(', ID, or number after '*' or '/'") | ||
| 440 | newError("errExpFac", "Error: expected expression after '('") | ||
| 441 | newError("errClosePar", "Error: expected ')' after expression") | ||
| 442 | |||
| 443 | local line | ||
| 444 | |||
| 445 | local function incLine() | ||
| 446 | line = line + 1 | ||
| 447 | return true | ||
| 448 | end | ||
| 449 | |||
| 450 | local function countLine(s, i) | ||
| 451 | line = 1 | ||
| 452 | local p = re.compile([[ | ||
| 453 | S <- (%nl -> incLine / .)* | ||
| 454 | ]], { incLine = incLine}) | ||
| 455 | p:match(s:sub(1, i)) | ||
| 456 | return true | ||
| 457 | end | ||
| 458 | |||
| 459 | local labelCode = {} | ||
| 460 | for k, v in ipairs(terror) do | ||
| 461 | labelCode[v.l] = k | ||
| 462 | end | ||
| 463 | |||
| 464 | re.setlabels(labelCode) | ||
| 465 | |||
| 466 | local g = re.compile([[ | ||
| 467 | Tiny <- CmdSeq | ||
| 468 | CmdSeq <- (Cmd (SEMICOLON / ErrSemi)) (Cmd (SEMICOLON / ErrSemi))* | ||
| 469 | Cmd <- IfCmd / RepeatCmd / ReadCmd / WriteCmd / AssignCmd | ||
| 470 | IfCmd <- IF (Exp / ErrExpIf) (THEN / ErrThen) (CmdSeq / ErrCmdSeq1) (ELSE (CmdSeq / ErrCmdSeq2) / '') (END / ErrEnd) | ||
| 471 | RepeatCmd <- REPEAT (CmdSeq / ErrCmdSeqRep) (UNTIL / ErrUntil) (Exp / ErrExpRep) | ||
| 472 | AssignCmd <- NAME (ASSIGNMENT / ErrAssignOp) (Exp / ErrExpAssign) | ||
| 473 | ReadCmd <- READ (NAME / ErrReadName) | ||
| 474 | WriteCmd <- WRITE (Exp / ErrWriteExp) | ||
| 475 | Exp <- SimpleExp ((LESS / EQUAL) (SimpleExp / ErrSimpExp) / '') | ||
| 476 | SimpleExp <- Term ((ADD / SUB) (Term / ErrTerm))* | ||
| 477 | Term <- Factor ((MUL / DIV) (Factor / ErrFactor))* | ||
| 478 | Factor <- OPENPAR (Exp / ErrExpFac) (CLOSEPAR / ErrClosePar) / NUMBER / NAME | ||
| 479 | ErrSemi <- ErrCount %{errSemi} | ||
| 480 | ErrExpIf <- ErrCount %{errExpIf} | ||
| 481 | ErrThen <- ErrCount %{errThen} | ||
| 482 | ErrCmdSeq1 <- ErrCount %{errCmdSeq1} | ||
| 483 | ErrCmdSeq2 <- ErrCount %{errCmdSeq2} | ||
| 484 | ErrEnd <- ErrCount %{errEnd} | ||
| 485 | ErrCmdSeqRep <- ErrCount %{errCmdSeqRep} | ||
| 486 | ErrUntil <- ErrCount %{errUntil} | ||
| 487 | ErrExpRep <- ErrCount %{errExpRep} | ||
| 488 | ErrAssignOp <- ErrCount %{errAssignOp} | ||
| 489 | ErrExpAssign <- ErrCount %{errExpAssign} | ||
| 490 | ErrReadName <- ErrCount %{errReadName} | ||
| 491 | ErrWriteExp <- ErrCount %{errWriteExp} | ||
| 492 | ErrSimpExp <- ErrCount %{errSimpExp} | ||
| 493 | ErrTerm <- ErrCount %{errTerm} | ||
| 494 | ErrFactor <- ErrCount %{errFactor} | ||
| 495 | ErrExpFac <- ErrCount %{errExpFac} | ||
| 496 | ErrClosePar <- ErrCount %{errClosePar} | ||
| 497 | ErrCount <- '' => countLine | ||
| 498 | ADD <- Sp '+' | ||
| 499 | ASSIGNMENT <- Sp ':=' | ||
| 500 | CLOSEPAR <- Sp ')' | ||
| 501 | DIV <- Sp '/' | ||
| 502 | IF <- Sp 'if' | ||
| 503 | ELSE <- Sp 'else' | ||
| 504 | END <- Sp 'end' | ||
| 505 | EQUAL <- Sp '=' | ||
| 506 | LESS <- Sp '<' | ||
| 507 | MUL <- Sp '*' | ||
| 508 | NAME <- Sp !RESERVED [a-z]+ | ||
| 509 | NUMBER <- Sp [0-9]+ | ||
| 510 | OPENPAR <- Sp '(' | ||
| 511 | READ <- Sp 'read' | ||
| 512 | REPEAT <- Sp 'repeat' | ||
| 513 | SEMICOLON <- Sp ';' | ||
| 514 | SUB <- Sp '-' | ||
| 515 | THEN <- Sp 'then' | ||
| 516 | UNTIL <- Sp 'until' | ||
| 517 | WRITE <- Sp 'write' | ||
| 518 | RESERVED <- (IF / ELSE / END / READ / REPEAT / THEN / UNTIL / WRITE) ![a-z]+ | ||
| 519 | Sp <- %s* | ||
| 520 | ]], { countLine = countLine }) | ||
| 521 | </pre> | ||
| 522 | |||
| 523 | |||
| 524 | <h2><a name="download"></a>Download</h2> | ||
| 525 | |||
| 526 | <p>LPeg | ||
| 527 | <a href="http://www.inf.puc-rio.br/~roberto/lpeg/lpeg-0.12.tar.gz">source code</a>.</p> | ||
| 528 | |||
| 529 | |||
| 530 | <h2><a name="license">License</a></h2> | ||
| 531 | |||
| 532 | <p> | ||
| 533 | The MIT License (MIT) | ||
| 534 | </p> | ||
| 535 | <p> | ||
| 536 | Copyright (c) 2014-2015 Sérgio Medeiros | ||
| 537 | </p> | ||
| 538 | <p> | ||
| 539 | Permission is hereby granted, free of charge, to any person obtaining a copy | ||
| 540 | of this software and associated documentation files (the "Software"), to deal | ||
| 541 | in the Software without restriction, including without limitation the rights | ||
| 542 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
| 543 | copies of the Software, and to permit persons to whom the Software is | ||
| 544 | furnished to do so, subject to the following conditions: | ||
| 545 | </p> | ||
| 546 | <p> | ||
| 547 | The above copyright notice and this permission notice shall be included in all | ||
| 548 | copies or substantial portions of the Software. | ||
| 549 | </p> | ||
| 550 | <p> | ||
| 551 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
| 552 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
| 553 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
| 554 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
| 555 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
| 556 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||
| 557 | SOFTWARE. | ||
| 558 | |||
| 559 | |||
| 560 | |||
| 561 | |||
| 562 | </p> | ||
| 563 | |||
| 564 | </div> <!-- id="content" --> | ||
| 565 | |||
| 566 | </div> <!-- id="main" --> | ||
| 567 | |||
| 568 | <div id="about"> | ||
| 569 | </div> <!-- id="about" --> | ||
| 570 | |||
| 571 | </div> <!-- id="container" --> | ||
| 572 | |||
| 573 | </body> | ||
| 574 | </html> | ||
