Repository navigation
Expand file tree
/
Copy pathparse.lisp
More file actions
83 lines (60 loc) · 2.18 KB
/
Copy pathparse.lisp
File metadata and controls
83 lines (60 loc) · 2.18 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
;;;; microlisp.parse: Parse microlisp source files.
(defpackage microlisp.parse
(:use :cl)
(:export :parse))
(in-package :microlisp.parse)
;;; The next two constants look like you could change them to modify
;;; parser behaviour but you can't. Never. They just designate the first
;;; and last character of a top-level s-expression.
(defconstant +list-open+ #\(
"List opening character.")
(defconstant +list-close+ #\)
"List closing character.")
;;; These you can totally adjust if you'd like.
(defconstant +comment-open+ #\;
"Comment opening character.")
(defconstant +comment-close+ #\Newline
"Comment closing character.")
(defparameter *whitespace* '(#\Space #\Tab #\Return #\Newline)
"Characters considered whitespace.")
;;; Utilities
(defun peek-char* (stream &optional peek-mode)
"(peek-char PEEK-MODE STREAM nil)"
(peek-char peek-mode stream nil))
(defun whitespace-p (character)
"Predicate to test if CHARACTER is in *whitespace*."
(member character *whitespace*))
(defun comment-open-p (character)
"Predicate to test if CHARACTER is +comment-open+."
(and character (char= +comment-open+ character)))
(defun skip-whitespace (input)
"Skips whitespace in input."
(loop while (whitespace-p (peek-char* input))
do (read-char input nil)))
(defun skip-comment (input)
"Skips comment in INPUT."
(when (comment-open-p (peek-char* input))
(peek-char* input +comment-close+)))
(defun skip-to-expression (input)
"Skips whitespace and comments in INPUT, return nil when end of file is
reached."
(skip-whitespace input)
(skip-comment input)
(let ((next-char (peek-char* input)))
(if (or (comment-open-p next-char)
(whitespace-p next-char))
(skip-to-expression input)
(when next-char t))))
;;; Parsing functions
(defun parse-sexp (input)
"Parses an s-expression from stream INPUT."
(unless (char= +list-open+ (read-char input))
(error "Invalid input."))
(read-delimited-list +list-close+ input))
(defun parse (input)
"Parses an abstract source tree from stream INPUT."
(let (ast)
(loop do
(if (skip-to-expression input)
(push (parse-sexp input) ast)
(return (reverse ast))))))