##// END OF EJS Templates
A few parser fixes
naryl -
r13:f0a3bfeb default
parent child Browse files
Show More
@@ -1,44 +1,44 b''
1 (инструкции на Русском - внизу)
1 (инструкции на Русском - внизу)
2
2
3 # sugar-qsp
3 # sugar-qsp
4 Compiler for QSP games which creates monolithic HTML pages.
4 Compiler for QSP games which creates monolithic HTML pages.
5
5
6 ## Usage
6 ## Usage
7
7
8 There are three mastery levels
8 There are three mastery levels
9
9
10 1. Just build me the game:<br/>
10 1. Just build me the game:<br/>
11 `sugar-qsp game.txt`<br/>
11 `sugar-qsp game.txt`<br/>
12 And it will create the game in game.html
12 And it will create the game in game.html
13
13
14 2. I know what I'm doing:<br/>
14 2. I know what I'm doing:<br/>
15 `sugar-qsp game.txt -o game.html --body body.html --js jquery.js my-js-library.js --css styles/*.css`<br/>
15 `sugar-qsp game.txt -o game.html --body body.html --js jquery.js my-js-library.js --css styles/*.css`<br/>
16 All options are self-explanatory. The result is a monolithic html specified
16 All options are self-explanatory. The result is a monolithic html specified
17 with the `-o` option. Default `body.html` (used by the first mastery level) can
17 with the `-o` option. Default `body.html` (used by the first mastery level) can
18 be found in `extas` directory.
18 be found in `extas` directory.
19
19
20 3. I'm a frontend developer!<br/>
20 3. I'm a frontend developer!<br/>
21 `sugar-qsp game.txt -c -o game.js`<br/>
21 `sugar-qsp game.txt -c -o game.js`<br/>
22 It just builds the game script into a js you can put on your website. To run
22 It just builds the game script into a js you can put on your website. To run
23 the game execute `SugarQSP.start()`
23 the game execute `SugarQSP.start()`
24
24
25 # sugar-qsp
25 # sugar-qsp
26 Компилятор для игр на QSP создающий монолитные страницы на HTML.
26 Компилятор для игр на QSP создающий монолитные страницы на HTML.
27
27
28 ## Инструкции
28 ## Инструкции
29
29
30 Есть три уровня мастерства.
30 Есть три уровня мастерства.
31
31
32 1. **Просто собери мне игру**:<br/>
32 1. **Просто собери мне игру**:<br/>
33 `sugar-qsp game.txt`<br/>
33 `sugar-qsp game.txt`<br/>
34 Создаст игру в game.html
34 Создаст игру в game.html
35
35
36 2. **Я знаю что делаю**:<br/>
36 2. **Я знаю что делаю**:<br/>
37 `sugar-qsp game.txt -o game.html --body body.html --js jquery.js my-js-library.js --css styles/*.css`<br/>
37 `sugar-qsp game.txt -o game.html --body body.html --js jquery.js my-js-library.js --css styles/*.css`<br/>
38 Если вы знаете что делаете, то для вас смысл опций очевиден. `body.html`
38 Если вы знаете что делаете, то для вас смысл опций очевиден. `body.html` и `default.css`
39 по-умолчанию лежит в каталоге `extras`.
39 лежат в каталоге `extras`.
40
40
41 3. **Я - фронтендер!**<br/>
41 3. **Я - фронтендер!**<br/>
42 `sugar-qsp game.txt -c -o game.js`<br/>
42 `sugar-qsp game.txt -c -o game.js`<br/>
43 Просто соберёт игру в Javascript файл который вы можете разместить на своём
43 Просто соберёт игру в Javascript файл который вы можете разместить на своём
44 сайте как вам угодно. Для запуска игры вызовите `SugarQSP.start()`.
44 сайте как вам угодно.
@@ -1,140 +1,144 b''
1
1
2 (in-package sugar-qsp)
2 (in-package sugar-qsp)
3
3
4 ;;;; Macros implementing some intrinsics where it makes sense
4 ;;;; Macros implementing some intrinsics where it makes sense
5 ;;;; E.g. an equivalent JS function exists, or it's a direct API call
5 ;;;; E.g. an equivalent JS function exists, or it's a direct API call
6
6
7 ;;; 1loc
7 ;;; 1loc
8
8
9 ;;; 2var
9 ;;; 2var
10
10
11 (ps:defpsmacro killvar (varname &optional (index :whole))
11 (ps:defpsmacro killvar (varname &optional (index :whole))
12 `(api-call kill-var ,varname ,index))
12 `(api-call kill-var ,varname ,index))
13
13
14 (ps:defpsmacro killall ()
14 (ps:defpsmacro killall ()
15 `(api-call kill-all))
15 `(api-call kill-all))
16
16
17 ;;; 3expr
17 ;;; 3expr
18
18
19 (ps:defpsmacro obj (name)
19 (ps:defpsmacro obj (name)
20 `(funcall (root objs includes) ,name))
20 `(funcall (root objs includes) ,name))
21
21
22 (ps:defpsmacro loc (name)
22 (ps:defpsmacro loc (name)
23 `(funcall (root locs includes) ,name))
23 `(funcall (root locs includes) ,name))
24
24
25 (ps:defpsmacro no (arg)
25 (ps:defpsmacro no (arg)
26 `(- -1 ,arg))
26 `(- -1 ,arg))
27
27
28 ;;; 4code
28 ;;; 4code
29
29
30 (ps:defpsmacro qspver ()
30 (ps:defpsmacro qspver ()
31 "0.0.1")
31 "0.0.1")
32
32
33 (ps:defpsmacro curloc ()
33 (ps:defpsmacro curloc ()
34 `(root current-location))
34 `(root current-location))
35
35
36 (ps:defpsmacro rnd ()
36 (ps:defpsmacro rnd ()
37 `(funcall (root lib rand) 1 1000))
37 `(funcall (root lib rand) 1 1000))
38
38
39 (ps:defpsmacro qspmax (&rest args)
39 (ps:defpsmacro qspmax (&rest args)
40 `(max ,@args))
40 (if (= 1 (length args))
41 `(*math.max.apply nil ,@args)
42 `(*math.max ,@args)))
41
43
42 (ps:defpsmacro qspmin (&rest args)
44 (ps:defpsmacro qspmin (&rest args)
43 `(min ,@args))
45 (if (= 1 (length args))
46 `(*math.min.apply nil ,@args)
47 `(*math.min ,@args)))
44
48
45 ;;; 5arrays
49 ;;; 5arrays
46
50
47 (ps:defpsmacro arrsize (name)
51 (ps:defpsmacro arrsize (name)
48 `(api-call array-size ,name))
52 `(api-call array-size ,name))
49
53
50 ;;; 6str
54 ;;; 6str
51
55
52 (ps:defpsmacro len (s)
56 (ps:defpsmacro len (s)
53 `(length ,s))
57 `(length ,s))
54
58
55 (ps:defpsmacro mid (s from &optional count)
59 (ps:defpsmacro mid (s from &optional count)
56 `(ps:chain ,s (substring ,from ,count)))
60 `(ps:chain ,s (substring ,from ,count)))
57
61
58 (ps:defpsmacro ucase (s)
62 (ps:defpsmacro ucase (s)
59 `(ps:chain ,s (to-upper-case)))
63 `(ps:chain ,s (to-upper-case)))
60
64
61 (ps:defpsmacro lcase (s)
65 (ps:defpsmacro lcase (s)
62 `(ps:chain ,s (to-lower-case)))
66 `(ps:chain ,s (to-lower-case)))
63
67
64 (ps:defpsmacro trim (s)
68 (ps:defpsmacro trim (s)
65 `(ps:chain ,s (trim)))
69 `(ps:chain ,s (trim)))
66
70
67 (ps:defpsmacro replace (s from to)
71 (ps:defpsmacro replace (s from to)
68 `(ps:chain ,s (replace ,from ,to)))
72 `(ps:chain ,s (replace ,from ,to)))
69
73
70 (ps:defpsmacro val (s)
74 (ps:defpsmacro val (s)
71 `(parse-int ,s 10))
75 `(parse-int ,s 10))
72
76
73 (ps:defpsmacro qspstr (n)
77 (ps:defpsmacro qspstr (n)
74 `(ps:chain ,n (to-string)))
78 `(ps:chain ,n (to-string)))
75
79
76 ;;; 7if
80 ;;; 7if
77
81
78 ;;; 8sub
82 ;;; 8sub
79
83
80 ;;; 9loops
84 ;;; 9loops
81
85
82 ;; JUMP is in ps-macros.lisp (because it's a part of a huge kludge)
86 ;; JUMP is in ps-macros.lisp (because it's a part of a huge kludge)
83
87
84 (ps:defpsmacro exit ()
88 (ps:defpsmacro exit ()
85 `(return-from nil (values)))
89 `(return-from nil (values)))
86
90
87 ;;; 10dynamic
91 ;;; 10dynamic
88
92
89 ;;; 11main
93 ;;; 11main
90
94
91 (ps:defpsmacro desc (s)
95 (ps:defpsmacro desc (s)
92 (declare (ignore s))
96 (declare (ignore s))
93 "")
97 "")
94
98
95 ;;; 12stat
99 ;;; 12stat
96
100
97 (ps:defpsmacro showstat (enable)
101 (ps:defpsmacro showstat (enable)
98 `(api-call enable-frame :stat ,enable))
102 `(api-call enable-frame :stat ,enable))
99
103
100 ;;; 13diag
104 ;;; 13diag
101
105
102 (ps:defpsmacro msg (text)
106 (ps:defpsmacro msg (text)
103 `(alert ,text))
107 `(alert ,text))
104
108
105 ;;; 14act
109 ;;; 14act
106
110
107 (ps:defpsmacro showacts (enable)
111 (ps:defpsmacro showacts (enable)
108 `(api-call enable-frame :acts ,enable))
112 `(api-call enable-frame :acts ,enable))
109
113
110 (ps:defpsmacro delact (name)
114 (ps:defpsmacro delact (name)
111 `(api-call del-act ,name))
115 `(api-call del-act ,name))
112
116
113 (ps:defpsmacro cla ()
117 (ps:defpsmacro cla ()
114 `(api-call clear-act))
118 `(api-call clear-act))
115
119
116 ;;; 15objs
120 ;;; 15objs
117
121
118 (ps:defpsmacro showobjs (enable)
122 (ps:defpsmacro showobjs (enable)
119 `(api-call enable-frame :objs ,enable))
123 `(api-call enable-frame :objs ,enable))
120
124
121 (ps:defpsmacro countobj ()
125 (ps:defpsmacro countobj ()
122 `(length (root objs)))
126 `(length (root objs)))
123
127
124 (ps:defpsmacro getobj (index)
128 (ps:defpsmacro getobj (index)
125 `(or (elt (root objs) ,index) ""))
129 `(or (elt (root objs) ,index) ""))
126
130
127 ;;; 16menu
131 ;;; 16menu
128
132
129 ;;; 17sound
133 ;;; 17sound
130
134
131 (ps:defpsmacro isplay (filename)
135 (ps:defpsmacro isplay (filename)
132 `(funcall (root playing includes) ,filename))
136 `(funcall (root playing includes) ,filename))
133
137
134 ;;; 18img
138 ;;; 18img
135
139
136 ;;; 19input
140 ;;; 19input
137
141
138 ;;; 20time
142 ;;; 20time
139
143
140 ;;; misc
144 ;;; misc
@@ -1,571 +1,580 b''
1
1
2 (in-package sugar-qsp)
2 (in-package sugar-qsp)
3
3
4 ;;;; Parses TXT source to an intermediate representation
4 ;;;; Parses TXT source to an intermediate representation
5
5
6 ;;; Utility
6 ;;; Utility
7
7
8 (defun remove-nth (list nth)
8 (defun remove-nth (list nth)
9 (append (subseq list 0 nth)
9 (append (subseq list 0 nth)
10 (subseq list (1+ nth))))
10 (subseq list (1+ nth))))
11
11
12 (defun not-quote (char)
12 (defun not-quote (char)
13 (not (eql #\' char)))
13 (not (eql #\' char)))
14
14
15
15
16 (defun not-doublequote (char)
16 (defun not-doublequote (char)
17 (not (eql #\" char)))
17 (not (eql #\" char)))
18
18
19 (defun not-brace (char)
19 (defun not-brace (char)
20 (not (eql #\} char)))
20 (not (eql #\} char)))
21
21
22 (defun not-integer (string)
22 (defun not-integer (string)
23 (when (find-if-not #'digit-char-p string)
23 (when (find-if-not #'digit-char-p string)
24 t))
24 t))
25
25
26 (defun not-newline (char)
26 (defun not-newline (char)
27 (not (eql #\newline char)))
27 (not (eql #\newline char)))
28
28
29 (defun id-any-char (char)
29 (defun id-any-char (char)
30 (and
30 (and
31 (not (digit-char-p char))
31 (not (digit-char-p char))
32 (not (eql #\newline char))
32 (not (eql #\newline char))
33 (not (find char " !:&=<>+-*/,'\"()[]{}"))))
33 (not (find char " !:&=<>+-*/,'\"()[]{}"))))
34
34
35 (defun intern-first (list)
35 (defun intern-first (list)
36 (list* (intern (string-upcase (first list)))
36 (list* (intern (string-upcase (first list)))
37 (rest list)))
37 (rest list)))
38
38
39 (eval-when (:compile-toplevel :load-toplevel :execute)
39 (eval-when (:compile-toplevel :load-toplevel :execute)
40 (defun remove-nil (list)
40 (defun remove-nil (list)
41 (remove nil list)))
41 (remove nil list)))
42
42
43 (defun binop-rest (list)
43 (defun binop-rest (list)
44 (destructuring-bind (ws1 operator ws2 operand2)
44 (destructuring-bind (ws1 operator ws2 operand2)
45 list
45 list
46 (declare (ignore ws1 ws2))
46 (declare (ignore ws1 ws2))
47 (list (intern (string-upcase operator)) operand2)))
47 (list (intern (string-upcase operator)) operand2)))
48
48
49 (defun do-binop% (left-op other-ops)
49 (defun do-binop% (left-op other-ops)
50 (if (null other-ops)
50 (if (null other-ops)
51 left-op
51 left-op
52 (destructuring-bind ((operator right-op) &rest rest-ops)
52 (destructuring-bind ((operator right-op) &rest rest-ops)
53 other-ops
53 other-ops
54 (if (and (listp left-op)
54 (if (and (listp left-op)
55 (eq (first left-op)
55 (eq (first left-op)
56 operator))
56 operator))
57 (do-binop% (append left-op (list right-op)) rest-ops)
57 (do-binop% (append left-op (list right-op)) rest-ops)
58 (do-binop% (list operator left-op right-op) rest-ops)))))
58 (do-binop% (list operator left-op right-op) rest-ops)))))
59
59
60 (defun do-binop (list)
60 (defun do-binop (list)
61 (destructuring-bind (left-op rest-ops)
61 (destructuring-bind (left-op rest-ops)
62 list
62 list
63 (do-binop% left-op
63 (do-binop% left-op
64 (mapcar #'binop-rest rest-ops))))
64 (mapcar #'binop-rest rest-ops))))
65
65
66 (p:defrule line-continuation (and #\_ #\newline)
66 (p:defrule line-continuation (and #\_ #\newline)
67 (:constant nil))
67 (:constant nil))
68
68
69 (p:defrule text-spaces (+ (or #\space #\tab line-continuation))
69 (p:defrule text-spaces (+ (or #\space #\tab line-continuation))
70 (:text t))
70 (:text t))
71
71
72 (p:defrule spaces (+ (or #\space #\tab line-continuation))
72 (p:defrule spaces (+ (or #\space #\tab line-continuation))
73 (:constant nil))
73 (:constant nil))
74
74
75 (p:defrule spaces? (* (or #\space #\tab line-continuation))
75 (p:defrule spaces? (* (or #\space #\tab line-continuation))
76 (:constant nil))
76 (:constant nil))
77
77
78 (p:defrule colon #\:
78 (p:defrule colon #\:
79 (:constant nil))
79 (:constant nil))
80
80
81 (p:defrule alphanumeric (alphanumericp character))
81 (p:defrule alphanumeric (alphanumericp character))
82
82
83 (p:defrule not-newline (not-newline character))
83 (p:defrule not-newline (not-newline character))
84
84
85 (p:defrule squote-esc "''"
85 (p:defrule squote-esc "''"
86 (:lambda (list)
86 (:lambda (list)
87 (p:text (elt list 0))))
87 (p:text (elt list 0))))
88
88
89 (p:defrule dquote-esc "\"\""
89 (p:defrule dquote-esc "\"\""
90 (:lambda (list)
90 (:lambda (list)
91 (p:text (elt list 0))))
91 (p:text (elt list 0))))
92
92
93 (p:defrule sstring-chars (+ (and (and (p:! "<<") (p:! (p:~ "\"exec:")))
93 (p:defrule sstring-chars (+ (and (and (p:! "<<") (p:! (p:~ "\"exec:")))
94 (or squote-esc (not-quote character))))
94 (or squote-esc (not-quote character))))
95 (:lambda (list)
95 (:lambda (list)
96 (p:text (mapcar #'second list))))
96 (p:text (mapcar #'second list))))
97
97
98 (p:defrule dstring-chars (+ (and (and (p:! "<<") (p:! (p:~ "'exec:")))
98 (p:defrule dstring-chars (+ (and (and (p:! "<<") (p:! (p:~ "'exec:")))
99 (or dquote-esc (not-doublequote character))))
99 (or dquote-esc (not-doublequote character))))
100 (:lambda (list)
100 (:lambda (list)
101 (p:text (mapcar #'second list))))
101 (p:text (mapcar #'second list))))
102
102
103 ;;; Identifiers
103 ;;; Identifiers
104
104
105 ;; From the official docs
105 ;; From the official docs
106 (defparameter *keywords* '(act addlib addobj addqst and arrcomp arrpos arrsize cla clear *clear close clr *clr cls cmdclear cmdclr copyarr $counter countobj $curacts curloc debug delact dellib delobj desc disablescroll disablesubex dynamic dyneval else elseif end exit fcolor $fname freelib fsize func getobj gosub goto gs gt if iif inclib input instr isnum isplay jump killall killobj killqst killvar lcase lcolor len let loc $maintxt max menu mid min mod msecscount msg nl *nl no nosave obj $onactsel $ongload $ongsave $onnewloc $onobjadd $onobjdel $onobjsel opengame openqst or p *p pl *pl play qspver rand refint replace rgb rnd savegame selact selobj set settimer showacts showinput showobjs showstat $stattxt str strcomp strfind strpos trim ucase unsel unselect $usercom user_text usrtxt val view wait xgoto xgt))
106 (defparameter *keywords* '(act addlib addobj addqst and arrcomp arrpos arrsize cla clear *clear close clr *clr cls cmdclear cmdclr copyarr counter countobj curacts curloc debug delact dellib delobj desc disablescroll disablesubex dynamic dyneval else elseif end exit fcolor fname freelib fsize func getobj gosub goto gs gt if iif inclib input instr isnum isplay jump killall killobj killqst killvar lcase lcolor len let loc maintxt max menu mid min mod msecscount msg nl *nl no nosave obj onactsel ongload ongsave onnewloc onobjadd onobjdel onobjsel opengame openqst or p *p pl *pl play qspver rand refint replace rgb rnd savegame selact selobj set settimer showacts showinput showobjs showstat stattxt str strcomp strfind strpos trim ucase unsel unselect usercom user_text usrtxt val view wait xgoto xgt))
107
108 (defun trim-$ (str)
109 (if (char= #\$ (elt str 0))
110 (subseq str 1)
111 str))
107
112
108 (defun qsp-keyword-p (id)
113 (defun qsp-keyword-p (id)
109 (member (intern (string-upcase id)) *keywords*))
114 (member (intern (trim-$ (string-upcase id))) *keywords*))
110
115
111 (defun not-qsp-keyword-p (id)
116 (defun not-qsp-keyword-p (id)
112 (not (member (intern (string-upcase id)) *keywords*)))
117 (not (member (intern (trim-$ (string-upcase id))) *keywords*)))
113
118
114 (p:defrule qsp-keyword (qsp-keyword-p identifier-raw))
119 (p:defrule qsp-keyword (qsp-keyword-p identifier-raw))
115
120
116 (p:defrule id-first (id-any-char character))
121 (p:defrule id-first (id-any-char character))
117 (p:defrule id-next (or (id-any-char character)
122 (p:defrule id-next (or (id-any-char character)
118 (digit-char-p character)))
123 (digit-char-p character)))
119 (p:defrule identifier-raw (and id-first (* id-next))
124 (p:defrule identifier-raw (and id-first (* id-next))
120 (:lambda (list)
125 (:lambda (list)
121 (let ((id (p:text list)))
126 (intern (string-upcase (p:text list)))))
122 (when (member id *keywords*)
123 (error "~A is a keyword" id))
124 (intern (string-upcase id)))))
125
127
126 (p:defrule identifier (not-qsp-keyword-p identifier-raw))
128 (p:defrule identifier (not-qsp-keyword-p identifier-raw))
127
129
128 ;;; Strings
130 ;;; Strings
129
131
130 (p:defrule qsp-string (or normal-string brace-string))
132 (p:defrule qsp-string (or normal-string brace-string))
131
133
132 (p:defrule normal-string (or sstring dstring)
134 (p:defrule normal-string (or sstring dstring)
133 (:lambda (str)
135 (:lambda (str)
134 (list* 'str (or str (list "")))))
136 (list* 'str (or str (list "")))))
135
137
136 (p:defrule sstring (and #\' (* (or string-interpol
138 (p:defrule sstring (and #\' (* (or string-interpol
137 sstring-exec
139 sstring-exec
138 sstring-chars))
140 sstring-chars))
139 #\')
141 #\')
140 (:function second))
142 (:function second))
141
143
142 (p:defrule dstring (and #\" (* (or string-interpol
144 (p:defrule dstring (and #\" (* (or string-interpol
143 dstring-exec
145 dstring-exec
144 dstring-chars))
146 dstring-chars))
145 #\")
147 #\")
146 (:function second))
148 (:function second))
147
149
148 (p:defrule string-interpol (and "<<" expression ">>")
150 (p:defrule string-interpol (and "<<" expression ">>")
149 (:function second))
151 (:function second))
150
152
151 (p:defrule sstring-exec-body (+ (or squote-esc (not-doublequote character)))
153 (p:defrule sstring-exec-body (+ (or squote-esc (not-doublequote character)))
152 (:text t))
154 (:text t))
153
155
154 (p:defrule dstring-exec-body (+ (or dquote-esc (not-quote character)))
156 (p:defrule dstring-exec-body (+ (or dquote-esc (not-quote character)))
155 (:text t))
157 (:text t))
156
158
157 (p:defrule sstring-exec (and (p:~ "\"exec:") sstring-exec-body #\")
159 (p:defrule sstring-exec (and (p:~ "\"exec:") sstring-exec-body #\")
158 (:lambda (list)
160 (:lambda (list)
159 (list* 'exec (p:parse 'exec-body (second list)))))
161 (list* 'exec (p:parse 'exec-body (second list)))))
160
162
161 (p:defrule dstring-exec (and (p:~ "'exec:") dstring-exec-body #\')
163 (p:defrule dstring-exec (and (p:~ "'exec:") dstring-exec-body #\')
162 (:lambda (list)
164 (:lambda (list)
163 (list* 'exec (p:parse 'exec-body (second list)))))
165 (list* 'exec (p:parse 'exec-body (second list)))))
164
166
165 (p:defrule brace-string (and #\{ before-statement block-body #\})
167 (p:defrule brace-string (and #\{ before-statement block-body #\})
166 (:lambda (list)
168 (:lambda (list)
167 (list* 'qspblock (third list))))
169 (list* 'qspblock (third list))))
168
170
169 ;;; Location
171 ;;; Location
170
172
171 (p:defrule sugar-qsp-grammar (and (* (or spaces #\newline))
173 (p:defrule sugar-qsp-grammar (and (* (or spaces #\newline))
172 (* location))
174 (* location))
173 (:function second))
175 (:function second))
174
176
175 (p:defrule location (and location-header block-body location-end)
177 (p:defrule location (and location-header block-body location-end)
176 (:destructure (header body end)
178 (:destructure (header body end)
177 (declare (ignore end))
179 (declare (ignore end))
178 `(location (,header) ,@body)))
180 `(location (,header) ,@body)))
179
181
180 (p:defrule location-header (and #\#
182 (p:defrule location-header (and #\#
181 (+ not-newline)
183 (+ not-newline)
182 (and #\newline spaces? before-statement))
184 (and #\newline spaces? before-statement))
183 (:destructure (spaces1 name spaces2)
185 (:destructure (spaces1 name spaces2)
184 (declare (ignore spaces1 spaces2))
186 (declare (ignore spaces1 spaces2))
185 (string-upcase (string-trim " " (p:text name)))))
187 (string-upcase (string-trim " " (p:text name)))))
186
188
187 (p:defrule location-end (and #\- (* not-newline) #\newline before-statement)
189 (p:defrule location-end (and #\- (* not-newline) #\newline before-statement)
188 (:constant nil))
190 (:constant nil))
189
191
190 ;;; Block body
192 ;;; Block body
191
193
192 (p:defrule newline-block-body (and #\newline spaces? block-body)
194 (p:defrule newline-block-body (and #\newline spaces? block-body)
193 (:function third))
195 (:function third))
194
196
195 (p:defrule block-body (* statement)
197 (p:defrule block-body (* statement)
196 (:function remove-nil))
198 (:function remove-nil))
197
199
198 ;; Just for <a href="exec:...'>
200 ;; Just for <a href="exec:...'>
199 ;; Explicitly called from that rule's production
201 ;; Explicitly called from that rule's production
200 (p:defrule exec-body (and before-statement line-body)
202 (p:defrule exec-body (and before-statement line-body)
201 (:function second))
203 (:function second))
202
204
203 (p:defrule line-body (and inline-statement (* next-inline-statement))
205 (p:defrule line-body (and inline-statement (* next-inline-statement))
204 (:lambda (list)
206 (:lambda (list)
205 (list* (first list) (second list))))
207 (list* (first list) (second list))))
206
208
207 (p:defrule before-statement (* (or #\newline spaces))
209 (p:defrule before-statement (* (or #\newline spaces))
208 (:constant nil))
210 (:constant nil))
209
211
210 (p:defrule statement-end (or statement-end-real statement-end-block-close))
212 (p:defrule statement-end (or statement-end-real statement-end-block-close))
211
213
212 (p:defrule statement-end-real (and (or #\newline
214 (p:defrule statement-end-real (and (or #\newline
213 (and #\& spaces? (p:& statement%)))
215 (and #\& spaces? (p:& statement%)))
214 before-statement)
216 before-statement)
215 (:constant nil))
217 (:constant nil))
216
218
217 (p:defrule statement-end-block-close (or (p:& #\}))
219 (p:defrule statement-end-block-close (or (p:& #\}))
218 (:constant nil))
220 (:constant nil))
219
221
220 (p:defrule inline-statement (and statement% spaces?)
222 (p:defrule inline-statement (and statement% spaces?)
221 (:function first))
223 (:function first))
222
224
223 (p:defrule next-inline-statement (and #\& spaces? inline-statement)
225 (p:defrule next-inline-statement (and #\& spaces? inline-statement)
224 (:function third))
226 (:function third))
225
227
226 (p:defrule not-a-non-statement (and (p:! (p:~ "elseif"))
228 (p:defrule not-a-non-statement (and (p:! (p:~ "elseif"))
227 (p:! (p:~ "else"))
229 (p:! (p:~ "else"))
228 (p:! (p:~ "end"))))
230 (p:! (p:~ "end"))))
229
231
230 (p:defrule statement (and inline-statement statement-end)
232 (p:defrule statement (and inline-statement statement-end)
231 (:function first))
233 (:function first))
232
234
233 (p:defrule statement% (and not-a-non-statement
235 (p:defrule statement% (and not-a-non-statement
234 (or label comment string-output
236 (or label comment string-output
235 block non-returning-intrinsic assignment
237 block non-returning-intrinsic assignment
236 expression-output))
238 expression-output))
237 (:function second))
239 (:function second))
238
240
239 (p:defrule expr-stopper (or comment block non-returning-intrinsic))
241 (p:defrule expr-stopper (or comment block non-returning-intrinsic))
240
242
241 (p:defrule string-output qsp-string
243 (p:defrule string-output qsp-string
242 (:lambda (string)
244 (:lambda (string)
243 (list 'main-pl string)))
245 (list 'main-pl string)))
244
246
245 (p:defrule expression-output expression
247 (p:defrule expression-output expression
246 (:lambda (list)
248 (:lambda (list)
247 (list 'main-pl list)))
249 (list 'main-pl list)))
248
250
249 (p:defrule label (and colon identifier)
251 (p:defrule label (and colon identifier)
250 (:lambda (list)
252 (:lambda (list)
251 (intern (string (second list)) :keyword)))
253 (intern (string (second list)) :keyword)))
252
254
253 (p:defrule comment (and #\! (* (or text-spaces qsp-string brace-string not-newline)))
255 (p:defrule comment (and #\! (* (or qsp-string brace-comment text-spaces not-newline)))
256 (:constant nil))
257
258 (p:defrule brace-comment (and #\{ (* (not-brace character)) #\})
254 (:constant nil))
259 (:constant nil))
255
260
256 ;;; Blocks
261 ;;; Blocks
257
262
258 (p:defrule block (or block-act block-if))
263 (p:defrule block (or block-act block-if))
259
264
260 (p:defrule block-if (and block-if-head block-if-body)
265 (p:defrule block-if (and block-if-head block-if-body)
261 (:destructure (head body)
266 (:destructure (head body)
262 `(qspcond (,@head ,@(first body))
267 `(qspcond (,@head ,@(first body))
263 ,@(rest body))))
268 ,@(rest body))))
264
269
265 (p:defrule block-if-head (and (p:~ "if") spaces expression spaces? colon spaces?)
270 (p:defrule block-if-head (and (p:~ "if") spaces expression spaces? colon spaces?)
266 (:function remove-nil)
271 (:function remove-nil)
267 (:function cdr))
272 (:function cdr))
268
273
269 (p:defrule block-if-body (or block-if-ml block-if-sl)
274 (p:defrule block-if-body (or block-if-ml block-if-sl)
270 (:destructure (if-body elseifs else &rest ws)
275 (:destructure (if-body elseifs else &rest ws)
271 (declare (ignore ws))
276 (declare (ignore ws))
272 `(,(remove-nil if-body) ,@elseifs ,@(when else `((else ,@else))))))
277 `(,(remove-nil if-body) ,@elseifs ,@(when else `((else ,@else))))))
273
278
274 (p:defrule block-if-sl (and line-body
279 (p:defrule block-if-sl (and line-body
275 (p:? block-if-elseif-inline)
280 (p:? block-if-elseif-inline)
276 (p:? block-if-else-inline)
281 (p:? block-if-else-inline)
277 spaces?))
282 spaces?))
278
283
279 (p:defrule block-if-ml (and (and #\newline spaces?)
284 (p:defrule block-if-ml (and (and #\newline spaces?)
280 block-body
285 block-body
281 (p:? block-if-elseif)
286 (p:? block-if-elseif)
282 (p:? block-if-else)
287 (p:? block-if-else)
283 block-if-end)
288 block-if-end)
284 (:lambda (list)
289 (:lambda (list)
285 (cdr list)))
290 (cdr list)))
286
291
287 (p:defrule block-if-elseif-inline (and block-if-elseif-head line-body (p:? block-if-elseif-inline))
292 (p:defrule block-if-elseif-inline (and block-if-elseif-head line-body (p:? block-if-elseif-inline))
288 (:destructure (head statements elseif)
293 (:destructure (head statements elseif)
289 `((,@(rest head) ,@(remove-nil statements)) ,@elseif)))
294 `((,@(rest head) ,@(remove-nil statements)) ,@elseif)))
290
295
291 (p:defrule block-if-elseif (and block-if-elseif-head statement-end block-body (p:? block-if-elseif))
296 (p:defrule block-if-elseif (and block-if-elseif-head statement-end block-body (p:? block-if-elseif))
292 (:destructure (head ws statements elseif)
297 (:destructure (head ws statements elseif)
293 (declare (ignore ws))
298 (declare (ignore ws))
294 `((,@(rest head) ,@(remove-nil statements)) ,@elseif)))
299 `((,@(rest head) ,@(remove-nil statements)) ,@elseif)))
295
300
296 (p:defrule block-if-elseif-head (and (p:~ "elseif") spaces expression spaces? colon spaces?)
301 (p:defrule block-if-elseif-head (and (p:~ "elseif") spaces expression spaces? colon spaces?)
297 (:function remove-nil)
302 (:function remove-nil)
298 (:function intern-first))
303 (:function intern-first))
299
304
300 (p:defrule block-if-else-inline (and block-if-else-head line-body)
305 (p:defrule block-if-else-inline (and block-if-else-head line-body)
301 (:function second))
306 (:function second))
302
307
303 (p:defrule block-if-else (and block-if-else-head #\newline spaces? block-body)
308 (p:defrule block-if-else (and block-if-else-head #\newline spaces? block-body)
304 (:function fourth))
309 (:function fourth))
305
310
306 (p:defrule block-if-else-head (and (p:~ "else") spaces?)
311 (p:defrule block-if-else-head (and (p:~ "else") spaces?)
307 (:constant nil))
312 (:constant nil))
308
313
309 (p:defrule block-if-end (and (p:~ "end")
314 (p:defrule block-if-end (and (p:~ "end")
310 (p:? (and spaces (p:~ "if"))))
315 (p:? (and spaces (p:~ "if"))))
311 (:constant nil))
316 (:constant nil))
312
317
313 (p:defrule block-act (and block-act-head (or block-act-ml block-act-sl))
318 (p:defrule block-act (and block-act-head (or block-act-ml block-act-sl))
314 (:lambda (list)
319 (:lambda (list)
315 (apply #'append list)))
320 (apply #'append list)))
316
321
317 (p:defrule block-act-sl line-body)
322 (p:defrule block-act-sl line-body)
318
323
319 (p:defrule block-act-ml (and newline-block-body block-act-end)
324 (p:defrule block-act-ml (and newline-block-body block-act-end)
320 (:lambda (list)
325 (:lambda (list)
321 (apply #'list* (butlast list))))
326 (apply #'list* (butlast list))))
322
327
323 (p:defrule block-act-head (and (p:~ "act") spaces qsp-string spaces?
328 (p:defrule block-act-head (and (p:~ "act") spaces qsp-string spaces?
324 (p:? block-act-head-img)
329 (p:? block-act-head-img)
325 colon spaces?)
330 colon spaces?)
326 (:lambda (list)
331 (:lambda (list)
327 (intern-first (list (first list)
332 (intern-first (list (first list)
328 (third list)
333 (third list)
329 (or (fifth list) '(str ""))))))
334 (or (fifth list) '(str ""))))))
330
335
331 (p:defrule block-act-head-img (and #\, spaces? qsp-string spaces?)
336 (p:defrule block-act-head-img (and #\, spaces? qsp-string spaces?)
332 (:lambda (list)
337 (:lambda (list)
333 (or (third list) "")))
338 (or (third list) "")))
334
339
335 (p:defrule block-act-end (and (p:~ "end"))
340 (p:defrule block-act-end (and (p:~ "end"))
336 (:constant nil))
341 (:constant nil))
337
342
338 ;;; Calls
343 ;;; Calls
339
344
340 (p:defrule first-argument (and expression spaces?)
345 (p:defrule first-argument (and expression spaces?)
341 (:function first))
346 (:function first))
342 (p:defrule next-argument (and "," spaces? expression)
347 (p:defrule next-argument (and "," spaces? expression)
343 (:function third))
348 (:function third))
344 (p:defrule arguments (or parenthesized-arguments plain-arguments no-arguments))
349 (p:defrule arguments (or parenthesized-arguments plain-arguments no-arguments))
345 (p:defrule parenthesized-arguments (and spaces? #\( base-arguments #\))
350 (p:defrule parenthesized-arguments (and spaces? #\( base-arguments #\))
346 (:function third))
351 (:function third))
347 (p:defrule plain-arguments (and spaces base-arguments)
352 (p:defrule plain-arguments (and spaces base-arguments)
348 (:function second))
353 (:function second))
349 (p:defrule no-arguments (or spaces (p:& #\newline) (p:& #\&))
354 (p:defrule no-arguments (or (and spaces? (p:& #\newline))
355 (and spaces? (p:& #\&))
356 spaces?)
350 (:constant nil))
357 (:constant nil))
351 (p:defrule base-arguments (and first-argument (* next-argument))
358 (p:defrule base-arguments (or (and first-argument (* next-argument)) spaces?)
352 (:destructure (first rest)
359 (:lambda (list)
353 (list* first rest)))
360 (if (null list)
361 nil
362 (list* (first list) (second list)))))
354
363
355 ;;; Intrinsics
364 ;;; Intrinsics
356
365
357 (defmacro defintrinsics ((rule-name returning-rule-name non-returning-rule-name) &body clauses)
366 (defmacro defintrinsics ((rule-name returning-rule-name non-returning-rule-name) &body clauses)
358 `(progn
367 `(progn
359 ,@(loop :for clause :in clauses
368 ,@(loop :for clause :in clauses
360 :collect `(defintrinsic ,@clause))
369 :collect `(defintrinsic ,@clause))
361 (p:defrule ,returning-rule-name (or ,@(remove-nil
370 (p:defrule ,returning-rule-name (or ,@(remove-nil
362 (mapcar (lambda (clause)
371 (mapcar (lambda (clause)
363 (when (second clause)
372 (when (second clause)
364 (alexandria:symbolicate
373 (alexandria:symbolicate
365 'intrinsic- (first clause))))
374 'intrinsic- (first clause))))
366 clauses))))
375 clauses))))
367 (p:defrule ,non-returning-rule-name (or ,@(remove-nil
376 (p:defrule ,non-returning-rule-name (or ,@(remove-nil
368 (mapcar (lambda (clause)
377 (mapcar (lambda (clause)
369 (unless (second clause)
378 (unless (second clause)
370 (alexandria:symbolicate
379 (alexandria:symbolicate
371 'intrinsic- (first clause))))
380 'intrinsic- (first clause))))
372 clauses))))
381 clauses))))
373 (p:defrule ,rule-name (or ,returning-rule-name ,non-returning-rule-name))))
382 (p:defrule ,rule-name (or ,returning-rule-name ,non-returning-rule-name))))
374
383
375 (defmacro defintrinsic (sym returning &optional (min-arity 0) (max-arity 10) &rest names)
384 (defmacro defintrinsic (sym returning &optional (min-arity 0) (max-arity 10) &rest names)
376 (declare (ignore returning))
385 (declare (ignore returning))
377 (setf names
386 (setf names
378 (if names
387 (if names
379 (mapcar #'string-upcase names)
388 (mapcar #'string-upcase names)
380 (list (string sym))))
389 (list (string sym))))
381 `(p:defrule ,(alexandria:symbolicate 'intrinsic- sym)
390 `(p:defrule ,(alexandria:symbolicate 'intrinsic- sym)
382 (and (p:? #\$) (or ,@(loop :for name :in names :collect `(p:~ ,name)))
391 (and (p:? #\$) (or ,@(loop :for name :in names :collect `(p:~ ,name)))
383 arguments)
392 arguments)
384 (:destructure (dollar name arguments)
393 (:destructure (dollar name arguments)
385 (declare (ignore dollar))
394 (declare (ignore dollar))
386 (unless (<= ,min-arity (length arguments) ,max-arity)
395 (unless (<= ,min-arity (length arguments) ,max-arity)
387 (error "Intrinsic ~A expects between ~A and ~A arguments but ~A were provided:~%~S"
396 (error "Intrinsic ~A expects between ~A and ~A arguments but ~A were provided:~%~S"
388 name ,min-arity ,max-arity (length arguments) arguments))
397 name ,min-arity ,max-arity (length arguments) arguments))
389 (list* ',sym arguments))))
398 (list* ',sym arguments))))
390
399
391 (defintrinsics (intrinsic returning-intrinsic non-returning-intrinsic)
400 (defintrinsics (intrinsic returning-intrinsic non-returning-intrinsic)
392 ;; Transitions
401 ;; Transitions
393 (goto nil 0 10 "gt" "goto")
402 (goto nil 0 10 "gt" "goto")
394 (xgoto nil 0 10 "xgt" "xgoto")
403 (xgoto nil 0 10 "xgt" "xgoto")
395 ;; Variables
404 ;; Variables
396 (killvar nil 0 2)
405 (killvar nil 0 2)
397 ;; Expressions
406 ;; Expressions
398 (obj t 1 1)
407 (obj t 1 1)
399 (loc t 1 1)
408 (loc t 1 1)
400 (no t 1 1)
409 (no t 1 1)
401 ;; Basic
410 ;; Basic
402 (qspver t 0 0)
411 (qspver t 0 0)
403 (curloc t 0 0)
412 (curloc t 0 0)
404 (rand t 1 2)
413 (rand t 1 2)
405 (rnd t 0 0)
414 (rnd t 0 0)
406 (qspmax t 1 10 "max")
415 (qspmax t 1 10 "max")
407 (qspmin t 1 10 "min")
416 (qspmin t 1 10 "min")
408 ;; Arrays
417 ;; Arrays
409 (killall nil 0 0)
418 (killall nil 0 0)
410 (copyarr nil 2 4)
419 (copyarr nil 2 4)
411 (arrsize t 1 1)
420 (arrsize t 1 1)
412 (arrpos t 2 3)
421 (arrpos t 2 3)
413 (arrcomp t 2 3)
422 (arrcomp t 2 3)
414 ;; Strings
423 ;; Strings
415 (len t 1 1)
424 (len t 1 1)
416 (mid t 2 3)
425 (mid t 2 3)
417 (ucase t 1 1)
426 (ucase t 1 1)
418 (lcase t 1 1)
427 (lcase t 1 1)
419 (trim t 1 1)
428 (trim t 1 1)
420 (replace t 2 3)
429 (replace t 2 3)
421 (instr t 2 3)
430 (instr t 2 3)
422 (isnum t 1 1)
431 (isnum t 1 1)
423 (val t 1 1)
432 (val t 1 1)
424 (qspstr t 1 1 "str")
433 (qspstr t 1 1 "str")
425 (strcomp t 2 2)
434 (strcomp t 2 2)
426 (strfind t 2 3)
435 (strfind t 2 3)
427 (strpos t 2 3)
436 (strpos t 2 3)
428 ;; IF
437 ;; IF
429 (iif t 2 3)
438 (iif t 2 3)
430 ;; Subs
439 ;; Subs
431 (gosub nil 1 10 "gosub" "gs")
440 (gosub nil 1 10 "gosub" "gs")
432 (func t 1 10)
441 (func t 1 10)
433 (exit nil 0 0)
442 (exit nil 0 0)
434 ;; Jump
443 ;; Jump
435 (jump nil 1 1)
444 (jump nil 1 1)
436 ;; Dynamic
445 ;; Dynamic
437 (dynamic nil 1 10)
446 (dynamic nil 1 10)
438 (dyneval t 1 10)
447 (dyneval t 1 10)
439 ;; Main window
448 ;; Main window
440 (main-p nil 1 1 "*p")
441 (main-pl nil 1 1 "*pl")
449 (main-pl nil 1 1 "*pl")
442 (main-nl nil 0 1 "*nl")
450 (main-nl nil 0 1 "*nl")
451 (main-p nil 1 1 "*p")
443 (maintxt t 0 0)
452 (maintxt t 0 0)
444 (desc t 1 1)
453 (desc t 1 1)
445 (main-clear nil 0 0 "*clear" "*clr")
454 (main-clear nil 0 0 "*clear" "*clr")
446 ;; Aux window
455 ;; Aux window
447 (showstat nil 1 1)
456 (showstat nil 1 1)
448 (stat-p nil 1 1 "p")
449 (stat-pl nil 1 1 "pl")
457 (stat-pl nil 1 1 "pl")
450 (stat-nl nil 0 1 "nl")
458 (stat-nl nil 0 1 "nl")
459 (stat-p nil 1 1 "p")
451 (stattxt t 0 0)
460 (stattxt t 0 0)
452 (stat-clear nil 0 0 "clear" "clr")
461 (stat-clear nil 0 0 "clear" "clr")
453 (cls nil 0 0)
462 (cls nil 0 0)
454 ;; Dialog
463 ;; Dialog
455 (msg nil 1 1)
464 (msg nil 1 1)
456 ;; Acts
465 ;; Acts
457 (showacts nil 1 1)
466 (showacts nil 1 1)
458 (delact nil 1 1 "delact" "del act")
467 (delact nil 1 1 "delact" "del act")
459 (curacts t 0 0)
468 (curacts t 0 0)
460 (cla nil 0 0)
469 (cla nil 0 0)
461 ;; Objects
470 ;; Objects
462 (showobjs nil 1 1)
471 (showobjs nil 1 1)
463 (addobj nil 1 3 "addobj" "add obj")
472 (addobj nil 1 3 "addobj" "add obj")
464 (delobj nil 1 1 "delobj" "del obj")
473 (delobj nil 1 1 "delobj" "del obj")
465 (killobj nil 0 1)
474 (killobj nil 0 1)
466 (countobj t 0 0)
475 (countobj t 0 0)
467 (getobj t 1 1)
476 (getobj t 1 1)
468 ;; Menu
477 ;; Menu
469 (menu nil 1 1)
478 (menu nil 1 1)
470 ;; Sound
479 ;; Sound
471 (play nil 1 2)
480 (play nil 1 2)
472 (isplay t 1 1)
481 (isplay t 1 1)
473 (close nil 1 1)
482 (close nil 1 1)
474 (closeall nil 0 0 "close all")
483 (closeall nil 0 0 "close all")
475 ;; Images
484 ;; Images
476 (refint nil 0 0)
485 (refint nil 0 0)
477 (view nil 0 1)
486 (view nil 0 1)
478 ;; Fonts
487 ;; Fonts
479 (rgb t 3 3)
488 (rgb t 3 3)
480 ;; Input
489 ;; Input
481 (showinput nil 1 1)
490 (showinput nil 1 1)
482 (usertxt t 0 0 "user_text" "usrtxt")
491 (usertxt t 0 0 "user_text" "usrtxt")
483 (cmdclear nil 0 0 "cmdclear" "cmdclr")
492 (cmdclear nil 0 0 "cmdclear" "cmdclr")
484 (input t 1 1)
493 (input t 1 1)
485 ;; Files
494 ;; Files
486 (openqst nil 1 1)
495 (openqst nil 1 1)
487 (addqst nil 1 1 "addqst" "addlib" "inclib")
496 (addqst nil 1 1 "addqst" "addlib" "inclib")
488 (killqst nil 1 1 "killqst" "dellib" "freelib")
497 (killqst nil 1 1 "killqst" "dellib" "freelib")
489 (opengame nil 0 0)
498 (opengame nil 0 0)
490 (savegame nil 0 0)
499 (savegame nil 0 0)
491 ;; Real time
500 ;; Real time
492 (wait nil 1 1)
501 (wait nil 1 1)
493 (msecscount t 0 0)
502 (msecscount t 0 0)
494 (settimer nil 1 1))
503 (settimer nil 1 1))
495
504
496 ;;; Expression
505 ;;; Expression
497
506
498 (p:defrule expression or-expr)
507 (p:defrule expression or-expr)
499
508
500 (p:defrule or-expr (and and-expr (* (and spaces? or-op spaces? and-expr)))
509 (p:defrule or-expr (and and-expr (* (and spaces? or-op spaces? and-expr)))
501 (:function do-binop))
510 (:function do-binop))
502
511
503 (p:defrule and-expr (and eq-expr (* (and spaces? and-op spaces? eq-expr)))
512 (p:defrule and-expr (and eq-expr (* (and spaces? and-op spaces? eq-expr)))
504 (:function do-binop))
513 (:function do-binop))
505
514
506 (p:defrule eq-expr (and cat-expr (* (and spaces? (or "<>" "<=" ">=" "=<" "=>"
515 (p:defrule eq-expr (and sum-expr (* (and spaces? (or "<=" ">=" "=<" "=>" "<>"
507 #\= #\< #\> #\!)
516 "=" "<" ">" "!")
508 spaces? cat-expr)))
517 spaces? cat-expr)))
509 (:function do-binop))
518 (:function do-binop))
510
519
511 (p:defrule cat-expr (and sum-expr (* (and spaces? #\& spaces? (p:! expr-stopper) sum-expr)))
512 (:lambda (list)
513 (do-binop (list (first list) (mapcar (lambda (l)
514 (remove-nth l 3))
515 (second list))))))
516
517 (p:defrule sum-expr (and mod-expr (* (and spaces? (or #\+ #\-) spaces? mod-expr)))
520 (p:defrule sum-expr (and mod-expr (* (and spaces? (or #\+ #\-) spaces? mod-expr)))
518 (:function do-binop))
521 (:function do-binop))
519
522
520 (p:defrule mod-expr (and mul-expr (* (and spaces? (p:~ "mod") spaces? mul-expr)))
523 (p:defrule mod-expr (and mul-expr (* (and spaces? (p:~ "mod") spaces? mul-expr)))
521 (:function do-binop))
524 (:function do-binop))
522
525
523 (p:defrule mul-expr (and unary-expr (* (and spaces? (or #\* #\/) spaces? unary-expr)))
526 (p:defrule mul-expr (and unary-expr (* (and spaces? (or #\* #\/) spaces? unary-expr)))
524 (:function do-binop))
527 (:function do-binop))
525
528
526 (p:defrule unary-expr (and (p:? (or #\+ #\-)) atom-expr)
529 (p:defrule unary-expr (and (p:? (or #\+ #\-)) atom-expr)
527 (:lambda (list)
530 (:lambda (list)
528 (let ((expr (remove-nil list)))
531 (let ((expr (remove-nil list)))
529 (if (= 1 (length expr))
532 (if (= 1 (length expr))
530 (first expr)
533 (first expr)
531 (intern-first expr)))))
534 (intern-first expr)))))
532
535
533 (p:defrule atom-expr (and (or variable literal returning-intrinsic paren-expr) spaces?)
536 (p:defrule atom-expr (and (or variable literal returning-intrinsic paren-expr) spaces?)
534 (:function first))
537 (:function first))
535
538
536 (p:defrule paren-expr (and #\( spaces? expression spaces? #\))
539 (p:defrule paren-expr (and #\( spaces? expression spaces? #\))
537 (:function third))
540 (:function third))
538
541
539 (p:defrule or-op (p:~ "or")
542 (p:defrule or-op (p:~ "or")
540 (:constant "or"))
543 (:constant "or"))
541
544
542 (p:defrule and-op (p:~ "and")
545 (p:defrule and-op (p:~ "and")
543 (:constant "and"))
546 (:constant "and"))
544
547
545 ;;; Variables
548 ;;; Variables
546
549
547 (p:defrule variable (and identifier (p:? array-index))
550 (p:defrule variable (and identifier (p:? array-index))
548 (:destructure (id idx)
551 (:destructure (id idx)
549 (list 'var id (or idx 0))))
552 (list 'var id (or idx 0))))
550
553
551 (p:defrule array-index (and #\[ spaces? (p:? expression) spaces? #\])
554 (p:defrule array-index (and #\[ spaces? (p:? expression) spaces? #\])
552 (:lambda (list)
555 (:lambda (list)
553 (or (third list) :end)))
556 (or (third list) :end)))
554
557
555 (p:defrule assignment (or kw-assignment plain-assignment)
558 (p:defrule assignment (or kw-assignment plain-assignment op-assignment)
556 (:destructure (var eq expr)
559 (:destructure (var eq expr)
557 (declare (ignore eq))
560 (declare (ignore eq))
558 (list 'set var expr)))
561 (list 'set var expr)))
559
562
563 (p:defrule kw-assignment (and (or (p:~ "let") (p:~ "set")) spaces? (or op-assignment plain-assignment))
564 (:function third))
565
566 (p:defrule op-assignment (and variable spaces? (or "+" "-" "*" "/") #\= spaces? expression)
567 (:destructure (var ws1 op eq ws2 expr)
568 (declare (ignore ws1 ws2))
569 (list var eq (intern-first (list op var expr)))))
570
560 (p:defrule plain-assignment (and variable spaces? #\= spaces? expression)
571 (p:defrule plain-assignment (and variable spaces? #\= spaces? expression)
561 (:function remove-nil))
572 (:function remove-nil))
562 (p:defrule kw-assignment (and (or (p:~ "let") (p:~ "set")) spaces? plain-assignment)
563 (:function third))
564
573
565 ;;; Non-string literals
574 ;;; Non-string literals
566
575
567 (p:defrule literal (or qsp-string brace-string number))
576 (p:defrule literal (or qsp-string brace-string number))
568
577
569 (p:defrule number (+ (or #\0 #\1 #\2 #\3 #\4 #\5 #\6 #\7 #\8 #\9))
578 (p:defrule number (+ (or #\0 #\1 #\2 #\3 #\4 #\5 #\6 #\7 #\8 #\9))
570 (:lambda (list)
579 (:lambda (list)
571 (parse-integer (p:text list))))
580 (parse-integer (p:text list))))
General Comments 0
You need to be logged in to leave comments. Login now