Fix PEG grammar and add action support.
[cl-opossum.git] / opossum.peg
blobce3ef230a1ca081e704ae43f190cd9f323c4671a
1 ## -*- mode: peg -*-
2 ## (c) 2008 Utz-Uwe Haus <lisp@uuhaus.de>
3 ## $Id$ 
4 ##
5 ## This code is free software; you can redistribute it and/or modify
6 ## it under the terms of the version 2.1 of the GNU Lesser General
7 ## Public License as published by the Free Software Foundation, as
8 ## clarified by the lisp prequel found in LICENSE.
9 ##
10 ## This code is distributed in the hope that it will be useful, but
11 ## without any warranty; without even the implied warranty of
12 ## merchantability or fitness for a particular purpose. See the GNU
13 ## Lesser General Public License for more details.
15 ## Version 2.1 of the GNU Lesser General Public License is in the file
16 ## LICENSE that was distributed with this file. If it is not
17 ## present, you can access it from
18 ## http://www.gnu.org/copyleft/lgpl.txt (until superseded by a
19 ## newer version) or write to the Free Software Foundation, Inc., 59
20 ## Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 ## Commentary:
24 ## PEG syntax in PEG as in the report from 2004 (`Parsing Expression Grammars:
25 ## A Recognition-Based Syntactic Foundation'' by Bryan Ford)
28 # Process this file with an existing PEG parser to bootstrap.
29 # The output needs to be adjusted by replacing the package OPOSSUM
30 # by OPOSSUM-SYSTEM if you want to use it as a replacement of
31 # the shipped pegparser-boot.lisp
33 # This file needs a cleanup wrt. linebreaks once we bootstrapped off
34 # the metapeg parser which is crippled.
36 # Hierarchical syntax
37 PEG-Grammar <- Spacing Definition+ EndOfFile {
38         `((eval-when (:compile-toplevel :load-toplevel :execute)        
39           (declaim (optimize (speed 0) (safety 3) (debug 3))))
40           (defun opossum-parser ()
41             (let ((*context* (make-instance 'context :start-index 0))) #'
42               (funcall (|PEG-Grammar|) 0)))
43            ,@(second data))
44         }
46 Definition <- Identifier LEFTARROW Expression {
47         `(,(opossum::make-name (first data)) #'(lambda () ,(third data))) ;'
48         } 
50 Expression <- Sequence Action? (SLASH Sequence Action?)* {
51          (if (null (second data))
52                (first data)
53                (let ((tail (second (cadr data))))
54                   (if (equal (first tail) 'seq) 
55                       `(seq ,(first data) ,@(rest tail))
56                       `(seq ,(first data) ,tail)))) ;'
57          }
59 Sequence <- Prefix* { `(many ,(first data)) }
61 Prefix <-   (AND Suffix) {
62          `(follow ,(second data)) 
63                 } / (NOT Suffix) {
64          `(negate ,(second data))
65          } / Suffix { (second data) }
67 Suffix <-   Primary QUESTION { `(optional ,(first data))
68         } / Primary STAR     { `(many ,(first data)) 
69         } / Primary PLUS     { `(many1 ,(first data)) 
70         } / Primary          { (first data) }
72 Primary <- Identifier !LEFTARROW { (first data)
73         } / OPEN Expression CLOSE { (second data) 
74         } / Literal            { (first data) 
75         } / Class              { (first data) 
76         } / DOT                { `(match-any-char ,data) }
78 Action <- "{" (!"}" .)* "}" Spacing { 
79         (let* ((action-data (second data))
80                (action-code (coerce
81                                (opossum::fix-escape-sequences
82                                 (mapcar #'second action-data))
83                              'string))
84                (action-name (opossum::make-action-name)))
85             (opossum::store-action opossum:*context*
86                                    `(,action-name ,action-code))
87             `(list ':action nil ',action-name))
88         }
90 # Lexical syntax
91 Identifier <- [a-zA-Z_] [a-zA-Z0-9_]* Spacing { (concatenate 'string (first data) (second data)) } 
93 Literal    <-     ['] (!['] Char)* ['] Spacing { 
94                 (second data)
95               } / ["] (!["] Char)* ["] Spacing  {
96                 (second data)   }
97 # "
98 Class      <- "[" (!"]" Range)* "]" Spacing { (second data) }
99
100 Range <-     Char "-" Char     { 
101           `(match-char-range ,(first data) ,(third data))
102          } / Char              { (first data) }
103 # FIXME: needs to be repaired when metapeg traces are gone
104 Char <-     "\\" [nrt'"]           { data
105         } / "\\["                  { data 
106         } / "\\]"                  { data
107         } / "\\\\"                 { data
108         } / "\\" [0-2] [0-7] [0-7]  { `(match-octal-char-code ,(second data) ,(third data) ,(fourth data))
109         } / "\\" [0-7] [0-7]?       { 
110           (if (third data)
111                  `(match-octal-char-code 0 ,(second data) ,(third data))
112                  `(match-octal-char-code 0 0 ,(second data)))
113         } / !"\\" .                { (last data) }
116 LEFTARROW <- "<-" Spacing { (first data) }
117 SLASH     <- "/"  Spacing { (first data) }
118 AND       <- "&"  Spacing { (first data) }
119 NOT       <- "!"  Spacing { (first data) }
120 QUESTION  <- "?"  Spacing { (first data) }
121 STAR      <- "*"  Spacing { (first data) }
122 PLUS      <- "+"  Spacing { (first data) }
123 OPEN      <- "("  Spacing { (first data) }
124 CLOSE     <- ")"  Spacing { (first data) }
125 DOT       <- "."  Spacing { (first data) }
126 Spacing   <- (Space / Comment)*
127 Comment   <- "#" (!EndOfLine .)* EndOfLine
128 Space     <- " " / "\t" / EndOfLine
129 EndOfLine <- "\r\n" / "\n" / "\r"
130 EndOfFile <- !.