| 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_emitters.bas
Go to the documentation of this file.
1 /'* \file fb-doc_emitters.bas
2 \brief Default emitter to create pseudo C source, \#INCLUDEs the other emitters
3
4 This file is the main file for emitters. It contains some helper
5 functions to extract original source code and comments. And it
6 contains the standard emitter to translate the FB source to pseudo C
7 source.
8
9 The pseudo C emitter is designed to create C source out of the FB
10 code including the documentation comments. Comments may be multi
11 line comment blocks or line end comments. The emitter tries to place
12 the comments similar as in the FB source (but a comment inside a
13 statement will be placed at the end of the corresponding C statement).
14
15 The emitter is designed to be used to generate output for the
16 documentation tool-chain back-end. This may be written to the StdOut
17 pipe (default) or to one or more files (option \em --fileoutout). It
18 also can be used to translate an FB header to C syntax by unsing
19 option \em --cstyle.
20
21 '/
22
23 #INCLUDE ONCE "fb-doc_emitters.bi"
24
25 /'* \brief Convenience macro for output '/
26 #DEFINE Code(_T_) PRINT #.Ocha, _T_;
27
28
29 /'* \brief Handler for exporting comments
30 \param P the parser calling this handler
31 \param Stop_ the end position in the input buffer Parser::Buf
32
33 Export the comments between the 'last position' and the Stop_
34 position. Then, the Stop_ position gets the new 'last position'.
35
36 '/
37 SUB cEmitComments CDECL(BYVAL P AS Parser PTR, BYVAL Stop_ AS INTEGER)
38 WITH *P
39 VAR i = .SrcBgn
40 WHILE i <= Stop_
41 SELECT CASE AS CONST .Buf[i]
42 CASE 0 : EXIT WHILE
43 CASE ASC(!"\n") : Code(NL)
44 CASE ASC("""")
45 SCAN_QUOTE(.Buf,i)
46 CASE ASC("'")
47 VAR c = i + 1
48 SCAN_SL_COMM(.Buf,i)
49 IF .Buf[c] = OPT->JoComm THEN c += 1 : Code("//!" & MID(.Buf, c + 1, i - c))
50 IF .Buf[c] = OPT->AdLine THEN c += 1 : Code(MID(.Buf, c + 1, i - c))
51 CONTINUE WHILE
52 CASE ASC("/") : IF .Buf[i + 1] <> ASC("'") THEN EXIT SELECT
53 i += 2
54 VAR c = IIF(.Buf[i] = OPT->JoComm, i + 1, 0)
55 IF c THEN Code("/**")
56 DO
57 SELECT CASE AS CONST .Buf[i]
58 CASE 0 : EXIT DO
59 CASE ASC(!"\n") : IF 0 = c THEN Code(NL) : EXIT SELECT
60 Code(MID(.Buf, c + 1, i - c + 1))
61 c = i + 1
62 IF OPT->Asterix = OPT->GTK_DOC THEN Code("* ")
63 CASE ASC("'")
64 SELECT CASE AS CONST .Buf[i + 1]
65 CASE 0 : EXIT SUB
66 CASE ASC("/") : i += 1 : EXIT DO
67 END SELECT
68 END SELECT : i += 1
69 LOOP
70 IF c THEN Code(MID(.Buf, c + 1, i - c - 1) & "*/")
71 END SELECT : i += 1
72 WEND : IF .SrcBgn < i THEN .SrcBgn = i
73 END WITH
74 END SUB
75
76
77 /'* \brief Export the name (including double colons for member functions)
78 \param P the parser calling this emitter
79
80 This property reads the name of a construct from the input buffer
81 and emits all words, concatenated by double colons.
82
83 \returns the name including dots (colons)
84
85 '/
86 SUB cppNam CDECL(BYVAL P AS Parser PTR)
87 WITH *P
88 VAR t = .NamTok
89 Code(.SubStr(t))
90 WHILE t < .TkEnd
91 t += 3
92 SELECT CASE AS CONST *t
93 CASE .TOK_DOT : Code("::")
94 CASE .TOK_WORD : Code(.SubStr(t))
95 CASE ELSE : EXIT WHILE
96 END SELECT
97 WEND
98 END WITH
99 END SUB
100
101
102 /'* \brief Export the name (including dots for member functions)
103 \param P the parser calling this emitter
104
105 This property reads the name of a construct from the input buffer
106 and emits all words as in the original source.
107
108 \returns the name including dots (colons)
109
110 '/
111 SUB cNam CDECL(BYVAL P AS Parser PTR)
112 WITH *P
113 VAR t = .NamTok, a = *(t + 1), l = *(t + 2)
114 WHILE t < .TkEnd
115 t += 3
116 SELECT CASE AS CONST *t
117 CASE .TOK_DOT, .TOK_WORD : l += *(t + 2)
118 CASE ELSE : EXIT WHILE
119 END SELECT
120 WEND : Code(MID(.Buf, a + 1, l))
121 END WITH
122 END SUB
123
124
125 /'* \brief Create pseude C declaration
126 \param P the parser calling this emitter
127
128 Create a declaration for the construct at the current parser
129 position using FB style. All FB keywords gets mangled to a single
130 word to get a FreeBasic look-and-feel in the documentation. Ie we emit
131
132 - "SUB Name();" (instead of "void Name(void);")
133 - "INTEGER varnam" (instead of "int varname")
134 - "BYREF_AS_STRING strng" (instead of "char** strng")
135 - "FUNCTION_CDECL_AS_SINGLE xyz CDECL(BYVAL_AS_BYTE C)" (instead of
136 "float xyz(char C)")
137 - ...
138
139 The C lexer of the back-end (gtk-doc or Doxygen) interprets this
140 single word as a C type declaration (or macro) and can handle FB
141 source code that way.
142
143 Exeptions handled in this SUB:
144
145 - TypTok = 0: no type, emit only the name (with a space in from)
146 - NymTok = 0: no name, emit type and exit
147
148 '/
149 SUB cppCreateTypNam CDECL(BYVAL P AS Parser PTR)
150 WITH *P
151 IF .TypTok THEN
152 IF .Co1Tok THEN Code(.SubStr(.Co1Tok) & "_")
153 Code(.SubStr(.TypTok))
154 IF .Co2Tok THEN Code("_" & .SubStr(.Co2Tok))
155 FOR i AS INTEGER = 1 TO .PtrCount
156 Code("_" & .SubStr(.PtrTok)) : NEXT
157 IF .NamTok THEN Code(" ") ELSE EXIT SUB
158 ELSE
159 Code(" ")
160 END IF
161
162 IF .NamTok > .TypTok _
163 THEN cEmitComments(P, *(.NamTok + 1))
164
165 cppNam(P)
166 IF .DimTok THEN Code(.Bracket(.DimTok))
167 IF .BitTok THEN Code(.BitIni)
168 IF .IniTok THEN Code(.VarIni)
169 END WITH
170 END SUB
171
172
173 /'* \brief The dimension of a variable
174 \param P the parser calling this emitter
175
176 This property reads the dimension of a construct from the input buffer.
177
178 \returns the name including round or squared brackets
179
180 '/
181 SUB cArrDim CDECL(BYVAL P AS Parser PTR)
182 WITH *P
183 VAR t = .DimTok, kl = 0
184 DO
185 SELECT CASE AS CONST *t
186 CASE .TOK_COMMA : Code(" + 1][")
187 CASE .TOK_BROPN : kl += 1 : Code("[")
188 CASE .TOK_BRCLO : kl -= 1 : Code(" + 1]") : IF kl <= 0 THEN EXIT DO
189 CASE ELSE : Code(.SubStr(t))
190 END SELECT : t += 3
191 LOOP UNTIL t >= .TkEnd
192 END WITH
193 END SUB
194
195
196 /'* \brief Create C declaration
197 \param P the parser calling this emitter
198
199 Create a C declaration for the construct at the current parser
200 position. All FB keywords gets translated to their C expressions. Ie
201 we emit
202
203 - "void Name(void);" (instead of "SUB Name();")
204 - "int varname" (instead of "INTEGER varnam")
205 - "char** strng" (instead of "BYREF_AS_STRING strng")
206 - "float xyz(char C)" (instead of "FUNCTION_CDECL_AS_SINGLE
207 xyz CDECL(BYVAL_AS_BYTE C)")
208 - ...
209
210 The C source code is very useful when you use a library compiled
211 with FreeBasic in a other language like C or C++. fb-doc can
212 auto-generate the header files (just check initializers and array
213 dimensioning manually).
214
215 Exeptions handled in this SUB:
216
217 - TypTok = 0: no type, emit only the name (with a space in from)
218 - NymTok = 0: no name, emit type and exit
219
220 '/
221 SUB cCreateTypNam CDECL(BYVAL P AS Parser PTR)
222 WITH *P
223 IF .TypTok THEN
224 IF .Co1Tok THEN Code("const ")
225
226 SELECT CASE AS CONST *.TypTok
227 CASE .TOK_BYTE : Code("signed char")
228 CASE .TOK_UBYT : Code("unsigned char")
229 CASE .TOK_SHOR : Code("short")
230 CASE .TOK_USHO : Code("unsigned short")
231 CASE .TOK_STRI : Code("char*") ' ??? FB_STRING, g_string
232 CASE .TOK_SING : Code("float")
233 CASE .TOK_DOUB : Code("double")
234 CASE .TOK_ZSTR : Code("char")
235 CASE .TOK_WSTR : Code("wchar")
236 CASE .TOK_INT, .TOK_LONG : Code("int")
237 CASE .TOK_UINT, .TOK_ULNG : Code("unsigned int")
238 CASE .TOK_LINT : Code("long int")
239 CASE .TOK_ULIN : Code("unsigned long int")
240 CASE ELSE : Code(.SubStr(.TypTok))
241 END SELECT
242
243 IF .Co2Tok THEN Code(" " & .SubStr(.Co2Tok))
244 IF .By_Tok ANDALSO *.By_Tok = .TOK_BYRE THEN .PtrCount += 1
245 FOR i AS INTEGER = 1 TO .PtrCount
246 Code("*") : NEXT
247 IF .NamTok THEN Code(" ") ELSE EXIT SUB
248 END IF
249
250 IF .NamTok > .TypTok _
251 THEN cEmitComments(P, *(.NamTok + 1))
252
253 SELECT CASE AS CONST *.StaTok
254 CASE .TOK_TYPE, .TOK_DIM, .TOK_RDIM, .TOK_COMM, .TOK_EXRN
255 IF .FunTok THEN Code("(*") : cNam(P) : Code(")") : EXIT SUB
256 END SELECT
257 cNam(P)
258 IF .DimTok THEN cArrDim(P)
259 IF .BitTok THEN Code(.BitIni)
260 IF .IniTok THEN Code(.VarIni)
261 END WITH
262 END SUB
263
264
265 DECLARE SUB cppCreateFunction CDECL(BYVAL AS Parser PTR)
266 /'* \brief Handler for a parameter declaration
267 \param P the parser calling this handler
268
269 Generate a declaration for a parameter list. The declaration may be
270 empty (), may have no name (prototype declaration) or may by an
271 ellipsis ( ... ). Initializers get emitted "as-is".
272
273 We emit a space in front and a comma behind the parameter. When done
274 the first space gets replaced by a '(' and the last comma gets
275 replaced by a ')'.
276
277 '/
278 SUB cppEntryListParameter CDECL(BYVAL P AS Parser PTR)
279 WITH *P
280 cEmitComments(P, *(.Tk1 + 1))
281
282 IF .FunTok THEN
283 IF .By_Tok THEN Code(.SubStr(.By_Tok) & "_")
284 IF .CalTok THEN Code("_" & .SubStr(.CalTok))
285 IF .DivTok THEN Code("_" & .SubStr(.DivTok))
286 cppCreateFunction(P)
287 ELSEIF .TypTok THEN
288 IF .By_Tok THEN Code(.SubStr(.By_Tok) & "_")
289 Code(.SubStr(.As_Tok) & "_")
290 cppCreateTypNam(P)
291 ELSEIF *.NamTok = .TOK_TRIDO THEN
292 Code("...)") : EXIT SUB
293 END IF
294
295 IF *.CurTok <> .TOK_BRCLO THEN Code(", ") : EXIT SUB
296 cEmitComments(P, *(.CurTok + 1)) : Code(")")
297 END WITH
298 END SUB
299
300
301 DECLARE SUB cCreateFunction CDECL(BYVAL AS Parser PTR)
302 /'* \brief Handler for a parameter declaration
303 \param P the parser calling this handler
304
305 Generate a declaration for a parameter list. The declaration may be
306 empty (), may have no name (prototype declaration) or may by an
307 ellipsis ( ... ). Initializers get emitted "as-is", this means you
308 have to check if they contain FB keywords (and translate manually, if
309 so).
310
311 We emit a space in front and a comma behind the parameter. When done
312 the first space gets replaced by a '(' and the last comma gets
313 replaced by a ')'.
314
315 '/
316 SUB cEntryListParameter CDECL(BYVAL P AS Parser PTR)
317 WITH *P
318 cEmitComments(P, *(.Tk1 + 1))
319
320 IF .FunTok THEN
321 cCreateFunction(P)
322 ELSEIF .TypTok THEN
323 cCreateTypNam(P)
324 IF .NamTok ANDALSO .IniTok THEN Code(.VarIni)
325 ELSEIF .NamTok = .TOK_TRIDO THEN
326 Code("...")
327 ELSE
328 Code("void")
329 END IF
330
331 IF *.CurTok <> .TOK_BRCLO THEN Code(", ") : EXIT SUB
332 cEmitComments(P, *(.CurTok + 1)) : Code(")")
333 END WITH
334 END SUB
335
336
337 /'* \brief Create a function declaration
338 \param P the parser calling this handler
339
340 Generate a declaration for a function (SUB, FUNCTION, DESTRUCTOR,
341 CONSTRUCTOR, PROPERTY). We emit a type, a name and a parameter list.
342
343 Exceptions:
344
345 - in a declaration a CONSTRUCTOR or DESTRUCTOR have no name
346
347 '/
348 SUB cppCreateFunction CDECL(BYVAL P AS Parser PTR)
349 WITH *P
350 IF .DivTok THEN Code(.SubStr(.DivTok) & " ")
351
352 SELECT CASE AS CONST *.FunTok
353 CASE .TOK_CTOR
354 IF .NamTok THEN Code(.SubStr(.NamTok) & "::" & .SubStr(.NamTok)) ELSE _
355 Code(.BlockNam)
356 CASE .TOK_DTOR
357 IF .NamTok THEN Code(.SubStr(.NamTok) & "::~" & .SubStr(.NamTok)) ELSE _
358 Code("~" & .BlockNam)
359 CASE ELSE
360 Code(.SubStr(.FunTok))
361 IF .CalTok THEN Code("_" & .SubStr(.CalTok))
362 IF .AliTok THEN Code("_" & .SubStr(.AliTok))
363 IF .TypTok ANDALSO .As_Tok THEN _
364 Code("_" & .SubStr(.As_Tok) & "_")
365 cppCreateTypNam(P)
366 END SELECT : IF 0 = .ParTok THEN Code("()") : EXIT SUB
367
368 cEmitComments(P, *(.ParTok + 1))
369 Code(" (")
370 .parseListPara(@cppEntryListParameter)
371 IF .ListCount <= 0 THEN Code(")")
372 END WITH
373 END SUB
374
375
376 /'* \brief Create a function declaration
377 \param P the parser calling this handler
378
379 Generate a declaration for a function (SUB, FUNCTION, DESTRUCTOR,
380 CONSTRUCTOR, PROPERTY). We emit a type, a name and a parameter list.
381
382 Exceptions:
383
384 - in a declaration a CONSTRUCTOR or DESTRUCTOR have no name
385
386 '/
387 SUB cCreateFunction CDECL(BYVAL P AS Parser PTR)
388 WITH *P
389 SELECT CASE AS CONST *.FunTok
390 CASE .TOK_CTOR
391 Code(.SubStr(.FunTok) & " ")
392 IF .NamTok THEN Code(.SubStr(.NamTok) & "." & .SubStr(.NamTok)) _
393 ELSE Code(.BlockNam)
394 CASE .TOK_DTOR
395 Code(.SubStr(.FunTok) & " ")
396 IF .NamTok THEN Code(.SubStr(.NamTok) & "." & .SubStr(.NamTok)) _
397 ELSE Code(.BlockNam)
398 CASE ELSE
399 IF 0 = .TypTok THEN Code("void ")
400 cCreateTypNam(P)
401 END SELECT : IF 0 = .ParTok THEN Code("(void)") : EXIT SUB
402
403 cEmitComments(P, *(.ParTok + 1))
404 Code(" (")
405 .parseListPara(@cEntryListParameter)
406 IF .ListCount <= 0 THEN Code("void)")
407 END WITH
408 END SUB
409
410
411 /'* \brief Handler for an include line
412 \param P the parser calling this handler
413
414 Generate an \#include line. This line are useful for diagrams in
415 Doxygen.
416
417 '/
418 /'* \brief Emitter to generate an \#INCLUDE translation
419 \param P the parser calling this emitter
420
421 This emitter gets called when the parser finds an \#INCLUDE
422 statement. It creates a C translation and sends it to the output
423 stream. When option \em --tree is given it checks if the file has
424 been done allready. If not, it creates a new #Parser and starts its
425 scanning process.
426
427 '/
428 SUB c_include CDECL(BYVAL P AS Parser PTR)
429 WITH *P
430 cEmitComments(P, *(.Tk1 + 1))
431 VAR n = .SubStr(.NamTok)
432 Code("#include " & n)
433 IF 0 = OPT->InTree THEN EXIT SUB
434
435 STATIC AS STRING done, o_path
436 n = MID(n, 2, LEN(n) - 2)
437 VAR f = !"\n" & CURDIR & SLASH & n & !"\n"
438 IF .DivTok THEN IF INSTR(done, f) THEN EXIT SUB
439 done &= f
440
441 VAR fnr = FREEFILE : IF OPEN(n FOR INPUT AS #fnr) THEN EXIT SUB ELSE CLOSE #fnr
442 VAR oldpath = CURDIR
443 VAR c = INSTRREV(n, SLASH) : IF c THEN CHDIR(LEFT(n, c - 1))
444 VAR pars = NEW Parser(OPT->EmitIF)
445
446 SELECT CASE AS CONST OPT->RunMode
447 CASE OPT->FILE_OUT
448 VAR o_pathlen = LEN(o_path)
449 IF 0 = o_pathlen THEN
450 VAR d = CURDIR
451 VAR r = OPT->checkDir(OPT->OutPath)
452 o_path = CURDIR & SLASH
453 CHDIR d
454 IF r THEN ERROUT(" --> Couldn't create path: " & OPT->OutPath) : EXIT SUB
455 o_pathlen = LEN(o_path)
456 END IF
457
458 PRINT : MSG_LINE(n)
459 VAR f = o_path & LEFT(n, INSTRREV(n, "."))
460 IF LCASE(RIGHT(n, 3)) = ".bi" THEN f &= "h" ELSE f &= "c"
461
462 IF c THEN
463 o_path &= LEFT(n, c)
464 VAR d = CURDIR
465 VAR r = OPT->checkDir(o_path)
466 CHDIR d
467 IF r THEN ERROUT(" --> Couldn't create path.") : EXIT SELECT
468 END IF
469
470 pars->Ocha = FREEFILE
471 IF OPEN(f FOR OUTPUT, AS #pars->Ocha) THEN
472 ERROUT("Couldn't write " & f)
473 ELSE
474 pars->File_(MID(n, c + 1))
475 CLOSE #pars->Ocha
476 ERROUT(" --> " & f)
477 END IF
478 IF c THEN o_path = LEFT(o_path, o_pathlen)
479 CASE OPT->SCAN_LIST
480 PRINT : MSG_LINE(n)
481 pars->Ocha = .Ocha
482 pars->File_(MID(n, c + 1))
483 ERROUT(" --> scanned " & f)
484 CASE ELSE
485 pars->Ocha = .Ocha
486 pars->File_(MID(n, c + 1))
487 END SELECT
488
489 DELETE pars : IF c THEN CHDIR(oldpath)
490 END WITH
491 END SUB
492
493
494 /'* \brief Emitter to generate a macro translation
495 \param P the parser calling this emitter
496
497 This emitter gets called when the parser finds a macro (\#DEFINE /
498 \#MACRO). It generates a C translation of the macro and sends it
499 to the output stream.
500
501 '/
502 SUB c_defi_ CDECL(BYVAL P AS Parser PTR)
503 WITH *P
504 cEmitComments(P, *(.Tk1 + 1))
505
506 Code("#define ")
507 VAR a = *(.NamTok + 1), e = *(.TkEnd + 1)
508 IF *.StaTok = .TOK_MACR THEN
509 VAR l = *(.CurTok + 1) - a
510 Code(MID(.Buf, a + 1, l) & " /* (multi line FreeBasic #MACRO) ")
511 a += l
512 Code(MID(.Buf, a + 1, e - a) & " */ ")
513 ELSE
514 Code(MID(.Buf, a + 1, e - a))
515 END IF
516 .SrcBgn = e
517 END WITH
518 END SUB
519
520
521 /'* \brief Emitter to generate a function translation
522 \param P the parser calling this emitter
523
524 This emitter gets called when the parser finds a function (SUB /
525 FUNCTION / PROPERTY / CONSTRUCTOR / DESTRUCTOR). It translates a
526 function and its parameter list to C-like code and sends it to the
527 output stream. The function body is either empty or contains pseudo
528 calls.
529
530 '/
531 SUB c_func_ CDECL(BYVAL P AS Parser PTR) ' ToDo: internal function calls for diagrams
532 WITH *P
533 cEmitComments(P, *(.Tk1 + 1))
534
535 OPT->Function_(P)
536 Code(" {")
537
538 IF OPT->AllCallees THEN
539 VAR t = .CurTok, e = .TkEnd - 6
540 WHILE t < e
541 VAR c = *(t + 1) - 1
542 IF *t >= .TOK_ABST ANDALSO .Buf[c] <> ASC("@") THEN
543 VAR l = *(t + 2), s = UCASE(MID(.Buf, c + 2, l)), x = l
544 FOR i AS INTEGER = LEN(OPT->Callees) - 2 TO 0 STEP -1
545 x = l - 1
546 WHILE s[x] = (OPT->Callees[i] AND &b11011111)
547 x -= 1
548 i -= 1
549 IF x < 0 THEN
550 SELECT CASE AS CONST OPT->Callees[i]
551 CASE ASC(!"\n")
552 CASE ASC( ".")
553 x = i
554 DO : i -= 1 : LOOP UNTIL OPT->Callees[i] = ASC(!"\n") ORELSE i < 1
555 l += x - i
556 CASE ELSE : EXIT WHILE
557 END SELECT
558 cEmitComments(P, c + 1)
559 Code(" " & MID(OPT->Callees, i + 2, l) & "();")
560 EXIT FOR
561 END IF
562 WEND : DO : i -= 1 : LOOP UNTIL OPT->Callees[i] = ASC(!"\n") ORELSE i < 1
563 NEXT
564 END IF : t += 3
565 WEND
566 END IF
567
568 cEmitComments(P, *(.TkEnd + 1) - 1)
569 Code("};")
570 END WITH
571 END SUB
572
573
574 /'* \brief Emitter to generate a declaration translation
575 \param P the parser calling this emitter
576
577 This emitter gets called when the parser is in a declaration (VAR /
578 DIM / CONST / COMMON / EXTERN / STATIC). It generates a C
579 translation for each variable name and sends it (them) to the output
580 stream. Documantation comments get emitted at the appropriate place.
581 Each declaration get a single line, even if the original source code
582 is a comma-separated list. (This may destroy line synchonisation, so
583 it's better to place each declaration in a single line.)
584
585 '/
586 SUB c_decl_ CDECL(BYVAL P AS Parser PTR)
587 WITH *P
588 cEmitComments(P, *(.Tk1 + 1))
589
590 IF 0 = .ListCount THEN
591 SELECT CASE AS CONST *.StaTok
592 CASE .TOK_CONS : Code("const ")
593 CASE .TOK_STAT : Code("static ")
594 CASE .TOK_COMM : Code("common ")
595 CASE .TOK_EXRN : Code("extern ")
596 CASE .TOK_TYPE : Code("typedef ")
597 IF 0 = .FunTok ANDALSO .TypTok > .NamTok THEN Code("struct ")
598 END SELECT
599 END IF
600
601 IF .FunTok THEN : OPT->Function_(P)
602 ELSEIF .TypTok THEN : OPT->Variable_(P)
603 ELSE
604 IF 0 = .ListCount THEN Code("VAR ")
605 Code(.SubStr(.NamTok))
606 IF .BitTok THEN Code(.BitIni)
607 IF .IniTok THEN Code(.VarIni)
608 END IF
609 IF *.CurTok <= .TOK_EOS THEN Code(";") : EXIT SUB
610 IF .NamTok > .TypTok _
611 THEN Code(", ") _
612 ELSE Code("; ")
613 END WITH
614 END SUB
615
616
617 /'* \brief Handler for an enumerator entry (inside ENUM block)
618 \param P the parser calling this handler
619
620 Generate an enumerator in an enum block. Name, initializers and
621 documentation comments are emitted. Logical operators like SHL or
622 AND are not handled jet.
623
624 '/
625 SUB cEntryBlockENUM CDECL(BYVAL P AS Parser PTR)
626 WITH *P
627 cEmitComments(P, *(.Tk1 + 1))
628
629 IF 0 = .ListCount THEN Code(STRING(.LevelCount * 2, " "))
630 Code(.SubStr(.NamTok))
631 IF .IniTok THEN Code(.VarIni)
632 IF *.CurTok <> .TOK_END THEN Code(", ")
633 END WITH
634 END SUB
635
636
637 DECLARE SUB c_Block CDECL(BYVAL AS Parser PTR)
638
639 /'* \brief Handler for a context line (TYPE / UNION block)
640 \param P the parser calling this handler
641
642 Generate a line in an struct or union block. Type, name,
643 initializers and documentation comments are emitted. Logical
644 operators like SHL or AND are not handled jet.
645
646 '/
647 SUB cEntryBlockTypeUnion CDECL(BYVAL P AS Parser PTR)
648 WITH *P
649 cEmitComments(P, *(.Tk1 + 1))
650
651 SELECT CASE AS CONST *.Tk1
652 CASE .TOK_PRIV : Code("private:")
653 CASE .TOK_PROT : Code("protected:")
654 CASE .TOK_PUBL : Code("public:")
655 CASE .TOK_ENUM, .TOK_UNIO, .TOK_TYPE, .TOK_CLAS : c_Block(P)
656 CASE ELSE
657 IF 0 = .ListCount THEN Code(STRING(.LevelCount * 2, " "))
658 IF *.Tk1 = .TOK_DECL THEN OPT->Function_(P) : Code(";") : EXIT SUB
659 IF .FunTok THEN OPT->Function_(P) _
660 ELSE OPT->Variable_(P)
661 IF *.CurTok <= .TOK_EOS THEN Code(";") : EXIT SUB
662 IF .NamTok > .TypTok THEN Code(",") ELSE Code("; ")
663 END SELECT
664 END WITH
665 END SUB
666
667
668 /'* \brief Emitter to generate a block translation
669 \param P the parser calling this emitter
670
671 This emitter gets called when the parser finds a block (TYPE / UNION
672 / ENUM). It generates a C translation of the block and sends it to
673 the output stream.
674
675 '/
676 SUB c_Block CDECL(BYVAL P AS Parser PTR)
677 WITH *P
678 cEmitComments(P, *(.Tk1 + 1))
679
680 IF .LevelCount THEN Code(STRING(.LevelCount * 2, " "))
681 SELECT CASE AS CONST *.Tk1
682 CASE .TOK_TYPE, .TOK_CLAS
683 IF OPT->Types = OPT->FB_STYLE THEN
684 Code("class " & .BlockNam & "{")
685 .parseBlockTyUn(@cEntryBlockTypeUnion)
686 .BlockNam = ""
687 ELSE
688 IF 0 = .LevelCount ANDALSO LEN(.BlockNam) THEN Code("typedef ")
689 Code("struct " & .BlockNam & "{")
690 .parseBlockTyUn(@cEntryBlockTypeUnion)
691 END IF
692 CASE .TOK_UNIO
693 IF 0 = .LevelCount ANDALSO LEN(.BlockNam) THEN Code("typedef ")
694 Code("union " & .BlockNam & "{")
695 .parseBlockTyUn(@cEntryBlockTypeUnion)
696 CASE .TOK_ENUM
697 IF 0 = .LevelCount ANDALSO LEN(.BlockNam) THEN Code("typedef ")
698 Code("enum " & .BlockNam & "{")
699 .parseBlockEnum(@cEntryBlockENUM)
700 CASE ELSE : Code("-???-")
701 END SELECT
702
703 cEmitComments(P, *(.Tk1 + 1))
704 IF .LevelCount THEN Code(STRING(.LevelCount * 2, " "))
705 IF LEN(.BlockNam) THEN Code("} " & .BlockNam & ";") _
706 ELSE Code("};")
707 END WITH
708 END SUB
709
710
711 /'* \brief Emitter for an error message
712 \param P the parser calling this handler
713
714 Generate an error output. When the parser detects an error it calls
715 this function. Depending on the run-mode we do or do not emit an
716 information. In \em --geany mode the error message gets shown in the
717 status line (or in the debug window).
718
719 '/
720 SUB c_error CDECL(BYVAL P AS Parser PTR)
721 WITH *P
722 SELECT CASE AS CONST OPT->RunMode
723 CASE OPT->GEANYFILTER ': EXIT SUB ' or shall we output?
724 Code(NL & "'!!! " & PROG_NAME & .ErrMsg & "!" & NL)
725 CASE ELSE
726 ERROUT("==> " & PROG_NAME & .ErrMsg & "!")
727 END SELECT
728 END WITH
729 END SUB
730
731
732 /'* \brief Emitter to be calles before parsing
733 \param P the parser calling this emitter
734
735 This emitter gets called before the parser starts its parsing
736 process. It initializes the FB source code emission.
737
738 '/
739 SUB c_Init CDECL(BYVAL P AS Parser PTR)
740 P->SrcBgn = 0
741 END SUB
742
743
744 /'* \brief Emitter to be calles after parsing
745 \param P the parser calling this emitter
746
747 This emitter gets called after the parser ands its parsing process.
748 It sends the rest of the FB source code to the output stream.
749
750 '/
751 SUB c_exit CDECL(BYVAL P AS Parser PTR)
752 cEmitComments(P, P->Fin)
753 END SUB
754
755
756 ' place the handlers in the emitter interface
757 WITH_NEW_EMITTER("C_Source")
758
759 ._Error_ = @c_error
760
761 .Defi_ = @c_defi_
762 .Incl_ = @c_include
763 .Func_ = @c_func_
764 .Decl_ = @c_decl_
765 .Enum_ = @c_Block
766 .Unio_ = @c_Block
767 .Clas_ = @c_Block
768
769 ._Init_ = @c_Init
770 ._Exit_ = @c_exit
771 END WITH
772
773
774 /'* \brief Handler for exporting FreeBasic source code
775 \param P the parser calling this handler
776 \param E the end position in the input buffer Parser::Buf
777
778 Extract original source code from the input buffer Parser::Buf. The
779 code starts at the last position and gets extracted up to the line end
780 before the given position. This line end gets stored as the new 'last
781 position'.
782
783 '/
784 SUB cEmitSource CDECL(BYVAL P AS Parser PTR, BYVAL E AS INTEGER)
785 WITH *P
786 DO : IF E > 0 THEN E -= 1 ELSE EXIT SUB
787 LOOP UNTIL .Buf[E] = ASC(!"\n")
788 VAR a = .SrcBgn, l = E - a : .SrcBgn = E + 1
789 Code(MID(.Buf, a + 1, l + 1))
790 END WITH
791 END SUB
792
793
794 /'* \brief Handler for FIXME
795 \param P the parser calling this handler
796
797 Generate FIXME
798
799 '/
800 SUB geanyInit CDECL(BYVAL P AS Parser PTR)
801 P->SrcBgn = 0
802 END SUB
803
804
805 /'* \brief Handler for FIXME
806 \param P the parser calling this handler
807
808 Generate FIXME
809
810 '/
811 SUB geanyExit CDECL(BYVAL P AS Parser PTR)
812 WITH *P
813 Code(MID(.Buf, .SrcBgn + 1))
814 END WITH
815 END SUB
816
817
818 #INCLUDE ONCE "fb-doc_emit_callees.bas"
819 #INCLUDE ONCE "fb-doc_emit_gtk.bas"
820 #INCLUDE ONCE "fb-doc_emit_doxy.bas"
821