FreeBASIC  0.91.0
parser-compound-if.bas
Go to the documentation of this file.
1 '' IF..ELSE..ELSEIF..END IF compound statement parsing (single and multi-line)
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 "ast.bi"
10 
11 '':::::
12 ''SingleIfStatement= !(COMMENT|NEWLINE|STATSEP) NUM_LIT | Statement*)
13 '' (ELSE NUM_LIT | Statement*)?
14 ''
15 sub hIfSingleLine(byval stk as FB_CMPSTMTSTK ptr)
16  '' NUM_LIT | Statement*
17  if( lexGetClass( ) = FB_TKCLASS_NUMLITERAL ) then
18  dim as FBSYMBOL ptr l = symbLookupByNameAndClass( symbGetCurrentNamespc( ), _
19  lexGetText( ), _
20  FB_SYMBCLASS_LABEL, _
21  FALSE, _
22  FALSE )
23  if( l = NULL ) then
24  l = symbAddLabel( lexGetText( ), FB_SYMBOPT_CREATEALIAS )
25  end if
26 
27  lexSkipToken( )
28 
29  astAdd( astNewBRANCH( AST_OP_JMP, l ) )
30  else
31  cStatement()
32  end if
33 
34  '' (ELSE Statement*)?
35  if( lexGetToken( ) = FB_TK_ELSE ) then
36  lexSkipToken( )
37 
38  '' end scope
39  if( stk->scopenode <> NULL ) then
40  astScopeEnd( stk->scopenode )
41  stk->scopenode = NULL
42  end if
43 
44  '' exit if stmt
45  astAdd( astNewBRANCH( AST_OP_JMP, stk->if.endlabel ) )
46 
47  '' emit next label
48  astAdd( astNewLABEL( stk->if.nxtlabel ) )
49 
50  '' NUM_LIT | Statement*
51  if( lexGetClass( ) = FB_TKCLASS_NUMLITERAL ) then
52  dim as FBSYMBOL ptr l = symbLookupByNameAndClass( symbGetCurrentNamespc( ), _
53  lexGetText( ), _
54  FB_SYMBCLASS_LABEL, _
55  FALSE, _
56  FALSE )
57  if( l = NULL ) then
58  l = symbAddLabel( lexGetText( ), FB_SYMBOPT_CREATEALIAS )
59  end if
60 
61  lexSkipToken( )
62 
63  astAdd( astNewBRANCH( AST_OP_JMP, l ) )
64  else
65 
66  '' begin scope
67  stk->scopenode = astScopeBegin( )
68 
69  '' Statement
70  cStatement()
71  end if
72 
73  '' emit end label
74  astAdd( astNewLABEL( stk->if.endlabel ) )
75  else
76  '' emit next label
77  astAdd( astNewLABEL( stk->if.nxtlabel ) )
78  end if
79 
80  '' END IF? -- added to make complex macros easier to be written
81  select case lexGetToken( )
82  case FB_TK_END
83  if( lexGetLookAhead( 1 ) = FB_TK_IF ) then
84  lexSkipToken( )
85  lexSkipToken( )
86  end if
87 
88  case FB_TK_ENDIF
89  lexSkipToken( )
90  end select
91 
92  '' end scope
93  if( stk->scopenode <> NULL ) then
94  astScopeEnd( stk->scopenode )
95  end if
96 
97  '' pop from stmt stack
98  cCompStmtPop( stk )
99 end sub
100 
101 '' IfStmtBegin = IF Expression THEN (BlockIfStatement | SingleIfStatement) .
103  dim as ASTNODE ptr expr = any
104  dim as FBSYMBOL ptr nl = any, el = any
105  dim as FB_CMPSTMTSTK ptr stk = any
106  dim as integer ismultiline = any
107 
108  '' IF
109  lexSkipToken( )
110 
111  '' Expression
112  expr = cExpression( )
113  if( expr = NULL ) then
114  errReport( FB_ERRMSG_EXPECTEDEXPRESSION )
115  '' error recovery: fake an expr
116  expr = astNewCONSTi( 0 )
117  end if
118 
119  '' add end label (at ENDIF)
120  el = symbAddLabel( NULL, FB_SYMBOPT_NONE )
121  '' and next label (at ELSE/ELSEIF)
122  nl = symbAddLabel( NULL, FB_SYMBOPT_NONE )
123 
124  '' branch
125  expr = astBuildBranch( expr, nl, FALSE )
126  if( expr = NULL ) then
127  errReport( FB_ERRMSG_INVALIDDATATYPES )
128  else
129  astAdd( expr )
130  end if
131 
132  '' push to stmt stack
133  stk = cCompStmtPush( FB_TK_IF )
134  stk->if.nxtlabel = nl
135  stk->if.endlabel = el
136  stk->if.elsecnt = 0
137 
138  '' GOTO?
139  if( lexGetToken( ) = FB_TK_GOTO ) then
140  hIfSingleLine( stk )
141  return
142  end if
143 
144  '' THEN?
145  if( lexGetToken( ) <> FB_TK_THEN ) then
146  errReport( FB_ERRMSG_EXPECTEDTHEN )
147  else
148  lexSkipToken( )
149  end if
150 
151  select case as const lexGetToken( )
152  '' COMMENT|NEWLINE?
153  case FB_TK_COMMENT, FB_TK_EOL, FB_TK_EOF
154  ismultiline = TRUE
155 
156  '' REM | ':'?
157  case FB_TK_REM, FB_TK_STMTSEP
158  '' QB treats "IF...THEN [REM|:] ..." as single-line IF
159  if( fbLangIsSet( FB_LANG_QB ) ) then
160  ismultiline = FALSE
161  else
162  ismultiline = TRUE
163  end if
164 
165  case else
166  ismultiline = FALSE
167  end select
168 
169  '' begin scope
170  stk->scopenode = astScopeBegin( )
171 
172  if( ismultiline ) then
173  stk->if.issingle = FALSE
174  else
175  stk->if.issingle = TRUE
176  hIfSingleLine( stk )
177  end if
178 end sub
179 
180 '' IfStmtNext = ELSEIF Expression THEN
181 '' | ELSE .
183  dim as ASTNODE ptr expr = any
184  dim as FB_CMPSTMTSTK ptr stk = any
185 
186  stk = cCompStmtGetTOS( FB_TK_IF, FALSE )
187  if( stk = NULL ) then
188  if( lexGetToken( ) = FB_TK_ELSEIF ) then
189  errReport( FB_ERRMSG_ELSEIFWITHOUTIF )
190  else
191  errReport( FB_ERRMSG_ELSEWITHOUTIF )
192  end if
193  hSkipStmt( )
194  exit sub
195  end if
196 
197  '' single line? don't process
198  if( stk->if.issingle ) then
199  exit sub
200  end if
201 
202  '' ELSE already parsed?
203  if( stk->if.elsecnt <> 0 ) then
204  errReport( FB_ERRMSG_EXPECTEDENDIF )
205  end if
206 
207  '' end scope
208  if( stk->scopenode <> NULL ) then
209  astScopeEnd( stk->scopenode )
210  stk->scopenode = NULL
211  end if
212 
213  '' ELSEIF Expression THEN ?
214  if( lexGetToken( ) = FB_TK_ELSEIF ) then
215  lexSkipToken( )
216 
217  '' exit last if stmt
218  astAdd( astNewBRANCH( AST_OP_JMP, stk->if.endlabel ) )
219 
220  '' emit next label
221  '' (can be NULL in case of error recovery, e.g. ELSEIF after ELSE)
222  if( stk->if.nxtlabel ) then
223  astAdd( astNewLABEL( stk->if.nxtlabel ) )
224  end if
225 
226  '' add next label (at ELSE/ELSEIF)
227  stk->if.nxtlabel = symbAddLabel( NULL, FB_SYMBOPT_NONE )
228 
229  '' Expression
230  expr = cExpression( )
231  if( expr = NULL ) then
232  errReport( FB_ERRMSG_EXPECTEDEXPRESSION )
233  '' error recovery: fake an expr
234  expr = astNewCONSTi( 0 )
235  end if
236 
237  '' THEN
238  if( hMatch( FB_TK_THEN ) = FALSE ) then
239  errReport( FB_ERRMSG_EXPECTEDTHEN )
240  end if
241 
242  '' branch
243  expr = astBuildBranch( expr, stk->if.nxtlabel, FALSE )
244  if( expr = NULL ) then
245  errReport( FB_ERRMSG_INVALIDDATATYPES )
246  else
247  astAdd( expr )
248  end if
249 
250  '' ELSE..
251  else
252  stk->if.elsecnt += 1
253 
254  lexSkipToken( )
255 
256  '' warn about IF statements immediately following ELSE, due to confusion with 'ELSEIF'
257  if( lexGetToken( ) = FB_TK_IF ) then
258  errReportWarn( FB_WARNINGMSG_IFFOUNDAFTERELSE )
259  end if
260 
261  '' exit last if stmt
262  astAdd( astNewBRANCH( AST_OP_JMP, stk->if.endlabel ) )
263 
264  '' emit next label
265  if( stk->if.nxtlabel <> NULL ) then
266  astAdd( astNewLABEL( stk->if.nxtlabel ) )
267  stk->if.nxtlabel = NULL
268  end if
269 
270  end if
271 
272  '' begin scope
273  stk->scopenode = astScopeBegin( )
274 
275  cStatement( )
276 end sub
277 
278 '' IfStmtEnd = END IF | ENDIF .
280  dim as FB_CMPSTMTSTK ptr stk = any
281 
282  stk = cCompStmtGetTOS( FB_TK_IF )
283  if( stk = NULL ) then
284  hSkipStmt( )
285  exit sub
286  end if
287 
288  '' single line? don't process
289  if( stk->if.issingle ) then
290  exit sub
291  end if
292 
293  '' ENDIF or END IF
294  if( lexGetToken() = FB_TK_END ) then
295  lexSkipToken( )
296  end if
297  lexSkipToken( )
298 
299  '' end scope
300  if( stk->scopenode <> NULL ) then
301  astScopeEnd( stk->scopenode )
302  end if
303 
304  '' emit next label
305  if( stk->if.nxtlabel <> NULL ) then
306  astAdd( astNewLABEL( stk->if.nxtlabel ) )
307  end if
308 
309  '' emit end label
310  astAdd( astNewLABEL( stk->if.endlabel ) )
311 
312  '' pop from stmt stack
313  cCompStmtPop( stk )
314 end sub
315