-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathsubtoken.os
298 lines (257 loc) · 12.2 KB
/
subtoken.os
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
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
!
! BRACY/SUBTOKEN. Read subtokens from a Bracy source file.
!
! Copyright © 2012 James B. Moen.
!
! This program is free software: you can redistribute it and/or modify it
! under the terms of the GNU General Public License as published by the Free
! Software Foundation, either version 3 of the License, or (at your option)
! any later version.
!
! This program is distributed in the hope that it will be useful, but WITHOUT
! ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
! FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
! more details.
!
! You should have received a copy of the GNU General Public License along with
! this program. If not, see <http://www.gnu.org/licenses/>.
!
(prog
! Constants that represent source subtokens.
makeSubtoken :− enum(high(int0))
blankSubtoken :− makeSubtoken() ! Separate words and scopes.
closeSubtoken :− makeSubtoken() ! End a scope.
endFileSubtoken :− makeSubtoken() ! End of source file.
endLineSubtoken :− makeSubtoken() ! End of source line.
glyphSubtoken :− makeSubtoken() ! A char with style information.
ignoredSubtoken :− makeSubtoken() ! A subtoken we don't care about.
openSubtoken :− makeSubtoken() ! Begin a scope.
! Constants that identify what ATOMs are for (see below).
makeLabel :− enum()
bulletLabel :− makeLabel() ! Scope with bulleted paragraphs.
centerLabel :− makeLabel() ! Scope with centered lines.
columnLabel :− makeLabel() ! Scope with unchanged paragraphs.
displayLabel :− makeLabel() ! Scope with unfilled lines.
endLineLabel :− makeLabel() ! End of line sentinel.
endParaLabel :− makeLabel() ! End of paragraph sentinel.
gotoLabel :− makeLabel() ! Scope with a link.
imageLabel :− makeLabel() ! Scope with an image.
indentLabel :− makeLabel() ! Scope with indented lines.
insertLabel :− makeLabel() ! Scope with an html file to insert.
itemizeLabel :− makeLabel() ! Scope with named paragraphs.
justifyLabel :− makeLabel() ! Scope with justified paragraphs.
labelLabel :− makeLabel() ! Scope for an internal label.
layoutLabel :− makeLabel() ! Scope to display a rectangular grid.
leftLabel :− makeLabel() ! Scope with left-justified paragraphs.
narrowLabel :− makeLabel() ! Scope with narrowed paragraphs.
numberLabel :− makeLabel() ! Scope with numbered paragraphs.
orsonLabel :− makeLabel() ! Scope to display Orson source code.
overLabel :− makeLabel() ! Scope to display a big fraction.
rightLabel :− makeLabel() ! Scope with right-justified paragraphs.
rowLabel :− makeLabel() ! Scope for a row in a layout or table.
ruleLabel :− makeLabel() ! Draw a horizontal line.
tableLabel :− makeLabel() ! Scope to display a rectangular table.
titleLabel :− makeLabel() ! Scope to display a title.
unknownLabel :− makeLabel() ! An unknown scope.
! Some subtokens have associated ATOMs in SUBTOKEN OBJECT (see below).
ref object bulletAtom :− makeAtom(''bullet'', bulletLabel)
ref object centerAtom :− makeAtom(''center'', centerLabel)
ref object columnAtom :− makeAtom(''column'', columnLabel)
ref object displayAtom :− makeAtom(''display'', displayLabel)
ref object endLineAtom :− makeAtom(''endLine'', endLineLabel)
ref object endParaAtom :− makeAtom(''endPara'', endParaLabel)
ref object gotoAtom :− makeAtom(''goto'', gotoLabel)
ref object imageAtom :− makeAtom(''image'', imageLabel)
ref object indentAtom :− makeAtom(''indent'', indentLabel)
ref object insertAtom :− makeAtom(''insert'', insertLabel)
ref object itemizeAtom :− makeAtom(''itemize'', itemizeLabel)
ref object justifyAtom :− makeAtom(''justify'', justifyLabel)
ref object labelAtom :− makeAtom(''label'', labelLabel)
ref object layoutAtom :− makeAtom(''layout'', layoutLabel)
ref object leftAtom :− makeAtom(''left'', leftLabel)
ref object narrowAtom :− makeAtom(''narrow'', narrowLabel)
ref object orsonAtom :− makeAtom(''orson'', orsonLabel)
ref object overAtom :− makeAtom(''over'', overLabel)
ref object numberAtom :− makeAtom(''number'', numberLabel)
ref object rightAtom :− makeAtom(''right'', rightLabel)
ref object rowAtom :− makeAtom(''row'', rowLabel)
ref object ruleAtom :− makeAtom(''rule'', ruleLabel)
ref object tableAtom :− makeAtom(''table'', tableLabel)
ref object titleAtom :− makeAtom(''title'', titleLabel)
ref object unknownAtom :− makeAtom(''unknown'', unknownLabel)
! Variables.
var styleStack opens :− makeStyleStack() ! Stack of OPEN tokens.
var int subtoken :− blankSubtoken ! Current subtoken.
var char subtokenChar :− ' ' ! SUBTOKEN's char.
var ref object subtokenObject :− nil ! SUBTOKEN's object.
var set subtokenStyle :− ∅ ! SUBTOKEN's style.
! NEXT SUBTOKEN. Scan the next subtoken using chars read from SOURCE.
nextSubtoken :−
(proc () void:
(with
! NEXT BACKSLASH. Scan a char after a backslash as if it's a GLYPH SUBTOKEN.
nextBackslash :−
(form () void:
nextChar()
(if ch = eofChar
then syntaxError(charExpectedErr)
nextEndFile()
else if ch = eolChar
then nextBlank()
else if ch = ' ' ∨ ch = '\\' ∨ ch = '{' ∨ ch = '}'
then nextGlyph()
else syntaxError(backslashErr)
nextBlank()))
! NEXT BLANK. Scan a BLANK SUBTOKEN.
nextBlank :−
(form () void:
subtoken := blankSubtoken
subtokenChar := ' '
subtokenObject := nil
nextChar())
! NEXT CLOSE. Scan a close brace, and pop a layer off the style stack. If that
! layer corresponds to a scope that established a new style, then we treat the
! subtoken as an IGNORED SUBTOKEN. Otherwise it's a CLOSE SUBTOKEN.
nextClose :−
(form () void:
(if isEmpty(opens)
then syntaxError(unexpectedBraceErr)
subtoken := ignoredSubtoken
else pop(subtoken, subtokenStyle, opens))
subtokenObject := nil
nextChar())
! NEXT END FILE. Scan an END FILE SUBTOKEN. Do not read the next char, because
! there isn't one.
nextEndFile :−
(form () void:
subtoken := endFileSubtoken
subtokenObject := nil)
! NEXT END LINE. Scan an END LINE SUBTOKEN.
nextEndLine :−
(form () void:
subtoken := endLineSubtoken
subtokenObject := endLineAtom
nextChar())
! NEXT GLYPH. Scan any char that isn't a delimiter.
nextGlyph :−
(alt
(form () void:
nextGlyph(ch)),
(form (char ch) void:
subtoken := glyphSubtoken
subtokenChar := ch
subtokenObject := nil
nextChar()))
! NEXT OPEN. Scan an open brace followed by the name of a scope.
nextOpen :−
(form () void:
(with
var set style :− ∅
var bool stylish :− true
var buffer(maxSourceLineLength + 1, char0) openChars
! NEXT COMMENT. Scan a comment. Comments may be nested. We stop scanning if we
! see a matching close brace or the end of the source file.
nextComment :−
(form () void:
(with var int count :− 1
do (while count > 0 ∧ ch ≠ eofChar
do (if ch = '\\'
then nextChar()
(if ch ≠ eofChar
then nextChar())
else if ch = '{'
then count += 1
nextChar()
else if ch = '}'
then count −= 1
nextChar()
else nextChar()))
(if count > 0
then syntaxError(braceExpectedErr))
subtoken := blankSubtoken
subtokenObject := nil))
! NEXT OTHER. Scan a char in a scope name that doesn't establish a style.
nextOther :−
(form () void:
append(openChars, ch)
stylish := false
nextChar())
! NEXT STYLE. Scan a char in a scope name that establishes a style code CODE.
nextStyle :−
(form (int code) void:
append(openChars, ch)
style ∪= code
nextChar())
! This is NEXT OPEN's body. Skip the open brace. If it's followed by "*", then
! we have a comment.
do nextChar()
(if ch = '*'
then nextComment()
! If we don't have a comment, then the open brace must be followed by the name
! of a scope: one or more letters, digits, and signs. These chars go into OPEN
! SCOPE, and STYLISH tells if they established new style codes in STYLE.
else empty(openChars)
(while isLetterOrDigit(ch) ∨ ch = '+' ∨ ch = '-' ∨ ch = '='
do (case ch
of '+': nextStyle(superCode)
'-': nextStyle(subCode)
'=': nextStyle(subSubCode)
'b': nextStyle(boldCode)
'c': nextStyle(capitalCode)
'i': nextStyle(italicCode)
'g': nextStyle(grayCode)
'q': nextStyle(quotedCode)
'u': nextStyle(underlineCode)
's': nextStyle(strikeCode)
't': nextStyle(typedCode)
none: nextOther()))
! If we establish new style codes then our subtoken is IGNORED SUBTOKEN, which
! is handled by the subtoken scanner. Otherwise our subtoken is OPEN SUBTOKEN,
! which is handled by the token scanner. Save the old SUBTOKEN STYLE, setting
! up a new SUBTOKEN OBJECT or SUBTOKEN STYLE as needed.
(if stylish ∧ style ≠ ∅
then (while ch = ' ' ∨ ch = eolChar
do nextChar())
push(opens, ignoredSubtoken, subtokenStyle)
subtoken := ignoredSubtoken
subtokenStyle ∪= style
else push(opens, closeSubtoken, subtokenStyle)
subtoken := openSubtoken
subtokenObject :=
select(openChars{string}, unknownAtom:
(: ''bullet'', bulletAtom),
(: ''center'', centerAtom),
(: ''column'', columnAtom),
(: ''display'', displayAtom),
(: ''goto'', gotoAtom),
(: ''image'', imageAtom),
(: ''indent'', indentAtom),
(: ''insert'', insertAtom),
(: ''itemize'', itemizeAtom),
(: ''justify'', justifyAtom),
(: ''label'', labelAtom),
(: ''layout'', layoutAtom),
(: ''left'', leftAtom),
(: ''narrow'', narrowAtom),
(: ''number'', numberAtom),
(: ''orson'', orsonAtom),
(: ''over'', overAtom),
(: ''right'', rightAtom),
(: ''row'', rowAtom),
(: ''rule'', ruleAtom),
(: ''table'', tableAtom),
(: ''title'', titleAtom))))))
! This is NEXT SUBTOKEN's body. Look at CH to figure out what kind of subtoken
! we have, then dispatch to code that scans it. Repeat, until we get one other
! than IGNORED SUBTOKEN.
do (while
(case ch
of ' ': nextBlank()
'\\': nextBackslash()
'}': nextClose()
'{': nextOpen()
eofChar: nextEndFile()
eolChar: nextEndLine()
none: nextGlyph())
subtoken = ignoredSubtoken)))
)