FreeBASIC  0.91.0
pp-cond.bas
Go to the documentation of this file.
1 '' pre-processor conditional (#if, #else, #elseif, #endif) parsing
2 ''
3 '' chng: dec/2004 written [v1ctor]
4 
5 #include once "fb.bi"
6 #include once "fbint.bi"
7 #include once "lex.bi"
8 #include once "parser.bi"
9 #include once "pp.bi"
10 
12 
14  istrue as integer
15  elsecnt as integer
16 end type
17 
18 declare sub ppSkip( )
19 
20 '' globals
21  dim shared pptb(1 to FB_PP_MAXRECLEVEL) as LEXPP_REC
22 
23 sub ppCondInit( )
24  pp.level = 0
25 end sub
26 
27 sub ppCondEnd( )
28 end sub
29 
30 function ppExpression( ) as integer
31  dim as ASTNODE ptr expr = any
32 
33  fbSetIsPP( TRUE )
34  expr = cExpression( )
35  fbSetIsPP( FALSE )
36 
37  if( expr = NULL ) then
38  errReport( FB_ERRMSG_EXPECTEDEXPRESSION )
39  expr = astNewCONSTi( 0 )
40  end if
41 
42  '' String literals evaluate to FALSE
43  if( astGetStrLitSymbol( expr ) <> NULL ) then
44  expr = astNewCONSTi( 0 )
45 
46  '' Besides that, it must be a numeric constant (that includes the
47  '' result of defined() or BOPs)
48  elseif( astIsCONST( expr ) = FALSE ) then
49  errReport( FB_ERRMSG_EXPECTEDCONST )
50  astDelTree( expr )
51  expr = astNewCONSTi( 0 )
52  end if
53 
54  function = not astConstEqZero( expr )
55 end function
56 
57 sub ppCondIf( )
58  dim as integer istrue = any
59  dim as FBSYMBOL ptr base_parent = any
60 
61  istrue = FALSE
62 
63  select case as const lexGetToken( LEXCHECK_KWDNAMESPC )
64  '' IFDEF ID
65  case FB_TK_PP_IFDEF
66  lexSkipToken( LEXCHECK_NODEFINE )
67 
68  if( cIdentifier( base_parent, FB_IDOPT_NONE ) <> NULL ) then
69  '' any symbol is okay or type's wouldn't be found
70  istrue = TRUE
71  end if
72  lexSkipToken( )
73 
74  '' IFNDEF ID
75  case FB_TK_PP_IFNDEF
76  lexSkipToken( LEXCHECK_NODEFINE )
77 
78  if( cIdentifier( base_parent, FB_IDOPT_NONE ) = NULL ) then
79  '' ditto
80  istrue = TRUE
81  end if
82  lexSkipToken( )
83 
84  '' IF Expression
85  case FB_TK_PP_IF
86  lexSkipToken( )
87 
88  istrue = ppExpression( )
89 
90  end select
91 
92  pp.level += 1
93  if( pp.level > FB_PP_MAXRECLEVEL ) then
94  errReport( FB_ERRMSG_RECLEVELTOODEEP )
96  exit sub
97  end if
98 
99  pptb(pp.level).istrue = istrue
100  pptb(pp.level).elsecnt = 0
101 
102  if( istrue = FALSE ) then
103  ppSkip( )
104  end if
105 end sub
106 
108  dim as integer istrue = any
109 
110  istrue = FALSE
111 
112  if( pp.level = 0 ) then
113  errReport( FB_ERRMSG_ILLEGALOUTSIDECOMP )
114  '' error recovery: skip statement
115  hSkipStmt( )
116  exit sub
117  end if
118 
119  if( pptb(pp.level).elsecnt > 0 ) then
120  errReport( FB_ERRMSG_SYNTAXERROR )
121  '' error recovery: skip statement
122  hSkipStmt( )
123  exit sub
124  end if
125 
126  '' ELSEIF?
127  if( lexGetToken( LEXCHECK_KWDNAMESPC ) = FB_TK_PP_ELSEIF ) then
128  lexSkipToken( )
129 
130  istrue = ppExpression( )
131 
132  if( pptb(pp.level).istrue ) then
133  ppSkip( )
134  exit sub
135  end if
136 
137  pptb(pp.level).istrue = istrue
138  '' ELSE
139  else
140  lexSkipToken( )
141 
142  pptb(pp.level).elsecnt += 1
143  pptb(pp.level).istrue = not pptb(pp.level).istrue
144  end if
145 
146  if( pptb(pp.level).istrue = FALSE ) then
147  ppSkip( )
148  end if
149 end sub
150 
152  '' ENDIF
153  lexSkipToken( )
154 
155  if( pp.level > 0 ) then
156  pp.level -= 1
157  else
158  errReport( FB_ERRMSG_ILLEGALOUTSIDECOMP )
159  end if
160 end sub
161 
162 '':::::
163 sub ppAssert( )
164  dim as integer istrue = any
165 
166  '' ASSERT Expression
167 
168  istrue = ppExpression( )
169 
170  if( istrue = FALSE ) then
171  errReport( FB_ERRMSG_PPASSERT_FAILED )
172  end if
173 
174 end sub
175 
176 '':::::
177 sub ppSkip( )
178  dim as integer iflevel = any
179 
180  pp.skipping = TRUE
181 
182  '' Comment?
183  cComment( )
184 
185  '' emit the current line in text form
186  hEmitCurrLine( )
187 
188  '' EOL
189  if( lexGetToken( ) <> FB_TK_EOL ) then
190  errReport( FB_ERRMSG_EXPECTEDEOL )
191  '' error recovery: skip until next line
192  hSkipUntil( FB_TK_EOL, TRUE )
193  else
194  lexSkipToken( )
195  end if
196 
197  iflevel = pp.level
198 
199  '' skip lines until a #ENDIF or #ELSE at same level is found
200  do
201  select case lexGetToken( )
202  case CHAR_SHARP
203  lexSkipToken( LEXCHECK_KWDNAMESPC )
204 
205  select case as const lexGetToken( LEXCHECK_KWDNAMESPC )
206  case FB_TK_PP_IF, FB_TK_PP_IFDEF, FB_TK_PP_IFNDEF
207  iflevel += 1
208 
209  case FB_TK_PP_ELSE, FB_TK_PP_ELSEIF
210  select case( iflevel )
211  case pp.level
212  pp.skipping = FALSE
213  ppCondElse( )
214  exit sub
215  case 0
216  errReport( FB_ERRMSG_ILLEGALOUTSIDECOMP )
217  end select
218 
219  case FB_TK_PP_ENDIF
220  select case( iflevel )
221  case pp.level
222  pp.skipping = FALSE
223  ppCondEndIf( )
224  exit sub
225  case 0
226  errReport( FB_ERRMSG_ILLEGALOUTSIDECOMP )
227  case else
228  iflevel -= 1
229  end select
230 
231  case FB_TK_PP_DEFINE, FB_TK_PP_UNDEF, FB_TK_PP_PRINT, FB_TK_PP_ERROR, _
232  FB_TK_PP_INCLUDE, FB_TK_PP_INCLIB, FB_TK_PP_LIBPATH, FB_TK_PP_PRAGMA, _
233  FB_TK_PP_MACRO, FB_TK_PP_ENDMACRO, FB_TK_PP_LINE, FB_TK_PP_LANG
234 
235  case else
236  errReport( FB_ERRMSG_SYNTAXERROR )
237  end select
238 
239  case FB_TK_EOF
240  errReport( FB_ERRMSG_EXPECTEDPPENDIF )
241  exit do
242 
243  end select
244 
245  lexSkipLine( )
246 
247  if( lexGetToken( ) = FB_TK_EOL ) then
248  lexSkipToken( )
249  end if
250  loop
251 
252  pp.skipping = FALSE
253 end sub
254