FreeBASIC  0.91.0
fb.bas
Go to the documentation of this file.
1 '' fb - main interface
2 ''
3 '' chng: sep/2004 written [v1ctor]
4 
5 
6 #include once "fb.bi"
7 #include once "fbint.bi"
8 #include once "parser.bi"
9 #include once "lex.bi"
10 #include once "rtl.bi"
11 #include once "ast.bi"
12 #include once "ir.bi"
13 #include once "objinfo.bi"
14 
16  name as const zstring ptr
18 end type
19 
20 declare sub parserInit ( )
21 
22 declare sub parserEnd ( )
23 
24 declare sub parserSetCtx ( )
25 
26 '' globals
27  dim shared infileTb( ) as FBFILE
28 
29  dim shared as FB_LANG_INFO langTb(0 to FB_LANGS-1) = _
30  { _
31  ( _
32  @"fb", _
33  FB_LANG_OPT_MT or _
34  FB_LANG_OPT_SCOPE or _
35  FB_LANG_OPT_NAMESPC or _
36  FB_LANG_OPT_EXTERN or _
37  FB_LANG_OPT_FUNCOVL or _
38  FB_LANG_OPT_OPEROVL or _
39  FB_LANG_OPT_CLASS or _
40  FB_LANG_OPT_INITIALIZER or _
41  FB_LANG_OPT_AUTOVAR or _
42  FB_LANG_OPT_SINGERRLINE or _
43  FB_LANG_OPT_QUIRKFUNC _
44  ) _
45  , _
46  ( _
47  @"deprecated", _
48  FB_LANG_OPT_MT or _
49  FB_LANG_OPT_SCOPE or _
50  FB_LANG_OPT_NAMESPC or _
51  FB_LANG_OPT_EXTERN or _
52  FB_LANG_OPT_FUNCOVL or _
53  FB_LANG_OPT_INITIALIZER or _
54  FB_LANG_OPT_CALL or _
55  FB_LANG_OPT_LET or _
56  FB_LANG_OPT_PERIODS or _
57  FB_LANG_OPT_NUMLABEL or _
58  FB_LANG_OPT_IMPLICIT or _
59  FB_LANG_OPT_DEFTYPE or _
60  FB_LANG_OPT_SUFFIX or _
61  FB_LANG_OPT_METACMD or _
62  FB_LANG_OPT_OPTION or _
63  FB_LANG_OPT_ONERROR or _
64  FB_LANG_OPT_QUIRKFUNC _
65  ) _
66  , _
67  ( _
68  @"fblite", _
69  FB_LANG_OPT_MT or _
70  FB_LANG_OPT_NAMESPC or _
71  FB_LANG_OPT_EXTERN or _
72  FB_LANG_OPT_FUNCOVL or _
73  FB_LANG_OPT_INITIALIZER or _
74  FB_LANG_OPT_GOSUB or _
75  FB_LANG_OPT_CALL or _
76  FB_LANG_OPT_LET or _
77  FB_LANG_OPT_PERIODS or _
78  FB_LANG_OPT_NUMLABEL or _
79  FB_LANG_OPT_IMPLICIT or _
80  FB_LANG_OPT_DEFTYPE or _
81  FB_LANG_OPT_SUFFIX or _
82  FB_LANG_OPT_METACMD or _
83  FB_LANG_OPT_OPTION or _
84  FB_LANG_OPT_ONERROR or _
85  FB_LANG_OPT_QUIRKFUNC _
86  ) _
87  , _
88  ( _
89  @"qb", _
90  FB_LANG_OPT_GOSUB or _
91  FB_LANG_OPT_CALL or _
92  FB_LANG_OPT_LET or _
93  FB_LANG_OPT_PERIODS or _
94  FB_LANG_OPT_NUMLABEL or _
95  FB_LANG_OPT_IMPLICIT or _
96  FB_LANG_OPT_DEFTYPE or _
97  FB_LANG_OPT_SUFFIX or _
98  FB_LANG_OPT_METACMD or _
99  FB_LANG_OPT_OPTION or _
100  FB_LANG_OPT_ONERROR or _
101  FB_LANG_OPT_QUIRKFUNC _
102  ) _
103  }
104 
105 dim shared as FBTARGET targetinfo(0 to FB_COMPTARGETS-1) = _
106 { _
107  ( _
108  @"win32", _ '' id
109  FB_DATATYPE_UINT, _ '' 32bit size_t
110  FB_DATATYPE_ULONGINT, _ '' 64bit size_t
111  FB_DATATYPE_USHORT, _ '' wchar
112  FB_FUNCMODE_STDCALL, _ '' fbcall
113  FB_FUNCMODE_STDCALL, _ '' stdcall
114  0 or FB_TARGETOPT_UNDERSCORE _
115  or FB_TARGETOPT_EXPORT _
116  or FB_TARGETOPT_RETURNINREGS _
117  ), _
118  ( _
119  @"cygwin", _
120  FB_DATATYPE_UINT, _
121  FB_DATATYPE_ULONGINT, _
122  FB_DATATYPE_USHORT, _
123  FB_FUNCMODE_STDCALL, _
124  FB_FUNCMODE_STDCALL, _
125  0 or FB_TARGETOPT_UNIX _
126  or FB_TARGETOPT_UNDERSCORE _
127  or FB_TARGETOPT_EXPORT _
128  or FB_TARGETOPT_RETURNINREGS _
129  ), _
130  ( _
131  @"linux", _
132  FB_DATATYPE_UINT, _
133  FB_DATATYPE_UINT, _
134  FB_DATATYPE_ULONG, _
135  FB_FUNCMODE_CDECL, _
136  FB_FUNCMODE_STDCALL_MS, _
137  0 or FB_TARGETOPT_UNIX _
138  or FB_TARGETOPT_CALLEEPOPSHIDDENPTR _
139  ), _
140  ( _
141  @"dos", _
142  FB_DATATYPE_ULONG, _
143  FB_DATATYPE_ULONG, _
144  FB_DATATYPE_UBYTE, _
145  FB_FUNCMODE_CDECL, _
146  FB_FUNCMODE_STDCALL_MS, _
147  0 or FB_TARGETOPT_UNDERSCORE _
148  or FB_TARGETOPT_CALLEEPOPSHIDDENPTR _
149  ), _
150  ( _
151  @"xbox", _
152  FB_DATATYPE_ULONG, _
153  FB_DATATYPE_ULONG, _
154  FB_DATATYPE_ULONG, _
155  FB_FUNCMODE_STDCALL, _
156  FB_FUNCMODE_STDCALL, _
157  0 or FB_TARGETOPT_UNDERSCORE _
158  or FB_TARGETOPT_RETURNINREGS _
159  ), _
160  ( _
161  @"freebsd", _
162  FB_DATATYPE_UINT, _
163  FB_DATATYPE_UINT, _
164  FB_DATATYPE_ULONG, _
165  FB_FUNCMODE_CDECL, _
166  FB_FUNCMODE_STDCALL_MS, _
167  0 or FB_TARGETOPT_UNIX _
168  or FB_TARGETOPT_CALLEEPOPSHIDDENPTR _
169  or FB_TARGETOPT_RETURNINREGS _
170  ), _
171  ( _
172  @"openbsd", _
173  FB_DATATYPE_UINT, _
174  FB_DATATYPE_UINT, _
175  FB_DATATYPE_ULONG, _
176  FB_FUNCMODE_CDECL, _
177  FB_FUNCMODE_STDCALL_MS, _
178  0 or FB_TARGETOPT_UNIX _
179  or FB_TARGETOPT_CALLEEPOPSHIDDENPTR _
180  or FB_TARGETOPT_RETURNINREGS _
181  ), _
182  ( _
183  @"darwin", _
184  FB_DATATYPE_UINT, _
185  FB_DATATYPE_UINT, _
186  FB_DATATYPE_ULONG, _
187  FB_FUNCMODE_CDECL, _
188  FB_FUNCMODE_STDCALL_MS, _
189  0 or FB_TARGETOPT_UNIX _
190  or FB_TARGETOPT_CALLEEPOPSHIDDENPTR _
191  or FB_TARGETOPT_RETURNINREGS _
192  ), _
193  ( _
194  @"netbsd", _
195  FB_DATATYPE_UINT, _
196  FB_DATATYPE_UINT, _
197  FB_DATATYPE_ULONG, _
198  FB_FUNCMODE_CDECL, _
199  FB_FUNCMODE_STDCALL_MS, _
200  0 or FB_TARGETOPT_UNIX _
201  or FB_TARGETOPT_CALLEEPOPSHIDDENPTR _
202  or FB_TARGETOPT_RETURNINREGS _
203  ) _
204 }
205 
207  gccarch as zstring ptr '' gcc -march argument (used for -gen gcc)
208  fbcarch as zstring ptr '' fbc -arch argument
209  is_x86 as integer
210  bits as integer
211 end type
212 
213 dim shared as FBCPUTYPEINFO cputypeinfo(0 to FB_CPUTYPE__COUNT-1) = _
214 { _
215  ( @"i386" , @"386" , TRUE , 32 ), _ '' FB_CPUTYPE_386
216  ( @"i486" , @"486" , TRUE , 32 ), _ '' FB_CPUTYPE_486
217  ( @"i586" , @"586" , TRUE , 32 ), _ '' FB_CPUTYPE_586
218  ( @"i686" , @"686" , TRUE , 32 ), _ '' FB_CPUTYPE_686
219  ( @"athlon" , @"athlon" , TRUE , 32 ), _ '' FB_CPUTYPE_ATHLON
220  ( @"athlon-xp" , @"athlon-xp" , TRUE , 32 ), _ '' FB_CPUTYPE_ATHLONXP
221  ( @"athlon-fx" , @"athlon-fx" , TRUE , 32 ), _ '' FB_CPUTYPE_ATHLONFX
222  ( @"k8-sse3" , @"k8-sse3" , TRUE , 32 ), _ '' FB_CPUTYPE_ATHLONSSE3
223  ( @"pentium-mmx", @"pentium-mmx" , TRUE , 32 ), _ '' FB_CPUTYPE_PENTIUMMMX
224  ( @"pentium2" , @"pentium2" , TRUE , 32 ), _ '' FB_CPUTYPE_PENTIUM2
225  ( @"pentium3" , @"pentium3" , TRUE , 32 ), _ '' FB_CPUTYPE_PENTIUM3
226  ( @"pentium4" , @"pentium4" , TRUE , 32 ), _ '' FB_CPUTYPE_PENTIUM4
227  ( @"prescott" , @"pentium4-sse3", TRUE , 32 ), _ '' FB_CPUTYPE_PENTIUMSSE3
228  ( @"x86-64" , @"x86-64" , FALSE, 64 ), _ '' FB_CPUTYPE_X86_64
229  ( NULL , @"32" , FALSE, 32 ), _ '' FB_CPUTYPE_32
230  ( NULL , @"64" , FALSE, 64 ), _ '' FB_CPUTYPE_64
231  ( NULL , NULL , FALSE, 0 ) _ '' FB_CPUTYPE_NATIVE
232 }
233 
234 ''::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
235 '' interface
236 ''::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
237 
238 '':::::
239 function hFindIncFile _
240  ( _
241  byval incfilehash as THASH ptr, _
242  byval filename as zstring ptr _
243  ) as zstring ptr static
244 
245  dim as string fname
246 
247 #if defined( __FB_WIN32__ ) or defined( __FB_DOS__ )
248  fname = ucase( *filename )
249 #else
250  fname = *filename
251 #endif
252 
253  function = hashLookup( incfilehash, fname )
254 
255 end function
256 
257 '':::::
258 function hAddIncFile _
259  ( _
260  byval incfilehash as THASH ptr, _
261  byval filename as zstring ptr _
262  ) as zstring ptr static
263 
264  dim as zstring ptr fname, res
265  dim as uinteger index
266 
267  fname = xallocate( len( *filename ) + 1 )
268 #if defined( __FB_WIN32__ ) or defined( __FB_DOS__ )
269  hUcase( filename, fname )
270 #else
271  *fname = *filename
272 #endif
273 
274  index = hashHash( fname )
275 
276  res = hashLookupEx( incfilehash, fname, index )
277  if( res = NULL ) then
278  hashAdd( incfilehash, fname, fname, index )
279  else
280  deallocate( fname )
281  fname = res
282  end if
283 
284  function = fname
285 
286 end function
287 
288 '':::::
289 function fbGetLangOptions _
290  ( _
291  byval lang as FB_LANG _
292  ) as FB_LANG_OPT
293 
294  function = langTb(lang).options
295 
296 end function
297 
298 '':::::
299 function fbGetLangName _
300  ( _
301  byval lang as FB_LANG _
302  ) as string
303 
304  function = *langTb(lang).name
305 
306 end function
307 
308 sub fbInit( byval ismain as integer, byval restarts as integer )
309  strsetInit( @env.libs, FB_INITLIBNODES \ 4 )
310  strsetInit( @env.libpaths, FB_INITLIBNODES \ 4 )
311 
312  env.restarts = restarts
313  env.dorestart = FALSE
314 
315  redim infileTb( 0 to FB_MAXINCRECLEVEL-1 )
316 
317  env.includerec = 0
318  env.main.proc = NULL
319 
320  env.opt.explicit = (env.clopt.lang = FB_LANG_FB)
321 
322  '' data type remapping
323  if( env.clopt.lang <> FB_LANG_QB ) then
324  '' In FB, the INTEGER keyword produces FB_DATATYPE_INTEGER
325  env.lang.integerkeyworddtype = FB_DATATYPE_INTEGER
326 
327  '' In FB, both 16bit/32bit number literals are made INTEGERs,
328  '' and floats are DOUBLE by default.
329  env.lang.int15literaldtype = FB_DATATYPE_INTEGER
330  env.lang.int16literaldtype = FB_DATATYPE_UINT
331  env.lang.int31literaldtype = FB_DATATYPE_INTEGER
332  env.lang.int32literaldtype = FB_DATATYPE_UINT
333  env.lang.floatliteraldtype = FB_DATATYPE_DOUBLE
334  else
335  '' In QB, the INTEGER keyword produces FB_DATATYPE_SHORT
336  '' (Note: FB_DATATYPE_INTEGER remains unchanged, it's just that
337  '' FB_DATATYPE_SHORT is being used instead in some places)
338  env.lang.integerkeyworddtype = FB_DATATYPE_SHORT
339 
340  '' In QB, 16bit number literals are made SHORTs (i.e. QB's
341  '' 16bit INTEGERs), and 32bit number literals are 32bit LONGs,
342  '' not FB 32bit/64bit INTEGERs. Floats are SINGLEs by default.
343  env.lang.int15literaldtype = FB_DATATYPE_SHORT
344  env.lang.int16literaldtype = FB_DATATYPE_USHORT
345  env.lang.int31literaldtype = FB_DATATYPE_LONG
346  env.lang.int32literaldtype = FB_DATATYPE_ULONG
347  env.lang.floatliteraldtype = FB_DATATYPE_SINGLE
348  end if
349 
350  env.opt.parammode = FB_PARAMMODE_BYREF
351  env.opt.procpublic = TRUE
352  env.opt.escapestr = FALSE
353  env.opt.dynamic = FALSE
354  env.opt.base = 0
355  env.opt.gosub = (env.clopt.lang = FB_LANG_QB)
356 
357  env.fbctinf_started = FALSE
358 
359  parserSetCtx( )
360  symbInit( ismain )
361  errInit( )
362  astInit( )
363  irInit( )
364 
365  '' After symbInit(), we can use typeGetSize()
366  env.wchar_doconv = (sizeof( wstring ) = typeGetSize( env.target.wchar ))
367  env.pointersize = typeGetSize( typeAddrOf( FB_DATATYPE_VOID ) )
368 
369  hashInit( @env.incfilehash, FB_INITINCFILES )
370  hashInit( @env.inconcehash, FB_INITINCFILES )
371 
372  stackNew( @parser.stmt.stk, FB_INITSTMTSTACKNODES, len( FB_CMPSTMTSTK ), FALSE )
373  lexInit( FALSE )
374  parserInit( )
375  rtlInit( )
376 end sub
377 
378 sub fbEnd()
379  rtlEnd( )
380  parserEnd( )
381  lexEnd( )
382  stackFree( @parser.stmt.stk )
383 
384  hashEnd( @env.inconcehash )
385  hashEnd( @env.incfilehash )
386 
387  irEnd( )
388  astEnd( )
389  errEnd( )
390  symbEnd( )
391 
392  erase infileTb
393  strsetEnd(@env.libs)
394  strsetEnd(@env.libpaths)
395 end sub
396 
398  env.lang.opt = langTb(env.clopt.lang).options
399 end sub
400 
402  env.target = targetinfo(env.clopt.target)
403 end sub
404 
406  '' -gen gas defaults to -asm intel, because that's all it supports,
407  '' -gen gcc/llvm defaults to -asm att, because that's GCC's/LLVM's standard
408  if( env.clopt.backend = FB_BACKEND_GAS ) then
409  env.clopt.asmsyntax = FB_ASMSYNTAX_INTEL
410  else
411  env.clopt.asmsyntax = FB_ASMSYNTAX_ATT
412  end if
413 end sub
414 
416  strlistInit(@env.predefines, FB_INITINCFILES)
417  strlistInit(@env.preincludes, FB_INITINCFILES)
418  strlistInit(@env.includepaths, FB_INITINCFILES)
419 
420  '' default settings
421  env.clopt.outtype = FB_DEFAULT_OUTTYPE
422  env.clopt.pponly = FALSE
423 
424  env.clopt.backend = FB_DEFAULT_BACKEND
425  env.clopt.target = FB_DEFAULT_TARGET
426  env.clopt.cputype = FB_DEFAULT_CPUTYPE
427  env.clopt.fputype = FB_DEFAULT_FPUTYPE
428  env.clopt.fpmode = FB_DEFAULT_FPMODE
429  env.clopt.vectorize = FB_DEFAULT_VECTORIZELEVEL
430  env.clopt.optlevel = 0
431 
432  env.clopt.lang = FB_DEFAULT_LANG
433  env.clopt.forcelang = FALSE
434 
435  env.clopt.debug = FALSE
436  env.clopt.errorcheck = FALSE
437  env.clopt.extraerrchk = FALSE
438  env.clopt.resumeerr = FALSE
439  env.clopt.profile = FALSE
440 
441  env.clopt.warninglevel = 0
442  env.clopt.showerror = TRUE
443  env.clopt.maxerrors = FB_DEFAULT_MAXERRORS
444  env.clopt.pdcheckopt = FB_PDCHECK_NONE
445 
446  env.clopt.gosubsetjmp = FALSE
447  env.clopt.export = FALSE
448  env.clopt.multithreaded = FALSE
449  env.clopt.msbitfields = FALSE
450  env.clopt.stacksize = FB_DEFSTACKSIZE
451 
455 end sub
456 
457 sub fbAddIncludePath(byref path as string)
458  strlistAppend(@env.includepaths, path)
459 end sub
460 
461 sub fbAddPreDefine(byref def as string)
462  strlistAppend(@env.predefines, def)
463 end sub
464 
465 sub fbAddPreInclude(byref file as string)
466  strlistAppend(@env.preincludes, file)
467 end sub
468 
469 sub fbSetOption( byval opt as integer, byval value as integer )
470  select case as const( opt )
471  case FB_COMPOPT_OUTTYPE
472  env.clopt.outtype = value
473  case FB_COMPOPT_PPONLY
474  env.clopt.pponly = value
475 
476  case FB_COMPOPT_BACKEND
477  env.clopt.backend = value
479  case FB_COMPOPT_TARGET
480  env.clopt.target = value
482  case FB_COMPOPT_CPUTYPE
483  env.clopt.cputype = value
484  case FB_COMPOPT_FPUTYPE
485  env.clopt.fputype = value
486  case FB_COMPOPT_FPMODE
487  env.clopt.fpmode = value
488  case FB_COMPOPT_VECTORIZE
489  env.clopt.vectorize = value
490  case FB_COMPOPT_OPTIMIZELEVEL
491  env.clopt.optlevel = value
492  case FB_COMPOPT_ASMSYNTAX
493  env.clopt.asmsyntax = value
494 
495  case FB_COMPOPT_LANG
496  env.clopt.lang = value
498  case FB_COMPOPT_FORCELANG
499  env.clopt.forcelang = value
500 
501  case FB_COMPOPT_DEBUG
502  env.clopt.debug = value
503  case FB_COMPOPT_ERRORCHECK
504  env.clopt.errorcheck = value
505  case FB_COMPOPT_RESUMEERROR
506  env.clopt.resumeerr = value
507  case FB_COMPOPT_EXTRAERRCHECK
508  env.clopt.extraerrchk = value
509  case FB_COMPOPT_PROFILE
510  env.clopt.profile = value
511 
512  case FB_COMPOPT_WARNINGLEVEL
513  env.clopt.warninglevel = value
514  case FB_COMPOPT_SHOWERROR
515  env.clopt.showerror = value
516  case FB_COMPOPT_MAXERRORS
517  env.clopt.maxerrors = value
518  case FB_COMPOPT_PEDANTICCHK
519  env.clopt.pdcheckopt = value
520 
521  case FB_COMPOPT_GOSUBSETJMP
522  env.clopt.gosubsetjmp = value
523  case FB_COMPOPT_EXPORT
524  env.clopt.export = value
525  case FB_COMPOPT_MSBITFIELDS
526  env.clopt.msbitfields = value
527  case FB_COMPOPT_MULTITHREADED
528  env.clopt.multithreaded = value
529  case FB_COMPOPT_STACKSIZE
530  env.clopt.stacksize = value
531  if (env.clopt.stacksize < FB_MINSTACKSIZE) then
532  env.clopt.stacksize = FB_MINSTACKSIZE
533  end if
534  end select
535 end sub
536 
537 function fbGetOption( byval opt as integer ) as integer
538  select case as const( opt )
539  case FB_COMPOPT_OUTTYPE
540  function = env.clopt.outtype
541  case FB_COMPOPT_PPONLY
542  function = env.clopt.pponly
543 
544  case FB_COMPOPT_BACKEND
545  function = env.clopt.backend
546  case FB_COMPOPT_TARGET
547  function = env.clopt.target
548  case FB_COMPOPT_CPUTYPE
549  function = env.clopt.cputype
550  case FB_COMPOPT_FPUTYPE
551  function = env.clopt.fputype
552  case FB_COMPOPT_FPMODE
553  function = env.clopt.fpmode
554  case FB_COMPOPT_VECTORIZE
555  function = env.clopt.vectorize
556  case FB_COMPOPT_OPTIMIZELEVEL
557  function = env.clopt.optlevel
558  case FB_COMPOPT_ASMSYNTAX
559  function = env.clopt.asmsyntax
560 
561  case FB_COMPOPT_LANG
562  function = env.clopt.lang
563  case FB_COMPOPT_FORCELANG
564  function = env.clopt.forcelang
565 
566  case FB_COMPOPT_DEBUG
567  function = env.clopt.debug
568  case FB_COMPOPT_ERRORCHECK
569  function = env.clopt.errorcheck
570  case FB_COMPOPT_RESUMEERROR
571  function = env.clopt.resumeerr
572  case FB_COMPOPT_EXTRAERRCHECK
573  function = env.clopt.extraerrchk
574  case FB_COMPOPT_PROFILE
575  function = env.clopt.profile
576 
577  case FB_COMPOPT_WARNINGLEVEL
578  function = env.clopt.warninglevel
579  case FB_COMPOPT_SHOWERROR
580  function = env.clopt.showerror
581  case FB_COMPOPT_MAXERRORS
582  function = env.clopt.maxerrors
583  case FB_COMPOPT_PEDANTICCHK
584  function = env.clopt.pdcheckopt
585 
586  case FB_COMPOPT_GOSUBSETJMP
587  function = env.clopt.gosubsetjmp
588  case FB_COMPOPT_EXPORT
589  function = env.clopt.export
590  case FB_COMPOPT_MSBITFIELDS
591  function = env.clopt.msbitfields
592  case FB_COMPOPT_MULTITHREADED
593  function = env.clopt.multithreaded
594  case FB_COMPOPT_STACKSIZE
595  function = env.clopt.stacksize
596 
597  case else
598  function = 0
599  end select
600 end function
601 
602 '':::::
603 sub fbChangeOption(byval opt as integer, byval value as integer)
604  select case as const opt
605  case FB_COMPOPT_MSBITFIELDS
606  fbSetOption( opt, value )
607 
608  case FB_COMPOPT_LANG
609  '' If not yet in the desired mode
610  if( value <> fbGetOption( opt ) ) then
611  '' Not module level? then error
612  if( parser.scope <> FB_MAINSCOPE ) then
613 
614  if( fbIsModLevel( ) = FALSE ) then
615  errReport( FB_ERRMSG_ILLEGALINSIDEASUB )
616  else
617  errReport( FB_ERRMSG_ILLEGALINSIDEASCOPE )
618  end if
619 
620  '' module level
621  else
622  '' If -forcelang is enabled, ignore #lang directives
623  if( env.clopt.forcelang ) then
624  errReportWarn( FB_WARNINGMSG_CMDLINEOVERRIDES )
625  else
626 
627  '' First pass?
628  if( env.restarts = 0 ) then
629  fbSetOption( opt, value )
630 
631  '' Tell parser to restart as soon as possible
632  env.dorestart = TRUE
633 
634  '' and don't show any more errors
636 
637  '' Second pass? Show a warning and ignore
638  else
639  errReportWarn( FB_WARNINGMSG_DIRECTIVEIGNORED )
640  end if
641 
642  end if
643 
644  end if
645 
646  end if
647 
648  case else
649  errReport( FB_ERRMSG_INTERNAL )
650 
651  end select
652 end sub
653 
654 '':::::
655 function fbIsCrossComp _
656  ( _
657  ) as integer
658 
659  function = (env.clopt.target <> FB_DEFAULT_TARGET)
660 
661 end function
662 
663 function fbGetTargetId( ) as zstring ptr
664  function = env.target.id
665 end function
666 
667 function fbGetGccArch( ) as zstring ptr
668  function = cputypeinfo(env.clopt.cputype).gccarch
669 end function
670 
671 function fbGetFbcArch( ) as zstring ptr
672  function = cputypeinfo(env.clopt.cputype).fbcarch
673 end function
674 
675 function fbCpuTypeIs64bit( ) as integer
676  function = (cputypeinfo(env.clopt.cputype).bits = 64)
677 end function
678 
679 function fbCpuTypeIsX86( ) as integer
680  function = cputypeinfo(env.clopt.cputype).is_x86
681 end function
682 
683 function fbIdentifyFbcArch( byref fbcarch as string ) as integer
684  select case( fbcarch )
685  case "native"
686  '' On x86 we can check fb_CpuDetect(), otherwise just use the
687  '' default, which is always safe for the host.
688  function = FB_DEFAULT_CPUTYPE
689 
690  #ifndef __FB_64BIT__
691  select case( fb_CpuDetect( ) shr 28 )
692  case 3 : function = FB_CPUTYPE_386
693  case 4 : function = FB_CPUTYPE_486
694  case 5 : function = FB_CPUTYPE_586
695  case 6 : function = FB_CPUTYPE_686
696  end select
697  #endif
698 
699  exit function
700 
701  case "32"
702  return FB_DEFAULT_CPUTYPE32
703  case "64"
704  return FB_DEFAULT_CPUTYPE64
705  end select
706 
707  for i as integer = 0 to FB_CPUTYPE__COUNT-1
708  if( *cputypeinfo(i).fbcarch = fbcarch ) then
709  return i
710  end if
711  next
712 
713  '' Extra names to be recognized by -arch to make it nicer to use
714  select case( fbcarch )
715  case "x86_64", "amd64"
716  function = FB_CPUTYPE_X86_64
717  case else
718  function = -1
719  end select
720 end function
721 
722 '':::::
723 function fbGetEntryPoint( ) as string static
724 
725  '' All targets use main(), except for xbox...
726  if (env.clopt.target = FB_COMPTARGET_XBOX) then
727  function = "XBoxStartup"
728  else
729  function = "main"
730  end if
731 
732 end function
733 
734 '':::::
735 function fbGetModuleEntry( ) as string static
736  dim as string sname
737 
738  sname = hStripPath( hStripExt( env.outf.name ) )
739 
740  hClearName( sname )
741 
742  function = "fb_ctor__" + sname
743 
744 end function
745 
746 function fbGetInputFileParentDir( ) as string
747  dim as string s
748 
749  '' Input file name is using a relative path?
750  if( pathIsAbsolute( env.inf.name ) = FALSE ) then
751  '' Then build the absolute path based on curdir()
752  s = hCurDir( ) + FB_HOST_PATHDIV
753  end if
754 
755  function = pathStripDiv( hStripFilename( s + env.inf.name ) )
756 end function
757 
758 '' Used to add libs found during parsing (#inclib, Lib "...", rtl-* callbacks)
759 sub fbAddLib(byval libname as zstring ptr)
760  strsetAdd(@env.libs, *libname, FALSE)
761 end sub
762 
763 sub fbAddLibPath(byval path as zstring ptr)
764  strsetAdd(@env.libpaths, pathStripDiv(*path), FALSE)
765 end sub
766 
768  dim as string defid, deftext
769  dim as string ptr def = listGetHead(@env.predefines)
770  while (def)
771  dim as integer idlength = instr(*def, "=") - 1
772  if (idlength < 0) then
773  idlength = len(*def)
774  end if
775 
776  defid = left(*def, idlength)
777  deftext = right(*def, len(*def) - idlength - 1)
778 
779  '' If no text was given, default to '1'
780  '' (this also means that it's not possible to make
781  '' empty defines with -d)
782  if (len(deftext) = 0) then
783  deftext = "1"
784  end if
785 
786  '' TODO: Check for invalid identifier and duplicated definition
787  symbAddDefine(defid, deftext, len(deftext))
788 
789  def = listGetNext(def)
790  wend
791 end sub
792 
794  dim as string ptr file = listGetHead(@env.preincludes)
795  while ((file <> NULL) and fbShouldContinue())
796  fbIncludeFile(*file, TRUE)
797  file = listGetNext(file)
798  wend
799 end sub
800 
801 sub hAppendFbctinf( byval value as zstring ptr )
802  if( env.fbctinf_started = FALSE ) then
803  env.fbctinf_started = TRUE
804  irEmitFBCTINFBEGIN( )
805  end if
806  irEmitFBCTINFSTRING( value )
807 end sub
808 
810  dim as TSTRSETITEM ptr i = any
811 
812  '' This must follow the format used by objinfo.bas:objinfoRead*().
813  '' We want to emit the .fbctinf section only if there is any meta data
814  '' to put into it.
815  assert( env.fbctinf_started = FALSE )
816 
817  '' libs
818  i = listGetHead( @env.libs.list )
819  while( i )
820  '' Not default?
821  if( i->userdata = FALSE ) then
822  hAppendFbctinf( objinfoEncode( OBJINFO_LIB ) )
823  hAppendFbctinf( i->s )
824  end if
825  i = listGetNext( i )
826  wend
827 
828  '' libpaths
829  i = listGetHead( @env.libpaths.list )
830  while( i )
831  '' Not default?
832  if( i->userdata = FALSE ) then
833  hAppendFbctinf( objinfoEncode( OBJINFO_LIBPATH ) )
834  hAppendFbctinf( *hEscape( i->s ) )
835  end if
836  i = listGetNext( i )
837  wend
838 
839  '' -mt
840  if( env.clopt.multithreaded ) then
841  hAppendFbctinf( objinfoEncode( OBJINFO_MT ) )
842  end if
843 
844  '' -lang
845  '' not the default -lang mode?
846  if( env.clopt.lang <> FB_LANG_FB ) then
847  hAppendFbctinf( objinfoEncode( OBJINFO_LANG ) )
848  hAppendFbctinf( fbGetLangName( env.clopt.lang ) )
849  end if
850 
851  if( env.fbctinf_started ) then
852  irEmitFBCTINFEND( )
853  end if
854 end sub
855 
856 sub fbCompile _
857  ( _
858  byval infname as zstring ptr, _
859  byval outfname as zstring ptr, _
860  byref pponlyfile as string, _
861  byval ismain as integer _
862  )
863 
864  dim as double tmr
865 
866  env.inf.name = *infname
867  hReplaceSlash( env.inf.name, asc( FB_HOST_PATHDIV ) )
868  env.inf.incfile = NULL
869  env.inf.ismain = ismain
870 
871  env.outf.name = *outfname
872  env.outf.ismain = ismain
873 
874  '' open source file
875  if( hFileExists( *infname ) = FALSE ) then
876  errReportEx( FB_ERRMSG_FILENOTFOUND, infname, -1 )
877  exit sub
878  end if
879 
880  env.inf.num = freefile
881  if( open( *infname, for binary, access read, as #env.inf.num ) <> 0 ) then
882  errReportEx( FB_ERRMSG_FILEACCESSERROR, infname, -1 )
883  exit sub
884  end if
885 
886  env.inf.format = hCheckFileFormat( env.inf.num )
887 
888  ''
889  if( irEmitBegin( ) = FALSE ) then
890  errReportEx( FB_ERRMSG_FILEACCESSERROR, env.outf.name, -1 )
891  exit sub
892  end if
893 
894  if( fbGetOption( FB_COMPOPT_PPONLY ) ) then
895  env.ppfile_num = freefile( )
896  if( open( pponlyfile, for output, as #env.ppfile_num ) <> 0 ) then
897  errReportEx( FB_ERRMSG_FILEACCESSERROR, pponlyfile, -1 )
898  exit sub
899  end if
900  else
901  env.ppfile_num = 0
902  end if
903 
904  fbMainBegin( )
905 
906  tmr = timer( )
907 
910  if (fbShouldContinue()) then
911  cProgram()
912  end if
913 
914  tmr = timer( ) - tmr
915 
916  fbMainEnd( )
917 
918  '' not cross-compiling?
919  if( fbIsCrossComp( ) = FALSE ) then
920  '' compiling only?
921  if( env.clopt.outtype = FB_OUTTYPE_OBJECT ) then
922  '' store libs, paths and cmd-line options in the obj
923  hEmitObjinfo( )
924  end if
925  end if
926 
927  '' save
928  irEmitEnd( tmr )
929 
930  if( env.ppfile_num > 0 ) then
931  close #env.ppfile_num
932  end if
933 
934  close #env.inf.num
935 
936  '' check if any label undefined was used
937  if (fbShouldContinue()) then
938  symbCheckLabels(symbGetGlobalTbHead())
939  end if
940 end sub
941 
942 function fbShouldRestart() as integer
943  return env.dorestart
944 end function
945 
946 function fbShouldContinue() as integer
947  return ((env.dorestart = FALSE) and (errGetCount() < env.clopt.maxerrors))
948 end function
949 
950 sub fbSetLibs(byval libs as TSTRSET ptr, byval libpaths as TSTRSET ptr)
951  strsetCopy(@env.libs, libs)
952  strsetCopy(@env.libpaths, libpaths)
953 end sub
954 
955 sub fbGetLibs(byval libs as TSTRSET ptr, byval libpaths as TSTRSET ptr)
956  strsetCopy(libs, @env.libs)
957  strsetCopy(libpaths, @env.libpaths)
958 end sub
959 
961  if( env.inf.name > "" ) then
962  if( hFindIncFile( @env.inconcehash, env.inf.name ) = NULL ) then
963  hAddIncFile( @env.inconcehash, env.inf.name )
964  end if
965  end if
966 end sub
967 
968 ''::::
969 function is_rootpath( byref path as zstring ptr ) as integer
970 
971  function = FALSE
972 
973  if( path = NULL ) then
974  exit function
975  end if
976 
977 #if defined( __FB_WIN32__ ) or defined( __FB_DOS__ )
978  if( path[1] = asc(":") ) then
979  function = TRUE
980  end if
981  if( (path[0] = asc("/")) or (path[0] = asc(RSLASH)) ) then
982  '' UNC?
983  if( (path[1] = asc("/")) or (path[1] = asc(RSLASH)) ) then
984  function = TRUE
985  else
986  '' quirky drive letters...
987  *path = left( fbGetInputFileParentDir( ), 1 ) + ":" + *path
988  function = TRUE
989  end if
990  end if
991 #else
992  function = (path[0] = asc("/"))
993 #endif
994 end function
995 
996 ''::::
997 function get_rootpath_len( byval path as zstring ptr ) as integer
998 
999  '' returns number of characters in the root_path
1000  '' assuming that 'path' is already been made a
1001  '' root path.
1002 
1003  function = 0
1004 
1005  if( path[0] = NULL ) then
1006  exit function
1007  end if
1008 
1009  '' {/}
1010  function = 1
1011 
1012 #if defined( __FB_WIN32__ ) or defined( __FB_DOS__ )
1013 
1014  '' {d:/}
1015  if( path[1] = asc(":") ) then
1016  function = 3
1017  end if
1018  if( (path[0] = asc("/")) or (path[0] = asc(RSLASH)) ) then
1019  '' UNC?
1020  '' {//}server/share/
1021  if( (path[1] = asc("/")) or (path[1] = asc(RSLASH)) ) then
1022  function = 2
1023  end if
1024 
1025  end if
1026 
1027 #endif
1028 
1029 end function
1030 
1031 ''::::
1032 function solve_path( byval path as zstring ptr ) as integer
1033 
1034  '' solves a path to its lowest common denominator...
1035  '' c:\foo\bar\..\baz => c:\foo\baz, etc
1036  '' \\server\share\..\.\share2 => \\server\share2, etc
1037 
1038  static cidx(0 to FB_MAXPATHLEN \ 2) as integer = any
1039  dim as integer stk = any '' # components on the stack
1040  dim as integer s = any '' starting index
1041  dim as integer n = any '' # of chars in current component
1042  dim as integer d = any '' # of .'s in the current component
1043  dim as integer r = any '' index of char we are reading
1044  dim as integer w = any '' index of char we are writing
1045  dim as integer c = any '' current character
1046 
1047  '' set-up stack and don't touch the root path
1048  '' (root path is not on the stack)
1049 
1050  stk = 0
1051  s = get_rootpath_len( path )
1052  cidx(stk) = s
1053  w = s
1054  n = 0
1055  d = 0
1056 
1057  '' scan through the rest of the path
1058  for r = s to len( *path ) - 1
1059 
1060  c = path[r]
1061 
1062  '' ('/' | '\')?
1063  if( (c = asc("/")) or (c = asc(RSLASH)) ) then
1064 
1065  '' check component
1066 
1067  '' "//"?
1068  if( n = 0 ) then
1069  '' ignore
1070 
1071  '' "/./"?
1072  elseif( (d = 1) and (n = 1) ) then
1073  '' ignore
1074  w -= 1
1075 
1076  '' "/../"?
1077  elseif( (d = 2) and (n = 2) ) then
1078  '' pop a component from the stack
1079  if( stk ) then
1080  stk -= 1
1081  end if
1082  w = cidx( stk )
1083 
1084  else
1085  '' add char
1086  path[w] = c
1087  w += 1
1088 
1089  '' push a component on the stack
1090  stk += 1
1091  cidx(stk) = w
1092 
1093  end if
1094 
1095  '' reset counters
1096  n = 0
1097  d = 0
1098 
1099  else
1100  '' '.'?
1101  if( c = asc(".") ) then
1102  d += 1
1103  end if
1104 
1105  '' add char
1106  n += 1
1107  path[w] = c
1108  w += 1
1109 
1110  end if
1111 
1112  next
1113 
1114  path[w] = 0
1115 
1116  function = TRUE
1117 
1118 end function
1119 
1120 sub fbIncludeFile(byval filename as zstring ptr, byval isonce as integer)
1121  static as zstring * FB_MAXPATHLEN incfile
1122  dim as zstring ptr fileidx
1123 
1124  if( env.includerec >= FB_MAXINCRECLEVEL ) then
1125  errReport( FB_ERRMSG_RECLEVELTOODEEP )
1127  exit sub
1128  end if
1129 
1130  '' 1st) try finding it at same path as the current source-file
1131  incfile = hStripFilename( env.inf.name )
1132  incfile += *filename
1133 
1134  if( hFileExists( incfile ) = FALSE ) then
1135 
1136  '' 2nd) try as-is (could include an absolute or relative path)
1137  if( hFileExists( filename ) = FALSE ) then
1138 
1139  '' 3rd) try finding it at the inc paths
1140  dim as string ptr path = listGetHead(@env.includepaths)
1141  while (path)
1142  incfile = *path + FB_HOST_PATHDIV + *filename
1143  if (hFileExists(incfile)) then
1144  exit while
1145  end if
1146  path = listGetNext(path)
1147  wend
1148 
1149  '' not found?
1150  if (path = NULL) then
1151  errReportEx( FB_ERRMSG_FILENOTFOUND, QUOTE + *filename + QUOTE )
1153  exit sub
1154  end if
1155 
1156  else
1157  incfile = *filename
1158  end if
1159  end if
1160 
1161  '' if this isn't a root path, make it one.
1162  if( is_rootpath( incfile ) = FALSE ) then
1163  incfile = hCurDir( ) + FB_HOST_PATHDIV + incfile
1164  end if
1165 
1166  '' now, if it isn't a root path(even possible?), we have a fatal.
1167  if( is_rootpath( incfile ) = FALSE ) then
1168  errReportEx( FB_ERRMSG_FILENOTFOUND, QUOTE + incfile + QUOTE )
1170  exit sub
1171  end if
1172 
1173  '' solve out the .. and .
1174  if( solve_path( incfile ) = FALSE ) then
1175  errReportEx( FB_ERRMSG_FILENOTFOUND, QUOTE + incfile + QUOTE )
1177  exit sub
1178  end if
1179 
1180  hReplaceSlash( incfile, asc( FB_HOST_PATHDIV ) )
1181 
1182  '' #include ONCE
1183  if( isonce ) then
1184  '' we should respect the path
1185  if( hFindIncFile( @env.incfilehash, incfile ) <> NULL ) then
1186  exit sub
1187  end if
1188  end if
1189 
1190  '' #pragma ONCE
1191  if( hFindIncFile( @env.inconcehash, incfile ) <> NULL ) then
1192  exit sub
1193  end if
1194 
1195  '' we should respect the path here too
1196  fileidx = hAddIncFile( @env.incfilehash, incfile )
1197 
1198  '' push context
1199  infileTb(env.includerec) = env.inf
1200  env.includerec += 1
1201 
1202  env.inf.name = incfile
1203  env.inf.incfile = fileidx
1204 
1205  ''
1206  env.inf.num = freefile
1207  if( open( incfile, for binary, access read, as #env.inf.num ) <> 0 ) then
1208  errReportEx( FB_ERRMSG_FILENOTFOUND, QUOTE + *filename + QUOTE )
1210  exit sub
1211  end if
1212 
1213  env.inf.format = hCheckFileFormat( env.inf.num )
1214 
1215  '' parse
1216  lexPushCtx( )
1217 
1218  lexInit( TRUE )
1219 
1220  cProgram()
1221 
1222  lexPopCtx( )
1223 
1224  close #env.inf.num
1225 
1226  '' pop context
1227  env.includerec -= 1
1228  env.inf = infileTb( env.includerec )
1229 end sub
1230 
1231 '':::::
1232 function fbGetLangId _
1233  ( _
1234  byval txt as zstring ptr _
1235  ) as FB_LANG
1236 
1237  select case lcase(*txt)
1238  case "fb"
1239  function = FB_LANG_FB
1240  case "deprecated"
1241  function = FB_LANG_FB_DEPRECATED
1242  case "fblite"
1243  function = FB_LANG_FB_FBLITE
1244  case "qb"
1245  function = FB_LANG_QB
1246  case else
1247  function = FB_LANG_INVALID
1248  end select
1249 
1250 end function
1251