source: trunk/csv.lisp

Last change on this file was 5, checked in by dsowen, 17 years ago

Updated for newer lexer

File size: 2.4 KB
Line 
1;;;; -*- Mode: Lisp; Syntax: ANSI-Common-Lisp -*-
2
3#|
4Copyright (C) 2007, 2008  David Owen <dsowen@fugue88.ws>
5
6This program is free software: you can redistribute it and/or modify
7it under the terms of the GNU Lesser Public License as published by
8the Free Software Foundation, either version 3 of the License, or
9(at your option) any later version.
10
11This program is distributed in the hope that it will be useful,
12but WITHOUT ANY WARRANTY; without even the implied warranty of
13MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14GNU Lesser Public License for more details.
15
16You should have received a copy of the GNU Lesser Public License
17along with this program.  If not, see <http://www.gnu.org/licenses/>.
18|#
19
20(defpackage #:dso-csv
21  (:use #:cl #:dso-lex #:dso-parse)
22  ;; TODO
23  (:import-from #:dso-parse #:substring)
24  (:export #:lex-all-csv
25           #:file
26           #:row
27           #:read-csv))
28
29(in-package #:dso-csv)
30
31
32
33(flet ((trim (s) (dso-parse::substring s :start 1 :length (- (length s) 2))))
34  (defun un-squote (s)
35    (cl-ppcre:regex-replace-all "''" (trim s) "'"))
36  (defun un-dquote (s)
37    (cl-ppcre:regex-replace-all "\"\"" (trim s) "\"")))
38
39(deflexer lex-csv (:priority-only t)
40  ("," comma)
41  ("\\r\\n?|\\n" newline)
42  ("'(?:[^']|'')*'" value un-squote)
43  ("\"(?:[^\"]|\"\")*\"" value un-dquote)
44  ("[^,'\"\\n\\r]+" value)
45  ("." illegal))
46
47(defun lex-all-csv (input)
48  (declare (optimize (speed 2) (debug 1)))
49  (labels ((lex-all (start tokens)
50             (multiple-value-bind (class image next-offset)
51                 (lex-csv input start)
52               (cond
53                 ((and class (eq class 'illegal))
54                  (error "Illegal input"))
55                 (class
56                  (lex-all next-offset (cons (cons class image) tokens)))
57                 (t
58                  (nreverse tokens))))))
59    (setf input (coerce input 'simple-string))
60    (lex-all 0 nil)))
61
62(defmacro defmatcher (class)
63  (let ((fn-sym (intern (concatenate 'string "T-" (symbol-name class)))))
64    `(defun ,fn-sym (token-list)
65      (when token-list
66        (destructuring-bind (class . image) (first token-list)
67          (when (eq class ',class)
68            (values t (rest token-list) (list image))))))))
69
70(defmatcher comma)
71(defmatcher newline)
72(defmatcher value)
73
74
75
76(defgrammar ()
77  (file (+ row))
78  (row (t-value (* row-rest) (= t-newline))
79       :filter (lambda (row) (cons (caar row) (mapcar #'second (second row)))))
80  (row-rest ((= t-comma) t-value) :filter 'car))
81
82
83
84(defun read-csv (input)
85  (let ((tokens (lex-all-csv input)))
86    (file tokens)))
Note: See TracBrowser for help on using the repository browser.