some cleanup and implement phase 2 of the C++ lexer
authorD Herring <dherring@at.tentpost.dot.com>
Sun, 1 Apr 2012 05:10:53 +0000 (01:10 -0400)
committerD Herring <dherring@at.tentpost.dot.com>
Sun, 1 Apr 2012 05:10:53 +0000 (01:10 -0400)
examples/c++lex-phases.lisp
examples/extensible-parser-example.lisp

index 5baf0f3..12e5f4b 100644 (file)
@@ -3,6 +3,34 @@
   ())
 
 ;; 2.2 -- impl
+
+;; phase 1
+;; take input string and produce an output string
+;; trigraphs to single characters
+;; \r\n to \n
+;; complain if anything doesn't match the basic-source-character-set
+;; this should get line numbers correct and columns close enough
+;; if desired, some structure could track offsets on affected lines
+
+(defun c++-lex-phase2 (source-string)
+  "strip out backslash-newline sequences -- need to preserve line numbers..."
+  (let* ((match (format nil "\\~%" slash-n))
+         (count
+          (loop
+             for c = 0 then (1+ c)
+             for p0 = 0 then (+ 2 pos)
+             for pos = (search match source-string :start2 p0)
+             while pos
+             finally (return c)))
+         (result (make-string (- (length source-string) (* 2 count)))))
+    (loop
+       for r0 = 0 then (+ r0 (- pos p0))
+       for p0 = 0 then (+ 2 pos)
+       for pos = (search (format nil "\\~%" slash-n) source-string :start2 p0)
+       do (replace result source-string :start1 r0 :start2 p0 :end2 (or pos (length source-string)))
+       while pos)
+    result))
+
 ;; approximate phase 3
 (defrule whitespace
   (or (c-comment) (c++-comment) slash-t slash-n slash-v slash-f slash-r " "))
@@ -25,6 +53,7 @@ void f(int *x);
     (with-open-file (file filename)
       (setf str (make-sequence 'string (file-length file)))
       (read-sequence str file))
+    (setf str (c++-lex-phase2 str))
     ;; eventually return the AST, the comment list, and the preproc list
     ;; also return a list of newlines (so line/col can be quickly calculated)
     ;; also return an indication if the parse didn't consume the whole file
index 267a112..340b632 100644 (file)
       (when (<= (char-code char0) (char-code c) (char-code char1))
         (values (1+ start) c)))))
 
-;; 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)))
-
 (defmacro when-match (name rule &body body)
   `(let ((,name ,rule))
      (when ,name
 ;; other source files should handle the other phases
 
 ;; 2.3, lex.charset
+#|
+ (defrule basic-source-character-set
+    (or
+     " " slash-t slash-v slash-f slash-n
+     (ascii-range #\a #\z)
+     (ascii-range #\A #\Z)
+     (ascii-range #\0 #\9)
+     and a bunch of punctuation))
+|#
+
 (defrule hex-quad
   (and (hexadecimal-digit)
        (hexadecimal-digit)
        (and (pp-number) #\.))
   |#
   ;; equivalent
-  (and
-   (or (and (repeat 0 nil (digit)) #\. (repeat 1 nil (digit)))
-       (and (repeat 1 nil (digit)) #\. (repeat 0 nil (digit)))
-       (repeat 1 nil (digit)))
-   (optional
-    (and (or #\e #\E)
-         (sign)
-         (repeat 0 nil (digit))))))
+  (:cl
+   (match-filter (:context) (string start after end)
+      (and
+       (or (and (repeat 0 nil (digit)) #\. (repeat 1 nil (digit)))
+           (and (repeat 1 nil (digit)) #\. (repeat 0 nil (digit)))
+           (repeat 1 nil (digit)))
+       (optional
+        (and (or #\e #\E)
+             (optional (sign))
+             (repeat 0 nil (digit)))))
+      (create-token :pp-number string start after))))
 
 
 #|