clean up the cpp example a bit
authorD Herring <dherring@at.tentpost.dot.com>
Thu, 12 Apr 2012 01:52:34 +0000 (21:52 -0400)
committerD Herring <dherring@at.tentpost.dot.com>
Thu, 12 Apr 2012 01:52:34 +0000 (21:52 -0400)
examples/cpp-lexer.lisp [deleted file]
examples/cpp-re.lisp [deleted file]
examples/cpp/README [new file with mode: 0644]
examples/cpp/cpp.lisp [new file with mode: 0644]
examples/cpp/lex.lisp [moved from examples/extensible-parser-example.lisp with 100% similarity]
examples/cpp/phases.lisp [moved from examples/c++lex-phases.lisp with 97% similarity]
extensible-parser.asd
extensible-parser.lisp

diff --git a/examples/cpp-lexer.lisp b/examples/cpp-lexer.lisp
deleted file mode 100644 (file)
index 13e3c5d..0000000
+++ /dev/null
@@ -1,66 +0,0 @@
-;; CPP lexer
-;; based on "JTC1.22.32 - ISO/IEC 14882 - Programming language C++ draft February 2011" (n3242.pdf)
-
-(defpackage #:cpp-lexer
-  (:use :common-lisp #:ebnf))
-
-(in-package #:cpp-lexer)
-
-(defgrammar "
-(* 2.4 *)")
-
-(defgrammar "(* 2.5 *)
-preprocessing-token=header-name|identifier|pp-number|character-literal|user-defined-character-literal|string-literal|user-defined-string-literal|preprocessing-op-or-punc|other-non-whitespace;")
-
-#|
-(* 2.6 -- rules need renaming and need substitutions below *)
-alt{='<%';
-alt}='%>';
-alt[='<:';
-alt]=':>';
-alt#='%:';
-alt##='%:%:';
-alt&&='and';
-alt|='bitor';
-alt||='or';
-alt^='xor';
-alt~='compl';
-alt&='bitand';
-alt&=='and_eq';
-alt|=='or_eq';
-alt^=='xor_eq';
-alt!='not';
-alt!=='not_eq';
-|#
-
-(defgrammar "(* 2.7 & see note *)
-token=identifier|keyword|literal|operator|punctuator;")
-
-(defgrammar "(* 2.8 *)
-c-comment='/*',*,'*/';
-cxx-comment='//',*,newline;")
-
-(defgrammar "(* 2.9 *)
-header-name=('<',h-char-sequence,'>')|('\"',q-char-sequence,'\"');
-h-char-sequence=h-char|(h-char-sequence,h-char);
-h-char=char-(new-line|'>');
-q-char-sequence=q-char|(q-char-sequence,q-char);
-q-char=char-(new-line|'\"');")
-
-(defgrammar "(* 2.10 *)
-pp-number=digit
-  |('.',digit)
-  |(pp-number,digit)
-  |(pp-number,identifier-nondigit)
-  |(pp-number,'e',sign)
-  |(pp-number,'E',sign)
-  |(pp-number,'.');")
-
-(defgrammar "(* 2.11 *)
-identifier=identifier-nondigit
-  |(identifier,identifier-nondigit)
-  |(identifier,digit);
-identifier-nondigit=nondigit|universal-character-name; (* or impl-defined *)
-nondigit='a'|'b'|'c'|'d'|'e'|'f'|'g'|...'Y'|'Z'|'_';
-digit='0'...'9';
-")
\ No newline at end of file
diff --git a/examples/cpp-re.lisp b/examples/cpp-re.lisp
deleted file mode 100644 (file)
index 3e7d2a6..0000000
+++ /dev/null
@@ -1,325 +0,0 @@
-#|
-parser protocol
-args: (sequence start end)
-return: nil or (next-start value)
-
-transform protocol similar to Boost::Spirit
-see http://www.boost.org/doc/libs/1_48_0/libs/spirit/doc/html/spirit/qi/reference/action.html
-args: (sequence start next-start end value)
-return: nil or (next-start value)
-note that the fancy return-value isn't necessary; just wrap the parser...
-
-old protocol had start
-|#
-
-#|
-definition: A ``parse-form'' is a shorthand notation for specifying parsers; it leaves out the (seq start end) parameters used to pass stream context.
-
-the parse-form (x y z) is expanded to (x seq start end y z)
-a parse-form atom is taken to be a literal token
-|#
-(defmacro parse-form (form seq start end)
-  "expand the parse-form f"
-
- )
-
-(defmacro grammar-call (form seq start end)
-  "how to invoke a form in a grammar rule"
-  (cond
-    ;; an empty list never matches
-    ((null form) nil)
-    ;; t always matches, without advancing the stream or producing a value
-    ((eql form t) (list 'values end))
-    ;; match some common literals
-    ((stringp form) (list 'match-string seq start end))
-    ((characterp form) (list 'match-char seq start end))
-    ;; if form is a list
-    ))
-
-(defmacro transform (seq start end parse-form modifier-form)
-  `(multiple-value-bind (e v)
-       ,parse-form
-     (when e
-       (values e ,(push v (cdr modifier-form))))))
-
-;; parser compiler similar to "On Lisp" section 19.5
-;; use generic functions to register actions
-
-(defgeneric cpf (form context)
-  (:documentation "CPF = compile parse form.  Given a parse expression and a parsing context, return (values expansion expanded-p)."))
-
-(defun cpf-cl-all (form context)
-  "recurse through a normal CL source form, processing sublists as possible parse forms"
-  (if (listp form)
-    (let ((modified nil))
-      (values 
-       (loop for x in form
-          collecting
-            (if (listp x)
-                (multiple-value-bind (exp exp-p) (cpf x context)
-                  (when exp-p
-                    (setf modified t))
-                  exp)
-                x))
-       modified))
-    form))
-
-(define-condition warn-not-parse-function (style-warning)
-  ((form :initarg :form :reader warn-not-parse-function-form))
-  (:report
-   (lambda (c s)
-     (format s "form was not a parse form: ~A" (warn-not-parse-function-form c)))))
-
-;; needs a way to control context chaining when recursing through normal expressions
-(defun cfp-cl-key (form context &optional (key 'parse))
-  "recurse through a normal CL form, processing sublists that begin with KEY as parse forms"
-  (if (listp form)
-      (let ((modified nil))
-        (values
-         (loop for x in form
-            collecting
-              (if (and (listp x) (eql (car x) key))
-                  (multiple-value-bind (exp exp-p) (cpf (cdr x) context)
-                    (if exp-p
-                        (setf modified t)
-                        (warn 'warn-not-parse-function :form exp))
-                    exp)
-                  x))
-         modified))
-      form))
-                        
-
-(defgeneric cpf-list (car form context)
-  (:documentation "CPF can dispatch list forms to this function."))
-
-(defclass context nil nil)
-
-(defclass string-context (context)
-  (string start end))
-
-(defclass list-context (context)
-  (top here end))
-
-(defun match-atom (seq start end atom)
-  (declare (ignore end))
-  (when (equal (elt seq start) atom)
-    (values (1+ start) atom)))
-
-(defmethod cpf (form seq start end)
-  "try to match the atom form in the seq"
-  `(match-atom ,seq ,start ,end ,form))
-
-(defmethod cpf-list (car form seq start end)
-  ;; default method: don't modify the form...
-  form)
-
-(defun starts-with (string start end prefix)
-  "Does 'string' begin with 'prefix'?"
-  (let ((stop (+ start (length prefix))))
-    (when (and (< stop (or end (length string)))
-               (string= prefix string :start2 start :end2 stop))
-      (values stop prefix))))
-
-(defmethod cpf ((form string) seq start end)
-  `(typecase ,seq
-     (string (starts-with ,seq ,start ,end ,form))
-     (t (match-atom ,seq ,start ,end ,form))))
-  
-
-(defmethod cpf ((form list) seq start end)
-  (cpf-list (car form) form seq start end))
-
-(defmethod cpf-list ((car (eql 'and)) form seq start end)
-  "return nil if any term failed or (values last-end (list val1 ... valn)) if all passed"
-  
-  (print 43))
-
-(defmacro defrule (name &body body)
-  `(progn
-     (defun ,name (seq start end)
-       (cpf ,body seq start end))
-     (demethod cpf-list ((car (eql ',name)) seq start end)
-             (cpf ,body seq start end)))
-
-
-;; translation of Boost's cpp.re
-
-(defconstant slash-t #\Tab "C escape: \t; (code-char 9)")
-(defconstant slash-n #\Linefeed "C escape: \n; (code-char 10)")
-(defconstant slash-v (code-char 11) "C escape: \v; (code-char 11)")
-(defconstant slash-f #\Page "C escape: \f; (code-char 12)")
-(defconstant slash-r #\Return "C escape: \r; (code-char 13)")
-
-(defparameter *c++-mode* nil "indicate that we are parsing C++ code")
-
-
-;; any                = [\t\v\f\r\n\040-\377];
-(defrule any
-  (or
-   slash-t
-   slash-v
-   slash-f
-   slash-r
-   slash-n
-   (ascii-range 32 255)))
-
-;; anyctrl            = [\001-\037];
-(defrule anyctrl
-    (ascii-range 1 31))
-
-;; OctalDigit         = [0-7];
-(defrule octal-digit
-    (ascii-range #\0 #\7))
-
-;; Digit              = [0-9];
-(defrule digit
-    (ascii-range #\0 #\9))
-
-;; HexDigit           = [a-fA-F0-9];
-(defrule hex-digit
-    (or
-     (ascii-range #\a #\f)
-     (ascii-range #\A #\F)
-     (ascii-range #\0 #\9)))
-
-;; Integer            = (("0" [xX] HexDigit+) | ("0" OctalDigit*) | ([1-9] Digit*));
-(defrule integer
-    (or
-     (and #\0 (or #\x #\X) (range 1 * hex-digit))
-     (and #\0 (range 0 * octal-digit))
-     (and (ascii-range #\1 #\9) (range 0 * digit))))
-
-;; ExponentStart      = [Ee] [+-];
-(defrule exponent-start
-    (and (or #\E #\e) (or #\+ #\-)))
-
-;; ExponentPart       = [Ee] [+-]? Digit+;
-(defrule exponent-part
-    (and (or #\E #\e)
-         (range 0 1 (or #\+ #\-))
-         (range 1 * digit)))
-
-;; FractionalConstant = (Digit* "." Digit+) | (Digit+ ".");
-(defrule fractional-constant
-    (or (and (range 0 * digit) #\. (range 1 * digit))
-        (and (range 1 * digit) #\.)))
-
-;; FloatingSuffix     = [fF] [lL]? | [lL] [fF]?;
-(defrule floating-suffix
-    (or (and (or #\f #\F) (range 0 1 (or #\l #\L)))
-        (and (or #\l #\L) (range 0 1 (or #\f #\F)))))
-
-;; IntegerSuffix      = [uU] [lL]? | [lL] [uU]?;
-(defrule integer-suffix
-    (or (and (or #\u #\U) (range 0 1 (or #\l #\L)))
-        (and (or #\l #\L) (range 0 1 (or #\u #\U)))))
-
-;; LongIntegerSuffix  = [uU] ([lL] [lL]) | ([lL] [lL]) [uU]?;
-(defrule long-integer-suffix
-Backslash          = [\\] | "??/";
-EscapeSequence     = Backslash ([abfnrtv?'"] | Backslash | "x" HexDigit+ | OctalDigit OctalDigit? OctalDigit?);
-HexQuad            = HexDigit HexDigit HexDigit HexDigit;
-UniversalChar      = Backslash ("u" HexQuad | "U" HexQuad HexQuad);
-Newline            = "\r\n" | "\n" | "\r";
-PPSpace            = ([ \t\f\v]|("/*"(any\[*]|Newline|("*"+(any\[*/]|Newline)))*"*"+"/"))*;
-Pound              = "#" | "??=" | "%:";
-NonDigit           = [a-zA-Z_$] | UniversalChar;
-
-
-(defrule newline
-    (or
-     (and #\Return #\Linefeed)
-     #\Linefeed
-     #\Return))
-
-;; 2.7
-(defrule token
-    (or identifier
-        keyword
-        literal
-        operator
-        punctuator))
-
-;; 2.8
-(defrule c-comment
-    (and "/*" (match-until "*/")))
-
-;; 2.8
-(defrule c++-comment
-    (cl:and *c++-mode*
-            (and "//"
-                 (repeat 0 * (exception any (or slash-v slash-f slash-n)))
-                 (repeat 0 * (or slash-v slash-f (exception whitespace slash-n)))
-                 slash-n)))
-
-(defun string-value (x)
-  "parser transform, return the matched string instead of its pieces"
-  (declare (ignore x))
-  (subseq string start end))
-
-(defun string-matcher (s)
-  "return a grammar lambda that matches the string s"
-  (let ((l (length s)))
-    (lambda (seq start end)
-      ;; dispatch on type of seq? For example, also match '(s) or #(s) ?
-      (let ((stop (+ start l)))
-        (when (and (< stop (or end (length seq)))
-                   (string= s seq :start2 start :end2 stop))
-          (values stop s))))))
-           
-
-;; if body is a single form, execute it
-;; if body has two forms, the second is a filter for the first
-(defmacro defrule (name &body body)
-  `(defun ,name (seq start end)
-     ,@
-     ))
-
-;; 2.9
-(defrule header-name
-    (multiple-value-bind (e v)
-        (or (and #\< h-char-sequence #\>)
-            (and #\" q-char-sequence #\"))
-      (when e
-        (values e (list :include (second v))))))
-
-(defrule h-char-sequence
-    (repeat 1 * h-char)
-  #'string-value)
-
-(defrule h-char
-    (exception any (or slash-n #\>)))
-
-(defrule q-char-sequence
-    (repeat 1 * q-char)
-  #'string-value)
-
-(defrule q-char
-    (exception any (or slash-n #\")))
-
-#|
-([ \t\f\v]|
- ("/*"
-  (any\[*]|
-  Newline|
-  ("*"+(any\[*/]|Newline)))*
- "*"+"/"))*
-|#
-(defrule ppspace
-(repeat *
- (or
-  (chartable #\Space #\Tab #\Page vtab)
-  (and
-   "/*"
-   (repeat *
-    (or
-     (exception any #\*)
-     newline
-     (and
-      (one-or-more "*")
-      (or
-       (exception
-        any (or #\* #\/))
-       #\Linefeed))))
-   (one-or-more "*")
-   "/")))
\ No newline at end of file
diff --git a/examples/cpp/README b/examples/cpp/README
new file mode 100644 (file)
index 0000000..96f7cb4
--- /dev/null
@@ -0,0 +1,3 @@
+CPP lexer
+based on "JTC1.22.32 - ISO/IEC 14882 - Programming language C++ draft"
+(n3290.pdf)
diff --git a/examples/cpp/cpp.lisp b/examples/cpp/cpp.lisp
new file mode 100644 (file)
index 0000000..544e7ea
--- /dev/null
@@ -0,0 +1,25 @@
+;; C++ standard, chapter 16: Preprocessing directives
+;; (PDF p. 426, printed p. 411)
+
+;; need to allow for whitespace, including comments
+
+(defrule if-group
+  (or (and "#" "if")
+      (and "#" "ifdef")
+      (and "#" "ifndef")))
+
+(defrule if-section
+  (and (if-group)
+       (optional (elif-groups))
+       (optional (else-group))
+       (assert (endif-line))))
+
+(defrule group-part
+  (or (if-section)
+      (control-line)
+      (text-line)
+      (and "#" (non-directive))))
+
+(defrule preprocessing-file
+    ;; inline the rule for group
+    (repeat 0 nil (group-part)))
\ No newline at end of file
similarity index 97%
rename from examples/c++lex-phases.lisp
rename to examples/cpp/phases.lisp
index 3f2daac..eae2ac8 100644 (file)
@@ -1,7 +1,3 @@
-(defun c++-lex-phase3 (string &optional (start 0) (end (length string)))
-  "approximate phase 3"
-  ())
-
 ;; 2.2 -- impl
 
 ;; phase 1
index ff23167..61c9420 100644 (file)
@@ -6,5 +6,7 @@
   :serial t
   :components ((:file "extensible-parser")
                (:file "string-context")
-               (:file "examples/extensible-parser-example")
-               (:file "examples/c++lex-phases")))
+               (:file "examples/cpp/lex")
+               (:file "examples/cpp/cpp")
+               (:file "examples/cpp/phases")
+               ))
\ No newline at end of file
index ddffdc9..ec3e71f 100644 (file)
@@ -29,6 +29,30 @@ if a list,
   (
 |#
 
+#|
+parser protocol
+args: (sequence start end)
+return: nil or (next-start value)
+
+transform protocol similar to Boost::Spirit
+see http://www.boost.org/doc/libs/1_48_0/libs/spirit/doc/html/spirit/qi/reference/action.html
+args: (sequence start next-start end value)
+return: nil or (next-start value)
+note that the fancy return-value isn't necessary; just wrap the parser...
+
+old protocol had start
+|#
+
+#|
+definition: A ``parse-form'' is a shorthand notation for specifying parsers; it leaves out the (seq start end) parameters used to pass stream context.
+
+the parse-form (x y z) is expanded to (x seq start end y z)
+a parse-form atom is taken to be a literal token
+|#
+
+;; parser compiler similar to "On Lisp" section 19.5
+;; use generic functions to register actions
+
 ;;;; PROTOCOL
 
 (defgeneric cpf (form context env)