| fb-doc 0.2 documentation tool for FreeBasic

- Main Page
- Tutorial
- Data Structures
- Files

- File List
- Globals

All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
fb-doc_parser.bas
Go to the documentation of this file.
1 /'* \file fb-doc_parser.bas
2 \brief Source code for the \ref Parser class.
3
4 This file contains the source code for the Parser class. It's used
5 to scan the FB input for relevant constructs and call the matching
6 function in the \ref EmitterIF.
7
8 '/
9
10 #INCLUDE ONCE "fb-doc_parser.bi"
11
12
13 /'* \brief The constructor
14 \param Em a pointer to the emitter interface to use
15
16 Initialize the start values. We get the pointer to the EmitterIF to
17 use and we create a short token list (just two entries) for usage
18 inside the parser. This token list is static and it doesn't change
19 its adress (unlike the #Parser::Tok list that may shift when growing).
20
21 '/
22 CONSTRUCTOR Parser(BYVAL Em AS EmitterIF PTR)
23 STATIC AS INTEGER ToLi(...) = {0, 0, 0, 0, 0, 0}
24
25 Emit = Em
26 StaTok = @ToLi(0)
27 A = @ToLi(1)
28 L = @ToLi(2)
29 END CONSTRUCTOR
30
31
32 /'* \brief Snippet to skip to the next token '/
33 #DEFINE SKIP Tk += 3
34
35
36 /'* \brief Move to the next comma and one step beyond
37 \returns the (doubled) number of steps gone in the token list (or
38 MSG_ERROR on error and MSG_STOP on the end of the token list)
39
40 We step trough the token list and search for the next comma,
41 skipping nested pairs of parenthesis. When we find a comma we walk
42 one step beyond. Otherwise we stop at the next right parenthesis or
43 the next colon or line end.
44
45 '/
46 FUNCTION Parser.skipOverComma() AS INTEGER
47 VAR t = Tk, kl = 0
48 WHILE Tk < TkEnd
49 SELECT CASE AS CONST *Tk
50 CASE MSG_ERROR, TOK_EOS : RETURN Tk - t
51 CASE TOK_COMMA : IF kl <= 0 THEN SKIP : RETURN Tk - t
52 CASE TOK_BROPN, TOK_KLOPN : kl += 1
53 CASE TOK_BRCLO, TOK_KLCLO : kl -= 1 : IF kl < 0 THEN RETURN Tk - t
54 END SELECT : SKIP
55 WEND
56 END FUNCTION
57
58
59 /'* \brief Move to the matching right parenthesis and one step beyond
60 \returns the (doubled) number of steps gone in the token list (or
61 MSG_ERROR on error and MSG_STOP on the end of the token list)
62
63 Step through the token list and search for the next right
64 parenthesis, skipping nested pairs of paranethesis. When we find a
65 matching right parenthesis we walk one step beyond. Else we
66 stop at the next colon or line end.
67
68 '/
69 FUNCTION Parser.skipOverBrclo() AS INTEGER
70 VAR t = Tk, kl = 0
71 WHILE Tk < TkEnd
72 SELECT CASE AS CONST *Tk
73 CASE MSG_ERROR, TOK_EOS : RETURN Tk - t
74 CASE TOK_BROPN : kl += 1
75 CASE TOK_BRCLO : kl -= 1 : IF kl <= 0 THEN SKIP : RETURN Tk - t
76 END SELECT : SKIP
77 WEND
78 END FUNCTION
79
80
81 /'* \brief Move to the end of statement and one step beyond
82 \returns the (doubled) number of steps gone in the token list (or
83 MSG_ERROR on error and MSG_STOP on the end of the token list)
84
85 Step through the token list and search for the end of the current
86 statement. Then walk one step beyond, if not end of token list.
87
88 '/
89 FUNCTION Parser.skipOverColon() AS INTEGER
90 VAR t = Tk, fl = 0
91 WHILE Tk < TkEnd
92 IF *Tk = TOK_EOS THEN fl = 1 ELSE IF fl THEN RETURN Tk - t
93 SKIP
94 WEND : RETURN Tk - t
95 END FUNCTION
96
97
98 /'* \brief Evaluate a name, dimension and initializer in the token list
99 \param MinTk the token to start at
100 \param DeclMod the modus (normal or declaration)
101 \returns the (doubled) number of steps gone in the token list (or
102 MSG_ERROR on error and MSG_STOP on the end of the token list)
103
104 Check the token list for a declaration of a name, starting at the
105 current token (ie behind a VAR keyword). Also checking for
106 parenthesis to specify a dimension and the equal '=' character of an
107 initializer. After execution the current position is at the next
108 token after the equal character, or behind the closing parenthesis,
109 or the name. An error is returned if there is no word at the current
110 position.
111
112 '/
113 FUNCTION Parser.demuxNam(BYVAL MinTk AS INTEGER = TOK_WORD, BYVAL DeclMod AS INTEGER = 0) AS INTEGER
114 DimTok = 0
115 IniTok = 0
116 BitTok = 0
117
118 IF *Tk >= MinTk THEN NamTok = Tk ELSE NamTok = 0 : RETURN MSG_ERROR
119 DO
120 SELECT CASE AS CONST *Tk
121 CASE TOK_BROPN, TOK_EQUAL
122 IF Tk > NamTok THEN EXIT DO ELSE NamTok = 0 : RETURN MSG_ERROR
123 CASE TOK_DOT : IF *(Tk + 3) < MinTk THEN NamTok = 0 : RETURN MSG_ERROR
124 CASE TOK_WORD : IF *(Tk + 3) <> TOK_DOT THEN SKIP : EXIT DO
125 CASE ELSE
126 IF LevelCount = 0 ORELSE *Tk < MinTk THEN NamTok = 0 : RETURN MSG_ERROR
127 SKIP : EXIT DO
128 END SELECT : SKIP
129 LOOP : IF DeclMod THEN RETURN Tk - NamTok
130
131 IF *Tk = TOK_BROPN THEN DimTok = Tk : skipOverBrclo()
132 IF *Tk = TOK_EQUAL THEN IniTok = Tk : RETURN Tk - NamTok
133 IF 0 = LevelCount ORELSE _
134 *Tk <> TOK_EOS ORELSE _
135 Buf[*(Tk + 1)] <> ASC(":") THEN RETURN Tk - NamTok
136
137 VAR x = Tk + 3 ' check for bitfield declaration
138 IF *x >= MinTk THEN
139 x += 3
140 IF *x = TOK_EOS ANDALSO Buf[*(x + 1)] <> ASC(":") THEN _
141 BitTok = Tk : Tk = x : RETURN Tk - NamTok
142 END IF
143
144 SELECT CASE AS CONST *x
145 CASE TOK_EQUAL : BitTok = Tk : Tk = x : IniTok = x
146 CASE TOK_COMMA : BitTok = Tk : Tk = x
147 CASE ELSE
148 FOR i AS INTEGER = *(Tk + 1) + 1 TO *(Tk + 4) - 1
149 SELECT CASE AS CONST Buf[i]
150 CASE ASC(" "), ASC(!"\t"), ASC(!"\v")
151 CASE ASC("0") TO ASC("9") : BitTok = Tk : EXIT FOR
152 CASE ELSE : EXIT FOR
153 END SELECT
154 NEXT
155 END SELECT : RETURN Tk - NamTok
156 END FUNCTION
157
158
159 /'* \brief Evaluate a function declaration in the token list
160 \returns the the result of demuxTyp() (or MSG_ERROR on error and
161 MSG_STOP on the end of the token list)
162
163 Pre-check the token list for a declaration of a function, starting at
164 the token behind the DECLARE statement. When OK, use demuxTyp() to
165 evaluate the type of the declaration.
166
167 '/
168 FUNCTION Parser.demuxDecl() AS INTEGER
169 SELECT CASE AS CONST *Tk
170 CASE TOK_CONS, TOK_STAT, TOK_VIRT, TOK_ABST : DivTok = Tk : SKIP
171 CASE ELSE : DivTok = 0
172 END SELECT
173
174 FunTok = Tk : DimTok = 0 : IniTok = 0
175 SELECT CASE AS CONST *Tk
176 CASE TOK_CTOR, TOK_DTOR
177 SKIP : IF *Tk = TOK_WORD THEN NamTok = Tk : SKIP ELSE NamTok = 0
178 IF *Tk = TOK_EOS THEN RETURN TOK_EOS ELSE RETURN demuxTyp(1)
179 CASE TOK_OPER
180 DO
181 SKIP
182 IF *Tk = TOK_BROPN THEN EXIT DO
183 IF *Tk < TOK_BROPN THEN EXIT SELECT
184 LOOP UNTIL Tk >= TkEnd : RETURN demuxTyp(1)
185 CASE TOK_PROP
186 SKIP : IF *Tk = TOK_WORD THEN NamTok = Tk ELSE EXIT SELECT
187 SKIP : IF *Tk = TOK_EOS THEN RETURN TOK_EOS ELSE RETURN demuxTyp(1)
188 CASE TOK_SUB, TOK_FUNC
189 SKIP : IF *Tk = TOK_WORD THEN NamTok = Tk ELSE EXIT SELECT
190 SKIP : IF *Tk = TOK_LIB THEN SKIP : IF *Tk = TOK_QUOTE THEN SKIP ELSE EXIT SELECT
191 IF *Tk = TOK_EOS THEN RETURN TOK_EOS ELSE RETURN demuxTyp(1)
192 END SELECT : TypTok = 0 : FunTok = 0 : NamTok = 0 : RETURN MSG_ERROR
193 END FUNCTION
194
195
196 /'* \brief Evaluate a type declaration in the token list
197 \param DeclMod the modus (normal or declaration)
198 \returns the (doubled) number of steps gone in the token list (or
199 MSG_ERROR on error and MSG_STOP on the end of the token list)
200
201 Check the token list for a type declaration. Starting at the AS
202 statement we read the name of the type and all following 'PTR'
203 statements. The type may be a SUB, FUNCTION, PROPERTY, ... After
204 execution the current position is at the next token behind the last
205 PTR, or at the type name, or at the closing parenthesis. An error is
206 returned if there is no word at the current position, or the token
207 list doesn't start with 'AS', or the next token isn't a word.
208
209 '/
210 FUNCTION Parser.demuxTyp(BYVAL DeclMod AS INTEGER = 0) AS INTEGER
211 VAR t = Tk
212 ParTok = 0
213 CalTok = 0
214 AliTok = 0
215 TypTok = 0
216 As_Tok = 0
217 Co1Tok = 0
218 Co2Tok = 0
219 PtrTok = 0
220 PtrCount = 0
221
222 IF 0 = DeclMod THEN
223 DivTok = 0
224 IF *Tk = TOK_AS THEN As_Tok = Tk : SKIP ELSE RETURN MSG_ERROR
225
226 SELECT CASE AS CONST *Tk
227 CASE TOK_SUB : FunTok = Tk
228 CASE TOK_FUNC : FunTok = Tk
229 CASE ELSE
230 IF *Tk = TOK_CONS THEN Co1Tok = Tk : SKIP
231 IF *Tk < TOK_BYTE ORELSE *Tk > TOK_WORD THEN RETURN MSG_ERROR
232 TypTok = Tk : FunTok = 0
233 END SELECT : SKIP
234 END IF
235
236 SELECT CASE AS CONST *Tk
237 CASE TOK_EQUAL
238 IF FunTok THEN TypTok = 0 : RETURN MSG_ERROR
239 IniTok = Tk : RETURN Tk - t
240 CASE TOK_BROPN : IF 0 = FunTok THEN RETURN Tk - t
241 ParTok = Tk : skipOverBrclo()
242 CASE ELSE
243 IF 0 = FunTok THEN
244 IF *Tk = TOK_CONS THEN
245 Co2Tok = Tk : SKIP
246 IF *Tk <> TOK_PTR THEN TypTok = 0 : RETURN MSG_ERROR
247 ELSE
248 IF *Tk <> TOK_PTR THEN RETURN Tk - t
249 END IF
250
251 PtrTok = Tk : WHILE *Tk = TOK_PTR : PtrCount += 1 : SKIP : WEND
252
253 IF *Tk = TOK_EQUAL THEN IniTok = Tk
254 RETURN Tk - t
255 END IF
256
257 IF *Tk = TOK_EOS THEN RETURN IIF(*FunTok = TOK_FUNC, MSG_ERROR, TOK_EOS)
258
259 SELECT CASE AS CONST *Tk
260 CASE TOK_CDEC : CalTok = Tk : SKIP
261 CASE TOK_STCL : CalTok = Tk : SKIP
262 CASE TOK_PASC : CalTok = Tk : SKIP
263 END SELECT
264
265 IF *Tk = TOK_OVER THEN SKIP
266 IF *Tk = TOK_ALIA THEN
267 AliTok = Tk
268 SKIP : IF *Tk <> TOK_QUOTE THEN TypTok = 0 : RETURN MSG_ERROR
269 SKIP
270 END IF
271
272 IF *Tk = TOK_BROPN THEN ParTok = Tk : skipOverBrclo()
273 END SELECT
274
275 IF *Tk = TOK_AS THEN
276 As_Tok = Tk : SKIP
277 IF *Tk = TOK_CONS THEN Co1Tok = Tk : SKIP
278 TypTok = Tk : SKIP
279 IF *Tk = TOK_CONS THEN
280 Co2Tok = Tk : SKIP
281 IF *Tk <> TOK_PTR THEN FunTok = 0: TypTok = 0 : RETURN MSG_ERROR
282 END IF
283 PtrTok = Tk : WHILE *Tk = TOK_PTR : PtrCount += 1 : SKIP : WEND
284 ELSE
285 IF *FunTok = TOK_FUNC THEN RETURN MSG_ERROR
286 END IF ' !!! ToDo STATIC, EXPORT
287
288 IF *Tk = TOK_STAT THEN
289 SKIP : IF *Tk = TOK_EXPO THEN SKIP
290 ELSE
291 IF *Tk = TOK_EXPO THEN SKIP : IF *Tk = TOK_STAT THEN SKIP
292 END IF : RETURN Tk - t
293 END FUNCTION
294
295
296 /'* \brief Evaluate a list of names
297 \param Export_ the function to call on each find
298
299 Scan the token list for variable declarations and call the emitter
300 for each find (ie for constructs like DIM AS BYTE Nam1, Nam2(5) =
301 {0,1,2,3,4,5}, Nam3, ...).
302
303 '/
304 SUB Parser.parseListNam(BYVAL Export_ AS EmitFunc)
305 VAR count = 1
306 TypTok = 0 : FunTok = 0
307 DO
308 Tk1 = Tk
309 IF MSG_ERROR >= demuxNam() THEN : Errr("name expected") : skipOverComma() : ELSE
310 skipOverComma() : ListCount = count : Export_(@THIS) : count += 1 : END IF
311 LOOP UNTIL *Tk <= TOK_COMMA
312 END SUB
313
314
315 /'* \brief Evaluate a list of declarations
316 \param Export_ the function to call on each find
317
318 Scan the token list for variable declarations and call the emitter
319 for each find (ie for constructs like DIM Nam1 AS BYTE, Nam2(5) AS
320 UBYTE = {0,1,2,3,4,5}, Nam3 AS STRING, ...).
321
322 '/
323 SUB Parser.parseListNamTyp(BYVAL Export_ AS EmitFunc)
324 DO
325 Tk1 = Tk
326 IF MSG_ERROR >= demuxNam() THEN : Errr("name expected") : skipOverComma() : ELSE
327 IF MSG_ERROR >= demuxTyp() THEN : Errr("type expected") : skipOverComma() : ELSE
328 skipOverComma() : ListCount = 0 : Export_(@THIS) : END IF : END IF
329 LOOP UNTIL *Tk <= TOK_COMMA
330 END SUB
331
332
333 /'* \brief Evaluate the context of an ENUM block
334 \param Export_ the function to call on each find
335
336 The emitter calls us to evaluate statements inside an ENUM block. So
337 we stop after finding a statement and call the emitter handler
338 one-by-one.
339
340 '/
341 SUB Parser.parseBlockEnum(BYVAL Export_ AS EmitFunc)
342 VAR lico = 0
343 TypTok = 0 : FunTok = 0 : LevelCount += 1
344 WHILE Tk < TkEnd
345 Tk1 = Tk
346 SELECT CASE AS CONST *Tk
347 CASE TOK_END
348 SKIP : IF *Tk = TOK_ENUM THEN EXIT WHILE
349 Errr("END ENUM expected") : EXIT WHILE
350 CASE TOK_LATTE : skipOverColon()
351 CASE ELSE
352 IF MSG_ERROR >= demuxNam() THEN Errr("name expected") : skipOverColon() : EXIT SELECT
353 ListCount = lico
354 skipOverComma() : IF *Tk = TOK_EOS THEN lico = 0 : skipOverColon() ELSE lico += 1
355 Export_(@THIS)
356 END SELECT
357 WEND : skipOverColon() : LevelCount -= 1
358 END SUB
359
360
361 /'* \brief Evaluate the context of a block
362 \param Export_ the function to call on each find
363
364 The emitter calls us to evaluate constructs inside a block (TYPE /
365 UNION). So we stop after finding a statement and call the emitter
366 handler one-by-one.
367
368 '/
369 SUB Parser.parseBlockTyUn(BYVAL Export_ AS EmitFunc)
370 VAR endtok = *Tk1
371 LevelCount += 1
372
373 DO
374 Tk1 = Tk
375 VAR nextok = *(Tk + 3)
376 SELECT CASE AS CONST nextok
377 CASE TOK_AS, TOK_BROPN
378 BitTok = 0
379 IF MSG_ERROR >= demuxNam(TOK_ABST) THEN _
380 IF Errr("name expected") = MSG_ERROR THEN CONTINUE DO _
381 ELSE EXIT DO
382 IF MSG_ERROR >= demuxTyp() THEN _
383 IF Errr("type expected") = MSG_ERROR THEN CONTINUE DO _
384 ELSE EXIT DO
385 *NamTok = TOK_WORD : ListCount = 0 : Export_(@THIS)
386 skipOverColon()
387
388 CASE ELSE
389 SELECT CASE AS CONST *Tk1
390 CASE TOK_LATTE : skipOverColon()
391 CASE TOK_AS
392 BitTok = 0
393 IF MSG_ERROR >= demuxTyp() THEN _
394 IF Errr("type expected") = MSG_ERROR THEN CONTINUE DO _
395 ELSE EXIT DO
396 IF MSG_ERROR >= demuxNam(TOK_ABST) THEN _
397 IF Errr("name expected") = MSG_ERROR THEN CONTINUE DO _
398 ELSE EXIT DO
399
400 skipOverComma()
401 *NamTok = TOK_WORD : ListCount = 0 : Export_(@THIS)
402 IF *Tk >= TOK_ABST THEN parseListNam(Export_)
403 skipOverColon()
404 CASE TOK_END
405 IF nextok = endtok THEN EXIT DO
406 IF Errr("not supported") < MSG_ERROR THEN EXIT DO
407 skipOverColon()
408
409 CASE TOK_DECL : SKIP
410 IF MSG_ERROR >= demuxDecl() THEN IF Errr("syntax error " & SubStr(NamTok)) = MSG_ERROR _
411 THEN skipOverColon() : EXIT SELECT ELSE EXIT DO
412 skipOverColon() : Export_(@THIS)
413
414 CASE TOK_PUBL, TOK_PRIV, TOK_PROT
415 skipOverColon() : Export_(@THIS)
416
417 CASE TOK_ENUM, TOK_TYPE, TOK_UNIO, TOK_CLAS
418 VAR n = BlockNam
419 IF nextok = TOK_WORD THEN SKIP : BlockNam = SubStr ELSE BlockNam = ""
420 skipOverColon() : Export_(@THIS) : BlockNam = n
421 CASE ELSE
422 skipOverColon() : IF Errr("not supported") < MSG_ERROR THEN EXIT DO
423 END SELECT
424 END SELECT
425 LOOP UNTIL Tk >= TkEnd : skipOverColon() : LevelCount -= 1
426 END SUB
427
428
429 /'* \brief Evaluate a parameter list
430 \param Export_ the function to call on each find
431
432 Scan the token list for a parameter list. Evaluate declaration
433 specifiers (BYVAL / BYREF) and handle ellipsis, parameters without
434 name, initializers and empty lists.
435
436 '/
437 SUB Parser.parseListPara(BYVAL Export_ AS EmitFunc)
438 VAR count = 0, t = Tk
439 Tk = ParTok
440 SKIP
441 DO
442 Tk1 = Tk
443 By_Tok = 0
444 SELECT CASE AS CONST *Tk
445 CASE TOK_BRCLO : IF count > 0 THEN Errr("parameter expected")
446 ListCount = count : EXIT DO
447 CASE TOK_TRIDO : NamTok = Tk : TypTok = 0 : FunTok = 0
448 CASE ELSE
449 IF *Tk = TOK_BYVA ORELSE *Tk = TOK_BYRE THEN By_Tok = Tk : SKIP
450 IF *Tk <> TOK_AS ANDALSO *Tk >= TOK_ABST THEN
451 NamTok = Tk : SKIP
452 IF *Tk = TOK_BROPN THEN DimTok = Tk : skipOverBrclo()
453 ELSE
454 NamTok = 0
455 END IF
456 IF MSG_ERROR >= demuxTyp() THEN Errr("type expected") : skipOverComma() : CONTINUE DO
457 END SELECT
458 skipOverComma() : count += 1 : ListCount = count : Export_(@THIS)
459 LOOP UNTIL *Tk < TOK_COMMA : By_Tok = 0 : Tk = t
460 END SUB
461
462
463 /'* \brief Evaluate a TYPE or CLASS statement
464 \returns MSG_ERROR (or MSG_STOP on the end of the token list)
465
466 The pre-parser found a TYPE or CLASS keyword. In case of TYPE we
467 tokenize the line and check if it is an alias declaration. In that
468 case we call the emitter for a declaration on that single line.
469 Otherwise we tokenize the complete block and call the emitter for a
470 TYPE block. Or we call Errr() on syntax problems.
471
472 Note: the C emitter creates
473 - 'typedef Typ Nam' for 'TYPE AS Typ Nam'
474 - 'typedef struct Typ Nam' for 'TYPE Nam AS Typ'
475
476 '/
477 FUNCTION Parser._TYPE_() AS INTEGER
478 IF 3 > tokenize(TO_COLON) THEN RETURN Errr("syntax error")
479
480 DimTok = 0 : IniTok = 0
481 IF *StaTok = TOK_TYPE THEN
482 IF *Tk = TOK_AS THEN
483 IF MSG_ERROR >= demuxTyp() THEN RETURN Errr("type expected")
484 IF *Tk = TOK_WORD THEN NamTok = Tk ELSE RETURN Errr("name expected1")
485 skipOverComma()
486 Emit->Decl_(@THIS) : RETURN MSG_ERROR
487 ELSE
488 IF *Tk = TOK_WORD THEN NamTok = Tk : SKIP ELSE RETURN Errr("name expected2")
489 IF *Tk = TOK_AS THEN
490 IF MSG_ERROR >= demuxTyp() THEN RETURN Errr("type expected")
491 skipOverComma()
492 Emit->Decl_(@THIS) : RETURN MSG_ERROR
493 END IF
494 END IF
495 ELSE
496 IF *Tk = TOK_WORD THEN NamTok = Tk ELSE RETURN Errr("name expected3")
497 END IF
498 BlockNam = SubStr(NamTok)
499 IF 9 > tokenize(TO_END_BLOCK) THEN RETURN Errr("syntax error")
500 Tk1 = StaTok
501 Emit->Clas_(@THIS) : RETURN MSG_ERROR
502 END FUNCTION
503
504
505 /'* \brief Evaluate a variable declaration
506 \returns MSG_ERROR (or MSG_STOP on the end of the token list)
507
508 The pre-parser found a VAR, DIM, CONST, EXTERN, COMMON or STATIC
509 keyword. We tokenize the current line and send the result to the
510 emitter, or we call Errr() on syntax problems.
511
512 '/
513 FUNCTION Parser._VAR_() AS INTEGER
514 IF 3 > tokenize(TO_COLON) THEN RETURN Errr("syntax error")
515 IF *Tk <> TOK_SHAR THEN ShaTok = 0 ELSE ShaTok = Tk : SKIP
516
517 IF *Tk = TOK_AS THEN
518 IF MSG_ERROR >= demuxTyp() THEN RETURN Errr("type expected")
519 IF MSG_ERROR >= demuxNam() THEN RETURN Errr("name expected")
520 ELSE
521 IF MSG_ERROR >= demuxNam() THEN RETURN Errr("name expected")
522 IF *Tk = TOK_AS THEN demuxTyp() ELSE TypTok = 0 : FunTok = 0
523 IF 0 = TypTok ANDALSO 0 = FunTok THEN
524 SELECT CASE AS CONST *StaTok
525 CASE TOK_VAR, TOK_CONS
526 IF 0 = IniTok THEN RETURN Errr("initialization expected")
527 CASE ELSE : RETURN Errr("type expected")
528 END SELECT
529 END IF
530 END IF
531
532 skipOverComma()
533 Emit->Decl_(@THIS)
534 IF *Tk <= TOK_EOS THEN RETURN MSG_ERROR
535 IF NamTok > TypTok THEN parseListNam(Emit->Decl_) _
536 ELSE parseListNamTyp(Emit->Decl_)
537 RETURN MSG_ERROR
538 END FUNCTION
539
540
541 /'* \brief Evaluate an ENUM block
542 \returns MSG_ERROR (or MSG_STOP on the end of the token list)
543
544 The pre-parser found an ENUM keyword. We tokenize the context of the
545 complete block and call the emitter, or we call Errr() on
546 syntax problems.
547
548 '/
549 FUNCTION Parser._ENUM_() AS INTEGER
550 IF 9 > tokenize(TO_END_BLOCK) THEN RETURN Errr("syntax error")
551 IF *Tk = TOK_WORD THEN BlockNam = SubStr : SKIP ELSE BlockNam = ""
552 IF *Tk = TOK_EOS THEN skipOverColon() ELSE RETURN Errr("syntax errorrrr")
553 Tk1 = StaTok
554 Emit->Enum_(@THIS)
555 RETURN MSG_ERROR
556 END FUNCTION
557
558
559 /'* \brief Evaluate an UNION block
560 \returns MSG_ERROR (or MSG_STOP on the end of the token list)
561
562 The pre-parser found an UNION keyword. We tokenize the context of the
563 complete block and call the emitter, or we call Errr() on
564 syntax problems.
565
566 '/
567 FUNCTION Parser._UNION_() AS INTEGER
568 IF 9 > tokenize(TO_END_BLOCK) THEN RETURN Errr("syntax error")
569 IF *Tk <> TOK_WORD THEN RETURN Errr("name expected")
570 BlockNam = SubStr
571 skipOverColon()
572 Tk1 = StaTok
573 Emit->Unio_(@THIS)
574 RETURN MSG_ERROR
575 END FUNCTION
576
577
578 /'* \brief Evaluate a function
579 \returns MSG_ERROR (or MSG_STOP on the end of the token list)
580
581 The pre-parser found a SUB, FUNCTION, CONSTRUCTOR, DESTRUCTOR,
582 PROPERTY or OPERATOR keyword. We tokenize the complete block,
583 evaluate the name and type and send the result to the emitter, or we
584 call Errr() on syntax problems.
585
586 '/
587 FUNCTION Parser._FUNCTION_() AS INTEGER
588 SELECT CASE AS CONST ToLast
589 CASE TOK_PUBL, TOK_PRIV : DivTok = StaTok
590 CASE ELSE : DivTok = 0
591 END SELECT
592 IF 9 > tokenize(TO_END_BLOCK) THEN RETURN Errr("syntax error")
593 FunTok = StaTok
594
595 IF DivTok THEN DivTok = Tk1
596 IF MSG_ERROR >= demuxNam(TOK_WORD, 1) THEN RETURN Errr("name expected")
597 IF MSG_ERROR >= demuxTyp(1) THEN RETURN Errr("syntax error")
598
599 FOR i AS INTEGER = 0 TO 1
600 SELECT CASE AS CONST *Tk
601 CASE TOK_STAT : SKIP ' !!! ToDo
602 CASE TOK_EXPO : SKIP ' !!! ToDo
603 CASE ELSE : EXIT FOR
604 END SELECT
605 NEXT
606 skipOverBrclo()
607 Emit->Func_(@THIS)
608 RETURN MSG_ERROR
609 END FUNCTION
610
611
612 /'* \brief Evaluate a forward declaration
613 \returns MSG_ERROR (or MSG_STOP on the end of the token list)
614
615 The pre-parser found a DECLARE keyword. We tokenize the current line
616 and send the result to the emitter, or we call Errr() on syntax
617 problems.
618
619 '/
620 FUNCTION Parser._DECLARE_() AS INTEGER
621 IF 3 > tokenize(TO_COLON) THEN RETURN Errr("syntax error")
622 IF MSG_ERROR >= demuxDecl() THEN Errr("syntax error!!")
623 Emit->Decl_(@THIS)
624 RETURN MSG_ERROR
625 END FUNCTION
626
627
628 /'* \brief Evaluate an \#INCLUDE line
629 \returns MSG_ERROR (or MSG_STOP on the end of the token list)
630
631 The pre-parser found an \#INCLUDE line. We tokenize the line and call
632 the emitter, or we call Errr() handler on syntax problems. It's up
633 to the emitter function to follow the source tree (= create a new
634 parser and load the file).
635
636 '/
637 FUNCTION Parser._INCLUDE_() AS INTEGER
638 IF 3 > tokenize(TO_EOL) THEN RETURN Errr("syntax error")
639 IF *Tk = TOK_ONCE THEN DivTok = Tk : SKIP ELSE DivTok = 0
640 IF *Tk <> TOK_QUOTE THEN RETURN Errr("file name expected")
641 NamTok = Tk
642 Emit->Incl_(@THIS)
643 END FUNCTION
644
645
646 /'* \brief Evaluate a \#MACRO declaration
647 \returns MSG_ERROR (or MSG_STOP on the end of the token list)
648
649 The pre-parser found a \#MACRO block. We tokenize the block and call
650 the emitter, or we call Errr() handler on syntax problems.
651
652 '/
653 FUNCTION Parser._MACRO_() AS INTEGER
654 IF 3 > tokenize(TO_END_BLOCK) THEN RETURN Errr("syntax error")
655 IF *Tk <> TOK_WORD THEN RETURN Errr("name expected")
656 NamTok = Tk : SKIP
657 IF *Tk <> TOK_BROPN THEN RETURN Errr("'()' expected")
658 ParTok = Tk
659 skipOverBrclo()
660 Emit->Defi_(@THIS)
661 RETURN MSG_ERROR
662 END FUNCTION
663
664
665 /'* \brief Evaluate a \#DEFINE declaration
666 \returns MSG_ERROR (or MSG_STOP on the end of the token list)
667
668 The pre-parser found a \#DEFINE line. We tokenize the line and call
669 the emitter, or we call Errr() handler on syntax problems.
670
671 '/
672 FUNCTION Parser._DEFINE_() AS INTEGER
673 IF 3 > tokenize(TO_EOL) THEN RETURN Errr("syntax error")
674 IF *Tk < TOK_ABST ORELSE *Tk > TOK_WORD THEN RETURN Errr("name expected")
675 NamTok = Tk
676 Tk = TkEnd - 3
677 Emit->Defi_(@THIS)
678 RETURN MSG_ERROR
679 END FUNCTION
680
681
682 /'* \brief Emit an error message
683 \param E the reason for the error message
684 \returns MSG_ERROR (and MSG_STOP at end of file)
685
686 Create an error message and call the error function of the emitter.
687 It depends on the emitter if and where the error is shown.
688
689 '/
690 FUNCTION Parser.Errr(BYREF E AS STRING) AS INTEGER
691 VAR z = InLines
692 IF LevelCount THEN ' !!! ToDo: counter init for Geany!
693 FOR i AS INTEGER = *(Tk + 1) TO *(TkEnd + 1)
694 IF Buf[i] = ASC(!"\n") THEN z -= 1
695 NEXT
696 END IF
697 ErrMsg = "-error(" & z & "): " & E ' & _
698 '"! (... " & MID(Buf, IIF(Po > 20, Po - 40, 1), 20)
699 SELECT CASE AS CONST *StaTok
700 CASE TOK_DIM : ErrMsg &= " (DIM)"
701 CASE TOK_RDIM : ErrMsg &= " (REDIM)"
702 CASE TOK_VAR : ErrMsg &= " (VAR)"
703 CASE TOK_CONS : ErrMsg &= " (CONST)"
704 CASE TOK_STAT : ErrMsg &= " (STATIC)"
705 CASE TOK_COMM : ErrMsg &= " (COMMON)"
706 CASE TOK_EXRN : ErrMsg &= " (EXTERN)"
707 CASE TOK_TYPE : ErrMsg &= " (TYPE)"
708 CASE TOK_CLAS : ErrMsg &= " (CLASS)"
709 CASE TOK_SUB : ErrMsg &= " (SUB)"
710 CASE TOK_FUNC : ErrMsg &= " (FUNCTION)"
711 CASE TOK_PROP : ErrMsg &= " (PROPERTY)"
712 CASE TOK_CTOR : ErrMsg &= " (CONSTRUCTOR)"
713 CASE TOK_DTOR : ErrMsg &= " (DESTRUCTOR)"
714 CASE TOK_NAMS : ErrMsg &= " (NAMESPACE)"
715 CASE TOK_SCOP : ErrMsg &= " (SCOPE)"
716 CASE TOK_ENUM : ErrMsg &= " (ENUM)"
717 CASE TOK_UNIO : ErrMsg &= " (UNION)"
718 CASE TOK_DECL : ErrMsg &= " (DECLARE)"
719 CASE TOK_DEFI : ErrMsg &= " (#DEFINE)"
720 CASE TOK_MACR : ErrMsg &= " (#MACRO)"
721 CASE ELSE : ErrMsg &= " (???)"
722 END SELECT
723 Emit->_Error_(@THIS)
724
725 RETURN IIF(Buf[Po] = 0, MSG_STOP, MSG_ERROR)
726 END FUNCTION
727
728
729 /'*
730 \brief Check word at current parser position
731 \returns: The token for the word at current position
732
733 This function checks the word at the current parser position. In
734 case of a keyword the matching token gets returned. Otherwise \ref
735 Parser::TOK_WORD gets returned.
736
737 '/
738 FUNCTION Parser.getToken() AS INTEGER
739 SELECT CASE AS CONST Buf[*A]
740 CASE ASC("A"), ASC("a")
741 SELECT CASE USubStr
742 CASE "AS" : RETURN TOK_AS
743 CASE "ALIAS" : RETURN TOK_ALIA
744 CASE "ABSTRACT" : RETURN TOK_ABST
745 END SELECT
746 CASE ASC("B"), ASC("b")
747 SELECT CASE USubStr
748 CASE "BYTE" : RETURN TOK_BYTE
749 CASE "BYREF" : RETURN TOK_BYRE
750 CASE "BYVAL" : RETURN TOK_BYVA
751 END SELECT
752 CASE ASC("C"), ASC("c")
753 SELECT CASE USubStr
754 CASE "CDECL" : RETURN TOK_CDEC
755 CASE "CLASS" : RETURN TOK_CLAS
756 CASE "CONST" : RETURN TOK_CONS
757 CASE "COMMON" : RETURN TOK_COMM
758 CASE "CONSTRUCTOR" : RETURN TOK_CTOR
759 END SELECT
760 CASE ASC("D"), ASC("d")
761 SELECT CASE USubStr
762 CASE "DIM" : RETURN TOK_DIM
763 CASE "DOUBLE" : RETURN TOK_DOUB
764 CASE "DEFINE" : IF ToLast = TOK_LATTE THEN RETURN TOK_DEFI
765 CASE "DECLARE" : RETURN TOK_DECL
766 CASE "DESTRUCTOR" : RETURN TOK_DTOR
767 END SELECT
768 CASE ASC("E"), ASC("e")
769 SELECT CASE USubStr
770 CASE "END" : RETURN TOK_END
771 CASE "ENUM" : RETURN TOK_ENUM
772 CASE "EXTERN" : RETURN TOK_EXRN
773 CASE "EXPORT" : RETURN TOK_EXPO
774 CASE "EXTENDS" : RETURN TOK_EXDS
775 CASE "ENDMACRO" : IF ToLast = TOK_LATTE THEN RETURN TOK_EMAC
776 END SELECT
777 CASE ASC("F"), ASC("f")
778 SELECT CASE USubStr
779 CASE "FUNCTION" : RETURN TOK_FUNC
780 CASE "FIELD" : RETURN TOK_FILD
781 END SELECT
782 CASE ASC("I"), ASC("i")
783 SELECT CASE USubStr
784 CASE "INCLUDE" : IF ToLast = TOK_LATTE THEN RETURN TOK_INCL
785 CASE "INTEGER" : RETURN TOK_INT
786 END SELECT
787 CASE ASC("L"), ASC("l")
788 SELECT CASE USubStr
789 CASE "LIB" : RETURN TOK_LIB
790 CASE "LONG" : RETURN TOK_LONG
791 CASE "LONGINT" : RETURN TOK_LINT
792 END SELECT
793 CASE ASC("M"), ASC("m") : IF USubStr = "MACRO" THEN IF ToLast = TOK_LATTE THEN RETURN TOK_MACR
794 CASE ASC("N"), ASC("n") : IF USubStr = "NAMESPACE" THEN RETURN TOK_NAMS
795 CASE ASC("O"), ASC("o")
796 SELECT CASE USubStr
797 CASE "ONCE" : RETURN TOK_ONCE
798 CASE "OPERATOR" : RETURN TOK_OPER
799 CASE "OVERLOAD" : RETURN TOK_OVER
800 END SELECT
801 CASE ASC("P"), ASC("p")
802 SELECT CASE USubStr
803 CASE "PTR" : RETURN TOK_PTR
804 CASE "POINTER" : RETURN TOK_PTR
805 CASE "PASCAL" : RETURN TOK_PASC
806 CASE "PUBLIC" : RETURN TOK_PUBL
807 CASE "PRIVATE" : RETURN TOK_PRIV
808 CASE "PROPERTY" : RETURN TOK_PROP
809 CASE "PROTECTED" : RETURN TOK_PROT
810 END SELECT
811 CASE ASC("R"), ASC("r") : IF USubStr = "REDIM" THEN RETURN TOK_RDIM
812 CASE ASC("S"), ASC("s")
813 SELECT CASE USubStr
814 CASE "SUB" : RETURN TOK_SUB
815 CASE "SCOPE" : RETURN TOK_SCOP
816 CASE "SHORT" : RETURN TOK_SHOR
817 CASE "SINGLE" : RETURN TOK_SING
818 CASE "SHARED" : RETURN TOK_SHAR
819 CASE "STRING" : RETURN TOK_STRI
820 CASE "STATIC" : RETURN TOK_STAT
821 CASE "STDCALL" : RETURN TOK_STCL
822 END SELECT
823 CASE ASC("T"), ASC("t") : IF USubStr = "TYPE" THEN RETURN TOK_TYPE
824 CASE ASC("U"), ASC("u")
825 SELECT CASE USubStr
826 CASE "UNION" : RETURN TOK_UNIO
827 CASE "UBYTE" : RETURN TOK_UBYT
828 CASE "ULONG" : RETURN TOK_ULNG
829 CASE "ULONGINT" : RETURN TOK_ULIN
830 CASE "UINTEGER" : RETURN TOK_UINT
831 CASE "USHORT" : RETURN TOK_USHO
832 END SELECT
833 CASE ASC("V"), ASC("v")
834 SELECT CASE USubStr
835 CASE "VAR" : RETURN TOK_VAR
836 CASE "VIRTUAL" : RETURN TOK_VIRT
837 END SELECT
838 CASE ASC("W"), ASC("w") : IF USubStr = "WSTRING" THEN RETURN TOK_WSTR
839 CASE ASC("Z"), ASC("z") : IF USubStr = "ZSTRING" THEN RETURN TOK_ZSTR
840 END SELECT : RETURN TOK_WORD
841 END FUNCTION
842
843
844 /'* \brief Find the end of a Quote
845
846 This snippet is used to find the end of a quoted string. It checks
847 if the string uses escape sequences and evaluates '\\"' . It stops at
848 the last double quote (if Buf[Po] isn't ASC(!"\\"") then the end of
849 the buffer is reached).
850
851 '/
852 #MACRO SCAN_QUOTE(Buf,Po)
853 VAR esc = IIF(Buf[Po - 1] = ASC("!"), 1, 0)
854 DO
855 Po += 1
856 SELECT CASE AS CONST Buf[Po]
857 CASE 0, ASC(!"\n") : Po -= 1 : EXIT DO
858 CASE ASC("\") : IF esc THEN Po += 1
859 CASE ASC("""") : IF Buf[Po + 1] = ASC("""") THEN Po += 1 ELSE EXIT DO
860 END SELECT
861 LOOP
862 #ENDMACRO
863
864
865 /'* \brief Find the end of a line end comment
866
867 This snippet is used to find the end of a line end comment. It
868 checks for a ASC(!"\n") and evaluates line concatenations ( _ ) on
869 the way. It stops at the line end (if Buf[Po] isn't ASC(!"\n") then
870 the end of the buffer is reached).
871
872 '/
873 #MACRO SCAN_SL_COMM(Buf,Po)
874 DO
875 Po += 1
876 SELECT CASE AS CONST Buf[Po]
877 CASE 0, ASC(!"\n") : EXIT DO
878 END SELECT
879 LOOP
880 #ENDMACRO
881
882
883 /'* \brief Find the end of a multi line comment
884
885 This snippet is used to find the end of a multi line comment block.
886 It stops at the characters ' and / (if Buf[Po] isn't ASC("/") then the
887 end of the buffer is reached).
888
889 '/
890 #MACRO SCAN_ML_COMM()
891 Po += 2
892 DO
893 SELECT CASE AS CONST Buf[Po]
894 CASE 0 : EXIT DO
895 CASE ASC(!"\n") : InLines += 1
896 CASE ASC("'")
897 SELECT CASE AS CONST Buf[Po + 1]
898 CASE 0 : EXIT DO
899 CASE ASC("/") : Po += 1 : EXIT DO
900 END SELECT
901 END SELECT : Po += 1
902 LOOP
903 #ENDMACRO
904
905
906 /'* \brief Find the end of a word
907
908 This snippet is used to find the end of a word in the input buffer.
909 Po is at the first non-word character when done.
910
911 '/
912 #MACRO SCAN_WORD()
913 *A = Po
914 Po += 1
915 DO
916 SELECT CASE AS CONST Buf[Po]
917 CASE ASC("0") TO ASC("9"), _
918 ASC("A") TO ASC("Z"), _
919 ASC("a") TO ASC("z"), ASC("_") : Po += 1
920 CASE ELSE : EXIT DO
921 END SELECT
922 LOOP
923 #ENDMACRO
924
925 '* snippet to set the current token
926 #DEFINE SETOK(_T_,_A_,_L_) Tok &= MKI(_T_) & MKI(_A_) & MKI(_L_) : ToLast = _T_
927
928 '* snippet to exit in case of end of file
929 #DEFINE EXIT_STOP SETOK(MSG_STOP, Po, 1) : Po -= 1 : EXIT DO
930
931 /'* \brief Parse a relevant construct, create a token list
932 \param Stop_ the condition where to end parsing
933 \returns the length of the token list in byte (at least 8)
934
935 Start at the current position of the input buffer to check each
936 character. Sort the input in to a token list. The token list
937 contains three values in each entry: the type of the input, its
938 start and its length.
939
940 The end of this process gets specified by the Stop_ parameter. It's
941 one of the #EoS_Modi enumerators.
942
943 '/
944 FUNCTION Parser.tokenize(BYVAL Stop_ AS EoS_Modi) AS INTEGER
945 VAR coca = 0, endcount = 0, newblock = 0 ', currTok = MSG_ERROR, fl_end = 0
946 VAR tok_begin = LEN(Tok) SHR 2
947 ToLast = IIF(*StaTok = TOK_TYPE, TOK_EOS, MSG_ERROR)
948 A += 3 : L += 3
949 DO
950 SELECT CASE AS CONST Buf[Po]
951 CASE 0 : EXIT_STOP
952 CASE ASC(!"\n") : InLines += 1 : IF coca THEN coca = 0 : EXIT SELECT
953 IF ToLast = TOK_EOS THEN EXIT SELECT
954 SETOK(TOK_EOS, Po, 1) : IF Stop_ >= TO_EOL THEN EXIT DO
955 IF newblock THEN endcount += 1 : newblock = 0
956 CASE ASC(":")
957 SETOK(TOK_EOS, Po, 1) : IF Stop_ >= TO_COLON THEN EXIT DO
958 IF newblock THEN endcount += 1 : newblock = 0
959 CASE ASC(",") : SETOK(TOK_COMMA, Po, 1)
960 CASE ASC(".")
961 IF Buf[Po + 1] <> ASC(".") ORELSE Buf[Po + 2] <> ASC(".") ORELSE Buf[Po + 3] = ASC(".") _
962 THEN SETOK(TOK_DOT, Po, 1) _
963 ELSE SETOK(TOK_TRIDO, Po, 3) : Po += 3 : CONTINUE DO
964 CASE ASC("=") : SETOK(TOK_EQUAL, Po, 1)
965 CASE ASC("{"), ASC("[") : SETOK(TOK_KLOPN, Po, 1)
966 CASE ASC("}"), ASC("]") : SETOK(TOK_KLCLO, Po, 1)
967 CASE ASC("(") : SETOK(TOK_BROPN, Po, 1)
968 CASE ASC(")") : SETOK(TOK_BRCLO, Po, 1)
969 CASE ASC("#") : SETOK(TOK_LATTE, Po, 1)
970
971 CASE ASC("A") TO ASC("Z"), ASC("a") TO ASC("z"), ASC("_")
972 SCAN_WORD()
973 *L = Po - *A : IF *L = 1 ANDALSO Buf[*A] = ASC("_") THEN coca = *A : CONTINUE DO
974
975 VAR pretok = ToLast
976 SETOK(getToken(), *A, *L)
977 newblock = 0
978 IF pretok = TOK_END THEN
979 SELECT CASE AS CONST *StaTok
980 CASE TOK_SUB, TOK_FUNC, TOK_PROP, TOK_OPER, TOK_CTOR, TOK_DTOR, TOK_ENUM
981 IF ToLast = *StaTok THEN Stop_ = TO_COLON
982 CONTINUE DO
983 CASE TOK_UNIO, TOK_TYPE, TOK_CLAS
984 IF ToLast <> *StaTok THEN CONTINUE DO
985 CASE ELSE : CONTINUE DO
986 END SELECT
987 endcount -= 1 : IF endcount < 0 THEN Stop_ = TO_COLON
988 ELSE
989 SELECT CASE AS CONST *StaTok
990 CASE TOK_UNIO, TOK_TYPE, TOK_CLAS
991 IF pretok <> TOK_EOS THEN CONTINUE DO
992 IF ToLast = *StaTok THEN newblock = 1
993 CASE TOK_MACR : IF ToLast = TOK_EMAC THEN Stop_ = TO_COLON
994 END SELECT
995 END IF : CONTINUE DO
996
997 CASE ASC("""")
998 *A = Po
999 SCAN_QUOTE(Buf,Po)
1000 SETOK(TOK_QUOTE, *A, Po - *A + 1)
1001 IF Buf[Po] <> ASC("""") THEN EXIT_STOP
1002 CASE ASC("'")
1003 SCAN_SL_COMM(Buf,Po)
1004 CONTINUE DO
1005 CASE ASC("/") : IF Buf[Po + 1] <> ASC("'") THEN EXIT SELECT
1006 SCAN_ML_COMM()
1007 IF Buf[Po] <> ASC("/") THEN EXIT_STOP
1008 END SELECT : Po += 1
1009 LOOP : A -= 3 : L -= 3 : Po += 1
1010
1011 Tk1 = CAST(INTEGER PTR, SADD(Tok))
1012 TkEnd = Tk1 + (LEN(Tok) SHR 2) - 3
1013 Tk = Tk1 + tok_begin
1014 RETURN TkEnd - Tk
1015 END FUNCTION
1016
1017
1018 /'* \brief Pre-parse all FB source code, search relevant constructs
1019 \returns the length of the output code, if any
1020
1021 Search the input buffer for a relevant construct. Start detailed
1022 parsing on each relevant construct. Otherways skip the current line.
1023 Export comments on the way.
1024
1025 '/
1026 SUB Parser.pre_parse()
1027 Fin = LEN(Buf) - 1
1028 *L = 0
1029 Po = 0
1030 ToLast = MSG_ERROR
1031 InLines = 1
1032 Tok = ""
1033 Emit->_Init_(@THIS)
1034 DO
1035 SELECT CASE AS CONST Buf[Po] ' search word
1036 CASE 0 : EXIT DO
1037 CASE ASC(!"\n") : *L = 0 : InLines += 1
1038 CASE ASC(":") : *L = 0 : ToLast = 0
1039 CASE ASC("#") : ToLast = TOK_LATTE
1040 CASE ASC("""")
1041 SCAN_QUOTE(Buf,Po)
1042 ToLast = TOK_QUOTE : IF Buf[Po] <> ASC("""") THEN EXIT DO
1043 CASE ASC("'")
1044 SCAN_SL_COMM(Buf,Po)
1045 CONTINUE DO
1046 CASE ASC("/") : IF Buf[Po + 1] <> ASC("'") THEN EXIT SELECT
1047 SCAN_ML_COMM()
1048 IF Buf[Po] <> ASC(!"/") THEN EXIT DO
1049
1050 CASE ASC("_"), ASC("A") TO ASC("Z"), ASC("a") TO ASC("z")
1051 SCAN_WORD() : IF *L THEN ToLast = 0 : CONTINUE DO' skip word, if not first
1052 *L = Po - *A : IF *L = 1 ANDALSO Buf[*A] = ASC("_") THEN ToLast = 0 : *L = 0 : CONTINUE DO
1053
1054 ListCount = 0
1055 LevelCount = 0
1056 *StaTok = getToken()
1057 SELECT CASE AS CONST *StaTok
1058 CASE TOK_SUB, TOK_FUNC, TOK_PROP, TOK_OPER, TOK_CTOR, TOK_DTOR
1059 IF _FUNCTION_() = MSG_STOP THEN EXIT DO
1060 CASE TOK_DIM, TOK_RDIM, TOK_VAR, TOK_CONS, TOK_COMM, TOK_EXRN, TOK_EXPO, TOK_STAT
1061 IF _VAR_() = MSG_STOP THEN EXIT DO
1062 CASE TOK_TYPE, TOK_CLAS
1063 IF _TYPE_() = MSG_STOP THEN EXIT DO
1064 CASE TOK_UNIO : IF _UNION_() = MSG_STOP THEN EXIT DO
1065 CASE TOK_ENUM : IF _ENUM_() = MSG_STOP THEN EXIT DO
1066 CASE TOK_DECL : IF _DECLARE_() = MSG_STOP THEN EXIT DO
1067 CASE TOK_DEFI : IF _DEFINE_() = MSG_STOP THEN EXIT DO
1068 CASE TOK_MACR : IF _MACRO_() = MSG_STOP THEN EXIT DO
1069 CASE TOK_INCL : IF _INCLUDE_() = MSG_STOP THEN EXIT DO
1070 CASE TOK_PUBL, TOK_PRIV
1071 SETOK(*StaTok, *A, *L) : *L = 0 : CONTINUE DO
1072 'CASE TOK_NAMS : ' !!! ToDo
1073 'CASE TOK_SCOP : ' !!! ToDo
1074 CASE ELSE : ToLast = *StaTok : CONTINUE DO
1075 END SELECT : ToLast = *StaTok : Tok = "" : *L = 0 : CONTINUE DO
1076 END SELECT : Po += 1
1077 LOOP : Emit->_Exit_(@THIS)
1078 END SUB
1079
1080
1081 /'* \brief Read a buffer from a file and parse
1082 \param File the name of the file to translate
1083 \returns the translated code (if any)
1084
1085 Read a file in to input buffer. Start detailed parsing on each
1086 relevant construct. Otherways skip the current line. Export comments
1087 on the way. Do nothing if file doesn't exist or isn't readable.
1088
1089 '/
1090 SUB Parser.File_(BYREF File AS STRING)
1091 VAR fnr = FREEFILE
1092 IF OPEN(File FOR INPUT AS #fnr) _
1093 THEN ERROUT("Couldn't read file """ & File & """ (ERR = " & ERR & ")"): EXIT SUB
1094 Buf = STRING(LOF(fnr) + 1, 0)
1095 GET #fnr, , Buf
1096 CLOSE #fnr
1097
1098 pre_parse()
1099 END SUB
1100
1101
1102 /'* \brief Read a buffer from pipe StdIn and parse
1103 \returns the translated code (or an informal text)
1104
1105 Get all characters from StdIn. Start the parsing process. If there
1106 is no input (an empty line) then load file Options::EmitFile and
1107 output its context. Otherwise call function \ref
1108 EmitterIF::_Empty_(). (Useful for generating templates in \em
1109 --geany mode.)
1110
1111 '/
1112 SUB Parser.StdIn()
1113 Buf = ""
1114 VAR fnr = FREEFILE
1115 OPEN CONS FOR INPUT AS #fnr
1116 WHILE NOT EOF(fnr)
1117 DIM AS UBYTE z
1118 GET #fnr, , z
1119 Buf &= CHR(z)
1120 WEND
1121 CLOSE #fnr
1122
1123 IF LEN(Buf) < 3 THEN
1124 fnr = FREEFILE
1125 IF OPEN(OPT->EmitFile FOR INPUT AS #fnr) THEN Emit->_Empty_(@THIS) : EXIT SUB
1126 VAR txt = STRING(LOF(fnr), 0)
1127 GET #fnr, , txt
1128 CLOSE #fnr
1129
1130 PRINT #Ocha, txt; : EXIT SUB
1131 END IF
1132
1133 pre_parse() : IF Tk1 THEN EXIT SUB
1134
1135 PRINT #Ocha, _
1136 "' " & PROG_NAME & ": no --geany output:" & _
1137 NL & "' select either a line" & _
1138 NL & "' DIM, COMMON, CONST, EXTERN, STATIC, DECLARE, #DEFINE" & _
1139 NL & "' or a block" & _
1140 NL & "' ENUM, UNION, TYPE, #MACRO" & _
1141 NL & "' or a" & _
1142 NL & "' SUB, FUNCTION or PROPERTY" & _
1143 NL & "' declaration or" & _
1144 NL & "' place the cursor in an empty line" & _
1145 NL;
1146 END SUB
1147
1148
1149 /'* \brief The current token
1150 \returns the token the parser currently stopping at
1151
1152 This property returns the parser token (where the parser currently
1153 stops).
1154
1155 '/
1156 PROPERTY Parser.CurTok() AS INTEGER PTR
1157 RETURN Tk
1158 END PROPERTY
1159
1160 /'* \brief The initialization of a bitfield
1161 \returns the bitfield initialization
1162
1163 This property returns the initialization of a bitfield in a TYPE / UNION
1164 block. The size of the bitfield may either be an integer number or a
1165 macro (= TOK_WORD).
1166
1167 '/
1168 PROPERTY Parser.BitIni() AS STRING
1169 IF *(BitTok + 3) = TOK_WORD THEN RETURN ": " & SubStr(BitTok + 3)
1170 VAR a = *(BitTok + 1) + 1, l = 0
1171 FOR i AS INTEGER = a TO *(BitTok + 4) - 1
1172 SELECT CASE AS CONST Buf[i]
1173 CASE ASC(" "), ASC(!"\t"), ASC(!"\v") : IF l THEN EXIT FOR
1174 CASE ASC("0") TO ASC("9") : IF l THEN l += 1 ELSE a = i : l = 1
1175 CASE ELSE : EXIT FOR
1176 END SELECT
1177 NEXT : RETURN ": " & MID(Buf, a + 1, l)
1178 END PROPERTY
1179
1180 /'* \brief The dimension of a variable
1181 \returns the name including round or squared brackets
1182
1183 This property reads the dimension of a variable from the input buffer.
1184
1185 '/
1186 PROPERTY Parser.Bracket(BYVAL T AS INTEGER PTR) AS STRING
1187 VAR kl = 0, p = *(T + 1), l = 0
1188 WHILE T < TkEnd
1189 SELECT CASE AS CONST *T
1190 CASE TOK_COMMA : IF kl <= 0 THEN l = *(T + 1) - p : EXIT WHILE
1191 CASE TOK_KLOPN, TOK_BROPN : kl += 1
1192 CASE TOK_KLCLO, TOK_BRCLO : kl -= 1
1193 IF kl <= 0 THEN l = *(T + 1) - p + 1 : EXIT WHILE
1194 END SELECT : T += 3
1195 WEND : RETURN MID(Buf, p + 1, l)
1196 END PROPERTY
1197
1198 /'* \brief The variable initialization
1199 \returns the initialiser
1200
1201 This property reads the initialization of a variable from the input
1202 buffer.
1203
1204 '/
1205 PROPERTY Parser.VarIni() AS STRING
1206 VAR kl = 0, i = *(IniTok + 1), p = i
1207 DO
1208 i += 1
1209 SELECT CASE AS CONST Buf[i]
1210 CASE 0, ASC(!"\n"), ASC(!"\r"), ASC("'") : EXIT DO
1211 CASE ASC("_") : IF Buf[i + 1] < ASC("0") THEN EXIT DO
1212 CASE ASC("""")
1213 VAR esc = IIF(Buf[i - 1] = ASC("!"), 1, 0)
1214 DO
1215 i += 1
1216 SELECT CASE AS CONST Buf[i]
1217 CASE 0, ASC(!"\n") : i -= 1 : EXIT DO
1218 CASE ASC("\") : IF esc THEN i += 1
1219 CASE ASC("""") : IF Buf[i + 1] = ASC("""") THEN i += 1 ELSE EXIT DO
1220 END SELECT
1221 LOOP
1222 CASE ASC("("), ASC("{"), ASC("[") : kl += 1
1223 CASE ASC(")"), ASC("}"), ASC("]") : kl -= 1 : IF kl < 0 THEN EXIT DO
1224 CASE ASC(",") : IF kl <= 0 THEN EXIT DO
1225 END SELECT
1226 LOOP : RETURN " " & RTRIM(MID(Buf, p + 1, i - p), ANY !" \t\v")
1227 END PROPERTY
1228
1229 /'* \brief Context of current token
1230 \returns the context of the current token
1231
1232 This property returns the context of the current token from the
1233 input buffer.
1234
1235 '/
1236 PROPERTY Parser.SubStr() AS STRING
1237 IF 0 = Tk THEN RETURN " ?? 0 ?? "
1238 RETURN MID(Buf, *(Tk + 1) + 1, *(Tk + 2))
1239 END PROPERTY
1240
1241 /'* \brief Check current token position, extract word if string type
1242 \param T The token to read
1243 \returns the context of the token T
1244
1245 This property returns the context of the token T from the
1246 input buffer.
1247
1248 '/
1249 PROPERTY Parser.SubStr(BYVAL T AS INTEGER PTR) AS STRING
1250 IF 0 = T THEN RETURN " ?? 0 ?? "
1251 RETURN MID(Buf, *(T + 1) + 1, *(T + 2))
1252 END PROPERTY
1253
1254
1255 /'* \brief Check current token position, extract word if string type
1256 \returns the current word in upper case
1257
1258 This property returns the context of the current parser position in the
1259 input buffer in upper case characters.
1260
1261 '/
1262 PROPERTY Parser.USubStr() AS STRING
1263 RETURN UCASE(MID(Buf, *A + 1, Po - *A))
1264 END PROPERTY
1265