FreeBASIC  0.91.0
parser-toplevel.bas
Go to the documentation of this file.
1 '' top-level parser
2 ''
3 '' a deterministic, top-down, linear directional (LL(2)), recursive descent parser
4 ''
5 '' chng: sep/2004 written [v1ctor]
6 
7 
8 #include once "fb.bi"
9 #include once "fbint.bi"
10 #include once "parser.bi"
11 #include once "ast.bi"
12 #include once "pp.bi"
13 
14 declare sub parserCompoundStmtInit ( )
15 
16 declare sub parserCompoundStmtEnd ( )
17 
18 declare sub parserCompoundStmtSetCtx ( )
19 
20 declare sub parserProcCallInit ( )
21 
22 declare sub parserProcCallEnd ( )
23 
24 declare sub parserLetInit( )
25 
26 declare sub parserLetEnd( )
27 
28 '' globals
29  dim shared as PARSERCTX parser
30 
31 '':::::
33 
34  parser.scope = FB_MAINSCOPE
35 
36  parser.currproc = NULL
37  parser.currblock = NULL
38 
39  parser.nspcrec = 0
40 
41  parser.mangling = FB_MANGLING_BASIC
42 
43  parser.stmt.cnt = 0
44  parser.stmt.id = 0
45 
46  parser.prntcnt = 0
47  parser.options = FB_PARSEROPT_CHKARRAY
48  parser.ctxsym = NULL
49  parser.ctx_dtype = FB_DATATYPE_INVALID
50 
52 
53 end sub
54 
55 '':::::
56 sub parserInit( )
57 
59 
61 
62  parserLetInit( )
63 
64 end sub
65 
66 '':::::
67 sub parserEnd( )
68 
69  parserLetEnd( )
70 
72 
74 
75 end sub
76 
78  dim as ASTNODE ptr n = any
79 
80  '' Notes:
81  '' - The text is only available after the lexer parsed through it,
82  '' so this must be done after parsing it
83  '' - And yet, the text (in form of a LIT node) should be inserted
84  '' above the code generated for it, so we need to use astAddAfter()
85  '' - No assumptions about the current procedure should be made, as it
86  '' can change when parsing the line/statement
87 
88  '' Find the last DBG( AST_OP_DBG_LINEINI ) node
89  '' in the current proc and insert behind it
90  n = astGetProcTailNode( )
91  while( n )
92  if( n->class = AST_NODECLASS_DBG ) then
93  if( n->dbg.op = AST_OP_DBG_LINEINI ) then
94  astAddAfter( astNewLIT( lexCurrLineGet( ) ), n )
95  exit while
96  end if
97  end if
98  n = n->prev
99  wend
100 
101  lexCurrLineReset( )
102 end sub
103 
104 '' Program = (Label? Statement? Comment?)* EOF?
105 sub cProgram()
106  dim as integer startlevel = pp.level
107 
108  '' For each line...
109  do
110  parser.stmt.cnt += 1
111 
112  '' line begin
113  astAdd( astNewDBG( AST_OP_DBG_LINEINI, lexLineNum( ) ) )
114 
115  '' Label?
116  cLabel( )
117 
118  '' Statement?
119  cStatement( )
120 
121  '' Comment?
122  cComment( )
123 
124  if (fbShouldContinue() = FALSE) then
125  exit sub
126  end if
127 
128  '' Emit the current line in text form, for debugging purposes
129  if( env.clopt.debug ) then
130  if( env.includerec = 0 ) then
132  end if
133  end if
134 
135  select case (lexGetToken())
136  case FB_TK_EOL
137  lexSkipToken( )
138 
139  case FB_TK_EOF
140 
141  case else
142  errReport( FB_ERRMSG_EXPECTEDEOL )
143  '' error recovery: skip until EOL
144  hSkipUntil( FB_TK_EOL, TRUE )
145  end select
146 
147  if (fbShouldContinue() = FALSE) then
148  exit sub
149  end if
150 
151  '' line end
152  astAdd( astNewDBG( AST_OP_DBG_LINEEND ) )
153  loop while (lexGetToken() <> FB_TK_EOF)
154 
155  '' EOF
156  assert(lexGetToken() = FB_TK_EOF)
157 
158  parser.stmt.cnt += 1
159 
160  if (pp.level <> startlevel) then '' inside #IF block?
161  errReport( FB_ERRMSG_EXPECTEDPPENDIF )
162  end if
163 
164  lexSkipToken()
165 
166  '' only check compound stmts if not parsing an include file
167  if (env.includerec = 0) then
169  end if
170 end sub
171 
172 ''::::
173 sub hSkipUntil _
174  ( _
175  byval token as integer, _
176  byval doeat as integer, _
177  byval flags as LEXCHECK, _
178  byval stop_on_comma as integer _
179  )
180 
181  dim as integer prntcnt
182 
183  prntcnt = 0
184  do
185  select case as const lexGetToken( flags )
186  case FB_TK_EOL
187  exit do
188 
189  case FB_TK_STMTSEP, FB_TK_COMMENT, FB_TK_REM
190  '' anything but EOL? exit..
191  if( token <> FB_TK_EOL ) then
192  exit do
193  end if
194 
195  case FB_TK_EOF
196  exit sub
197 
198  '' '('?
199  case CHAR_LPRNT
200  if( token = CHAR_LPRNT ) then
201  exit do
202  end if
203 
204  prntcnt += 1
205 
206  case CHAR_LBRACE
207  prntcnt += 1
208 
209  '' ')'?
210  case CHAR_RPRNT
211  '' inside parentheses?
212  if( prntcnt > 0 ) then
213  prntcnt -= 1
214  else
215  if( token = CHAR_RPRNT ) then
216  exit do
217  end if
218  end if
219 
220  case CHAR_RBRACE
221  '' inside braces?
222  if( prntcnt > 0 ) then
223  prntcnt -= 1
224  else
225  if( token = CHAR_RBRACE ) then
226  exit do
227  end if
228  end if
229 
230  '' ','?
231  case CHAR_COMMA
232  '' skip until ','?
233  if( (token = CHAR_COMMA) or stop_on_comma ) then
234  '' not inside parentheses?
235  if( prntcnt = 0 ) then
236  exit do
237  end if
238  end if
239 
240  case else
241  '' token found? exit..
242  if( lexGetToken( flags ) = token ) then
243  exit do
244  end if
245 
246  end select
247 
248  lexSkipToken( flags )
249  loop
250 
251  '' skip token?
252  if( doeat ) then
253  '' same?
254  if( token = lexGetToken( flags ) ) then
255  lexSkipToken( flags )
256  end if
257  end if
258 
259 end sub
260 
261 '':::::
262 sub hSkipCompound _
263  ( _
264  byval for_token as integer, _
265  byval until_token as integer, _
266  byval flags as LEXCHECK _
267  )
268 
269  dim as integer cnt, iscomment
270 
271  if( until_token = INVALID ) then
272  until_token = for_token
273  end if
274 
275  cnt = 0
276  iscomment = FALSE
277  do
278  select case lexGetToken( flags )
279  case FB_TK_EOF
280  exit sub
281 
282  case FB_TK_EOL
283  iscomment = FALSE
284 
285  case FB_TK_COMMENT, FB_TK_REM
286  iscomment = TRUE
287 
288  case FB_TK_END
289  if( iscomment = FALSE ) then
290  if( lexGetLookAhead( 1, flags ) = until_token ) then
291  lexSkipToken( flags )
292 
293  if( cnt > 0 ) then
294  cnt -= 1
295  end if
296 
297  if( cnt = 0 ) then
298  exit do
299  end if
300  end if
301  end if
302 
303  case for_token
304  if( iscomment = FALSE ) then
305  cnt += 1
306  end if
307 
308  end select
309 
310  lexSkipToken( flags )
311  loop
312 
313  lexSkipToken( flags )
314 
315 end sub
316 
317 '':::::
318 function hMatchExpr _
319  ( _
320  byval dtype as integer _
321  ) as ASTNODE ptr
322 
323  dim as ASTNODE ptr expr
324 
325  expr = cExpression( )
326  if( expr = NULL ) then
327  errReport( FB_ERRMSG_EXPECTEDEXPRESSION )
328  '' error recovery: fake an expr
329  if( dtype = FB_DATATYPE_INVALID ) then
330  return NULL
331  end if
332 
333  expr = astNewCONSTz( dtype )
334  end if
335 
336  function = expr
337 
338 end function
339