FreeBASIC  0.91.0
parser-quirk-file.bas
Go to the documentation of this file.
1 '' quirk file statements and functions (PRINT, WRITE, OPEN, ...) parsing
2 ''
3 '' chng: sep/2004 written [v1ctor]
4 
5 #include once "fb.bi"
6 #include once "fbint.bi"
7 #include once "parser.bi"
8 #include once "rtl.bi"
9 #include once "ast.bi"
10 
11 '':::::
12 '' PrintStmt = (PRINT|'?') ('#' Expression ',')? (USING Expression{str} ';')? (Expression? ';'|"," )*
13 ''
14 function cPrintStmt _
15  ( _
16  byval tk as FB_TOKEN _
17  ) as integer
18 
19  dim as ASTNODE ptr usingexpr, filexpr, filexprcopy, expr
20  dim as integer expressions, issemicolon, iscomma, istab, isspc, islprint
21 
22  function = FALSE
23 
24  '' (PRINT|'?')
25  select case tk
26  case FB_TK_PRINT, CHAR_QUESTION
27  islprint = FALSE
28 
29  case FB_TK_LPRINT
30  if( fbLangOptIsSet( FB_LANG_OPT_OPTION ) = FALSE ) then
31  errReportNotAllowed( FB_LANG_OPT_OPTION )
32  else
33  islprint = TRUE
34  end if
35 
36  case else
37  exit function
38  end select
39 
40  lexSkipToken( )
41 
42  if( islprint ) then
43  filexpr = astNewCONSTi( -1 )
44  else
45  '' ('#' Expression)?
46  if( hMatch( CHAR_SHARP ) ) then
47  hMatchExpressionEx( filexpr, FB_DATATYPE_INTEGER )
48  hMatchCOMMA( )
49  else
50  filexpr = astNewCONSTi( 0 )
51  end if
52  end if
53 
54  '' side-effect?
55  '' (vars may also cause side-effects if modified by printed expressions)
56  if( astIsCONST( filexpr ) = FALSE ) then
57  astAdd( astRemSideFx( filexpr ) )
58  end if
59 
60  usingexpr = NULL
61 
62  '' (Expression?|SPC(Expression)|TAB(Expression) ';'|"," )*
63  expressions = 0
64  do
65 
66  '' (USING Expression{str} ';')?
67  if( hMatch( FB_TK_USING ) ) then
68 
69  if( usingexpr <> NULL ) then
70 #if 1 '' remove this to allow multiple USINGs on one line
71  errReport( FB_ERRMSG_EXPECTEDEOL )
72 #endif
73  filexprcopy = astCloneTree( filexpr )
74  if( rtlPrintUsingEnd( filexprcopy, _
75  islprint ) = FALSE ) then
76  exit function
77  end if
78  end if
79 
80  hMatchExpressionEx( usingexpr, FB_DATATYPE_STRING )
81 
82  if( hMatch( CHAR_SEMICOLON ) = FALSE ) then
83  errReport( FB_ERRMSG_EXPECTEDSEMICOLON )
84  end if
85 
86  if( rtlPrintUsingInit( usingexpr, islprint ) = FALSE ) then
87  exit function
88  end if
89  end if
90 
91  '' (Expression?|SPC(Expression)|TAB(Expression)
92  isspc = FALSE
93  istab = FALSE
94  if( hMatch( FB_TK_SPC ) ) then
95  isspc = TRUE
96  hMatchLPRNT( )
97  hMatchExpressionEx( expr, FB_DATATYPE_INTEGER )
98  hMatchRPRNT( )
99  elseif( hMatch( FB_TK_TAB ) ) then
100  istab = TRUE
101  hMatchLPRNT( )
102  hMatchExpressionEx( expr, FB_DATATYPE_INTEGER )
103  hMatchRPRNT( )
104  else
105  expr = cExpression( )
106  end if
107 
108  iscomma = FALSE
109  issemicolon = FALSE
110  if( hMatch( CHAR_COMMA ) ) then
111  if( usingexpr <> NULL ) then
112  '' QB automatically converted them to semi-colons in the editor.
113  errReport( FB_ERRMSG_EXPECTEDSEMICOLON )
114  end if
115  iscomma = TRUE
116  elseif( hMatch( CHAR_SEMICOLON ) ) then
117  issemicolon = TRUE
118  end if
119 
120  '' handle PRINT w/o expressions
121  if( (iscomma = FALSE) and _
122  (issemicolon = FALSE) and _
123  (expr = NULL) ) then
124  exit do
125  end if
126 
127  if( isspc ) then
128  filexprcopy = astCloneTree( filexpr )
129  if( rtlPrintSPC( filexprcopy, _
130  expr, _
131  islprint ) = FALSE ) then
132  exit function
133  end if
134 
135  elseif( istab ) then
136  filexprcopy = astCloneTree( filexpr )
137  if( rtlPrintTab( filexprcopy, _
138  expr, _
139  islprint ) = FALSE ) then
140  exit function
141  end if
142 
143  else
144 /'or expr = NULL'/ ) then
145 /' (commented check allows multiple consecutive commas/semicolons in USING statements.
146  QB doesn't support it though, so I'm not sure we should. '/
147  filexprcopy = astCloneTree( filexpr )
148  if( rtlPrint( filexprcopy, _
149  iscomma, _
150  issemicolon, _
151  expr, _
152  islprint ) = FALSE ) then
153  errReport( FB_ERRMSG_INVALIDDATATYPES )
154  end if
155 
156  else
157  filexprcopy = astCloneTree( filexpr )
158  if( rtlPrintUsing( filexprcopy, _
159  expr, _
160  iscomma, _
161  issemicolon, _
162  islprint ) = FALSE ) then
163  errReport( FB_ERRMSG_INVALIDDATATYPES )
164  end if
165  end if
166  end if
167 
168  expressions += 1
169  loop while( iscomma or issemicolon )
170 
171  if( usingexpr = NULL ) then
172  if( expressions = 0 ) then
173  filexprcopy = astCloneTree( filexpr )
174  if( rtlPrint( filexprcopy, _
175  FALSE, _
176  FALSE, _
177  NULL, _
178  islprint ) = FALSE ) then
179  exit function
180  end if
181  end if
182  else
183  filexprcopy = astCloneTree( filexpr )
184  if( rtlPrintUsingEnd( filexprcopy, _
185  islprint ) = FALSE ) then
186  exit function
187  end if
188  end if
189 
190  ''
191  astDelTree( filexpr )
192 
193  function = TRUE
194 
195 end function
196 
197 '':::::
198 '' WriteStmt = WRITE ('#' Expression)? (Expression? "," )*
199 ''
200 function cWriteStmt() as integer
201  dim as ASTNODE ptr filexpr, filexprcopy, expr
202  dim as integer expressions, iscomma
203 
204  function = FALSE
205 
206  '' WRITE
207  lexSkipToken( )
208 
209  '' ('#' Expression)?
210  if( hMatch( CHAR_SHARP ) ) then
211  hMatchExpressionEx( filexpr, FB_DATATYPE_INTEGER )
212 
213  hMatchCOMMA( )
214 
215  else
216  filexpr = astNewCONSTi( 0 )
217  end if
218 
219  '' side-effect?
220  '' (vars may also cause side-effects if modified by printed expressions)
221  if( astIsCONST( filexpr ) = FALSE ) then
222  astAdd( astRemSideFx( filexpr ) )
223  end if
224 
225  '' (Expression? "," )*
226  expressions = 0
227  do
228  expr = cExpression( )
229  if( expr = NULL ) then
230  expr = NULL
231  end if
232 
233  iscomma = FALSE
234  if( hMatch( CHAR_COMMA ) ) then
235  iscomma = TRUE
236  end if
237 
238  filexprcopy = astCloneTree( filexpr )
239 
240  '' handle WRITE w/o expressions
241  if( (iscomma = FALSE) and (expr = NULL) ) then
242  if( expressions = 0 ) then
243  rtlWrite( filexprcopy, FALSE, NULL )
244  end if
245 
246  exit do
247  end if
248 
249  if( rtlWrite( filexprcopy, iscomma, expr ) = FALSE ) then
250  errReport( FB_ERRMSG_INVALIDDATATYPES )
251  end if
252 
253  expressions += 1
254  loop while( iscomma )
255 
256  ''
257  astDelTree( filexpr )
258 
259  function = TRUE
260 end function
261 
262 '':::::
263 '' LineInputStmt = LINE INPUT ';'? ('#' Expression| Expression{str}?) (','|';')? Variable? .
264 ''
265 function cLineInputStmt _
266  ( _
267  _
268  ) as integer
269 
270  dim as ASTNODE ptr expr, dstexpr
271  dim as integer isfile, addnewline, issep, addquestion
272 
273  function = FALSE
274 
275  '' INPUT
276  if( lexGetLookAhead( 1 ) <> FB_TK_INPUT ) then
277  exit function
278  end if
279 
280  lexSkipToken( )
281  lexSkipToken( )
282 
283  '' ';'?
284  addnewline = (hMatch( CHAR_SEMICOLON ) = FALSE)
285 
286  '' '#'?
287  isfile = FALSE
288  if( hMatch( CHAR_SHARP ) ) then
289  isfile = TRUE
290  end if
291 
292  '' Expression?
293  expr = cExpression( )
294  if( expr = NULL ) then
295  if( isfile ) then
296  errReport( FB_ERRMSG_EXPECTEDEXPRESSION )
297  expr = astNewCONSTi( 0 )
298  else
299  expr = NULL
300  end if
301  end if
302 
303  '' ','|';'?
304  issep = TRUE
305  if( hMatch( CHAR_COMMA ) = FALSE ) then
306  if( hMatch( CHAR_SEMICOLON ) = FALSE ) then
307  issep = FALSE
308  if( (expr = NULL) or (isfile) ) then
309  errReport( FB_ERRMSG_EXPECTEDCOMMA )
310  end if
311  else
312  addquestion = TRUE
313  end if
314  else
315  addquestion = FALSE
316  end if
317 
318  '' Variable?
319  dstexpr = cVarOrDeref( )
320  if( dstexpr = NULL ) then
321  if( (expr = NULL) or (isfile) ) then
322  errReport( FB_ERRMSG_EXPECTEDIDENTIFIER )
323  hSkipStmt( )
324  return TRUE
325  else
326  dstexpr = expr
327  expr = NULL
328  end if
329  else
330  if( issep = FALSE ) then
331  errReport( FB_ERRMSG_EXPECTEDCOMMA )
332  end if
333  end if
334 
335  '' dest can't be a top-level const
336  if( typeIsConst( astGetFullType( dstexpr ) ) ) then
337  errReport( FB_ERRMSG_CONSTANTCANTBECHANGED )
338  end if
339 
340  select case astGetDataType( dstexpr )
341  case FB_DATATYPE_STRING, FB_DATATYPE_FIXSTR, FB_DATATYPE_CHAR
342  function = rtlFileLineInput( isfile, expr, dstexpr, addquestion, addnewline )
343 
344  case FB_DATATYPE_WCHAR
345  function = rtlFileLineInputWstr( isfile, expr, dstexpr, addquestion, addnewline )
346 
347  '' not a string?
348  case else
349  astDelTree( dstexpr )
350  errReport( FB_ERRMSG_INVALIDDATATYPES )
351  return TRUE
352  end select
353 
354 end function
355 
356 '':::::
357 '' InputStmt = INPUT ';'? (('#' Expression| STRING_LIT) (','|';'))? Variable (',' Variable)*
358 ''
359 function cInputStmt _
360  ( _
361  _
362  ) as integer
363 
364  dim as ASTNODE ptr filestrexpr, dstexpr
365  dim as integer islast, isfile, addnewline, addquestion
366 
367  function = FALSE
368 
369  '' INPUT
370  lexSkipToken( )
371 
372  '' ';'?
373  addnewline = (hMatch( CHAR_SEMICOLON ) = FALSE)
374 
375  '' '#'?
376  addquestion = FALSE
377  if( hMatch( CHAR_SHARP ) ) then
378  isfile = TRUE
379  '' Expression
380  hMatchExpressionEx( filestrexpr, FB_DATATYPE_INTEGER )
381 
382  else
383  isfile = FALSE
384  '' STRING_LIT?
385  if( lexGetClass( ) = FB_TKCLASS_STRLITERAL ) then
386  filestrexpr = astNewVAR( symbAllocStrConst( *lexGetText( ), lexGetTextLen( ) ) )
387  lexSkipToken( )
388  else
389  filestrexpr = NULL
390  addquestion = TRUE
391  end if
392  end if
393 
394  '' ','|';'
395  if( (isfile) or (filestrexpr <> NULL) ) then
396  if( hMatch( CHAR_COMMA ) = FALSE ) then
397  if( hMatch( CHAR_SEMICOLON ) = FALSE ) then
398  errReport( FB_ERRMSG_EXPECTEDCOMMA )
399  else
400  addquestion = TRUE
401  end if
402  end if
403  end if
404 
405  ''
406  if( rtlFileInput( isfile, filestrexpr, addquestion, addnewline ) = FALSE ) then
407  exit function
408  end if
409 
410  '' Variable (',' Variable)*
411  do
412  dstexpr = cVarOrDeref( )
413  if( dstexpr = NULL ) then
414  errReport( FB_ERRMSG_EXPECTEDIDENTIFIER )
415  dstexpr = NULL
416  hSkipUntil( CHAR_COMMA )
417  end if
418 
419  if( hMatch( CHAR_COMMA ) ) then
420  islast = FALSE
421  else
422  islast = TRUE
423  end if
424 
425  if( dstexpr <> NULL ) then
426  '' dest can't be a top-level const
427  if( typeIsConst( astGetFullType( dstexpr ) ) ) then
428  errReport( FB_ERRMSG_CONSTANTCANTBECHANGED )
429  end if
430 
431  if( rtlFileInputGet( dstexpr ) = FALSE ) then
432  exit function
433  end if
434  end if
435 
436  loop until( islast )
437 
438  function = TRUE
439 
440 end function
441 
442 '':::::
443 function hFileClose _
444  ( _
445  byval isfunc as integer _
446  ) as ASTNODE ptr
447 
448  dim as integer cnt
449  dim as ASTNODE ptr filenum, proc
450 
451  function = NULL
452 
453  '' CLOSE
454  lexSkipToken( )
455 
456  if( isfunc ) then
457  '' '('
458  hMatchLPRNT( )
459  end if
460 
461  cnt = 0
462  do
463  hMatch( CHAR_SHARP )
464 
465  filenum = cExpression( )
466  if( filenum = NULL ) then
467  if( cnt = 0 ) then
468  '' pass NULL to rtlFileClose to get close-all function
469  else
470  errReport( FB_ERRMSG_EXPECTEDEXPRESSION )
471  filenum = astNewCONSTi( 0 )
472  end if
473  end if
474 
475  proc = rtlFileClose( filenum, isfunc )
476  if( proc = NULL ) then
477  exit function
478  end if
479 
480  if( isfunc ) then
481  exit do
482  end if
483 
484  cnt += 1
485 
486  loop while( hMatch( CHAR_COMMA ) )
487 
488  if( isfunc ) then
489  '' ')'
490  hMatchRPRNT( )
491  end if
492 
493  function = proc
494 
495 end function
496 
497 '':::::
498 '' Put = PUT '#' Expression ',' Expression? ',' Expression{str|int|float|array} (',' Expression)?
499 ''
500 function hFilePut _
501  ( _
502  byval isfunc as integer _
503  ) as ASTNODE ptr
504 
505  dim as ASTNODE ptr fileexpr, posexpr, srcexpr, elmexpr
506  dim as integer isarray
507  dim as FBSYMBOL ptr s
508 
509  function = NULL
510 
511  '' '#'?
512  if( lexGetToken( ) = CHAR_SHARP ) then
513  lexSkipToken( )
514  end if
515 
516  hMatchExpressionEx( fileexpr, FB_DATATYPE_INTEGER )
517 
518  '' ',' offset
519  hMatchCOMMA( )
520 
521  posexpr = cExpression( )
522  if( posexpr = NULL ) then
523  posexpr = NULL
524  end if
525 
526  '' ',' source
527  hMatchCOMMA( )
528 
529  hMatchExpressionEx( srcexpr, FB_DATATYPE_INTEGER )
530 
531  '' don't allow literal values, due the way "byref as
532  '' any" args work (ie, the VB-way: literals are passed by value)
533  if( astIsCONST( srcexpr ) or astIsOFFSET( srcexpr ) ) then
534  astDelTree( srcexpr )
535  errReport( FB_ERRMSG_EXPECTEDIDENTIFIER, TRUE )
536  if( isfunc ) then
537  hSkipUntil( CHAR_RPRNT )
538  else
539  hSkipStmt( )
540  end if
541  return astNewCONSTi( 0 )
542  end if
543 
544  isarray = FALSE
545  if( lexGetToken( ) = CHAR_LPRNT ) then
546  if( lexGetLookAhead( 1 ) = CHAR_RPRNT ) then
547 
548  s = astGetSymbol( srcexpr )
549  if( s <> NULL ) then
550  isarray = symbIsArray( s )
551  if( isarray ) then
552 
553  '' don't allow var-len strings
554  if( symbGetType( s ) = FB_DATATYPE_STRING ) then
555  astDelTree( srcexpr )
556  errReport( FB_ERRMSG_INVALIDDATATYPES, TRUE )
557  if( isfunc ) then
558  hSkipUntil( CHAR_RPRNT )
559  else
560  hSkipStmt( )
561  end if
562  return astNewCONSTi( 0 )
563  end if
564 
565  lexSkipToken( )
566  lexSkipToken( )
567 
568  end if
569  end if
570  end if
571  end if
572 
573  '' (',' elements)?
574  if( hMatch( CHAR_COMMA ) ) then
575  if( isarray ) then
576  errReport( FB_ERRMSG_ELEMENTSMUSTBEEMPTY )
577  '' error recovery: skip elements
578  elmexpr = cExpression( )
579  if( elmexpr <> NULL ) then
580  astDelTree( elmexpr )
581  elmexpr = NULL
582  end if
583  else
584  '' don't allow elements if source is string type
585  select case astGetDataType( srcexpr )
586  case FB_DATATYPE_STRING, FB_DATATYPE_FIXSTR
587  errReport( FB_ERRMSG_ELEMENTSMUSTBEEMPTY )
588  '' error recovery: skip elements
589  elmexpr = cExpression( )
590  if( elmexpr <> NULL ) then
591  astDelTree( elmexpr )
592  elmexpr = NULL
593  end if
594  case else
595  elmexpr = cExpression( )
596  if( elmexpr = NULL ) then
597  errReport( FB_ERRMSG_EXPECTEDEXPRESSION )
598  end if
599  end select
600  end if
601 
602  '' elems has to be an integer or able to be converted
603  if( elmexpr ) then
604  if( typeIsPtr( astGetDatatype( elmexpr ) ) ) then
605  errReportWarn( FB_WARNINGMSG_PASSINGPTRTOSCALAR )
606  end if
607  if( astGetDatatype( elmexpr ) <> FB_DATATYPE_INTEGER ) then
608  elmexpr = astNewCONV( FB_DATATYPE_INTEGER, NULL, elmexpr )
609  if( elmexpr = NULL ) then
610  errReport( FB_ERRMSG_SYNTAXERROR, TRUE )
611  end if
612  end if
613  end if
614  else
615  elmexpr = NULL
616  end if
617 
618  if( isarray = FALSE ) then
619  function = rtlFilePut( fileexpr, posexpr, srcexpr, elmexpr, isfunc )
620  else
621  function = rtlFilePutArray( fileexpr, posexpr, srcexpr, isfunc )
622  end if
623 
624 end function
625 
626 '':::::
627 '' Get = GET '#' Expression ',' Expression? ',' Variable{str|int|float|array}
628 '' (',' Expression)? (',' variable)?
629 ''
630 function hFileGet _
631  ( _
632  byval isfunc as integer _
633  ) as ASTNODE ptr
634 
635  dim as ASTNODE ptr fileexpr, posexpr, dstexpr, elmexpr, iobexpr
636  dim as integer isarray
637  dim as FBSYMBOL ptr s
638 
639  function = NULL
640 
641  '' '#'?
642  if( lexGetToken( ) = CHAR_SHARP ) then
643  lexSkipToken( )
644  end if
645 
646  hMatchExpressionEx( fileexpr, FB_DATATYPE_INTEGER )
647 
648  '' ',' offset
649  hMatchCOMMA( )
650 
651  posexpr = cExpression( )
652 
653  '' ',' destine
654  hMatchCOMMA( )
655 
656  dstexpr = cVarOrDeref( )
657  if( dstexpr = NULL ) then
658  errReport( FB_ERRMSG_EXPECTEDIDENTIFIER )
659  if( isfunc ) then
660  hSkipUntil( CHAR_RPRNT )
661  else
662  hSkipStmt( )
663  end if
664  return astNewCONSTi( 0 )
665  end if
666 
667  isarray = FALSE
668  if( lexGetToken( ) = CHAR_LPRNT ) then
669  if( lexGetLookAhead( 1 ) = CHAR_RPRNT ) then
670  s = astGetSymbol( dstexpr )
671  if( s <> NULL ) then
672  isarray = symbIsArray( s )
673  if( isarray ) then
674  '' don't allow var-len strings
675  if( symbGetType( s ) = FB_DATATYPE_STRING ) then
676  errReport( FB_ERRMSG_INVALIDDATATYPES, TRUE )
677  if( isfunc ) then
678  hSkipUntil( CHAR_RPRNT )
679  else
680  hSkipStmt( )
681  end if
682  return astNewCONSTi( 0 )
683  end if
684  lexSkipToken( )
685  lexSkipToken( )
686  end if
687  end if
688  end if
689  end if
690 
691  '' (',' elements)?
692  if( hMatch( CHAR_COMMA ) ) then
693  elmexpr = cExpression( )
694  if( isarray ) then
695  '' elems must be NULL
696  if( elmexpr <> NULL ) then
697  errReport( FB_ERRMSG_ELEMENTSMUSTBEEMPTY )
698  astDelTree( elmexpr )
699  elmexpr = NULL
700  end if
701  else
702  if( elmexpr ) then
703  '' don't allow elements if destine is string type
704  select case astGetDataType( dstexpr )
705  case FB_DATATYPE_STRING, FB_DATATYPE_FIXSTR
706  errReport( FB_ERRMSG_ELEMENTSMUSTBEEMPTY )
707  '' error recovery: skip elements
708  astDelTree( elmexpr )
709  elmexpr = NULL
710  case else
711  '' elems has to be an integer or able to be converted
712  if( typeIsPtr( astGetDatatype( elmexpr ) ) ) then
713  errReportWarn( FB_WARNINGMSG_PASSINGPTRTOSCALAR )
714  end if
715  if( astGetDatatype( elmexpr ) <> FB_DATATYPE_INTEGER ) then
716  elmexpr = astNewCONV( FB_DATATYPE_INTEGER, NULL, elmexpr )
717  if( elmexpr = NULL ) then
718  errReport( FB_ERRMSG_SYNTAXERROR, TRUE )
719  end if
720  end if
721  end select
722  end if
723  end if
724  else
725  elmexpr = NULL
726  end if
727 
728  '' (',' iobytes)?
729  if( hMatch( CHAR_COMMA ) ) then
730  iobexpr = cVarOrDeref( )
731  if( iobexpr <> NULL ) then
732  s = astGetSymbol( iobexpr )
733  if( s <> NULL ) then
734  '' It's for a BYREF AS INTEGER parameter, so it
735  '' must be an integer type of the same size to
736  '' be allowed by astNewARG().
737  '' (Note: normally astNewARG() would do these
738  '' checks already, but this is a quirk RTL function,
739  '' and astNewARG()'s error reports may be confusing
740  '' if the RTL function parameters and the quirk syntax
741  '' arguments don't match up)
742  var dtype = symbGetType( s )
743  if( (typeGetSize( dtype ) <> env.pointersize) or _
744  (typeGetClass( dtype ) <> FB_DATACLASS_INTEGER) or _
745  typeIsPtr( dtype ) ) then
746  errReport( FB_ERRMSG_INVALIDDATATYPES )
747  end if
748  end if
749  else
750  errReport( FB_ERRMSG_EXPECTEDIDENTIFIER )
751  end if
752  else
753  iobexpr = NULL
754  end if
755 
756  '' dest can't be a top-level const
757  if( typeIsConst( astGetFullType( dstexpr ) ) ) then
758  errReport( FB_ERRMSG_CONSTANTCANTBECHANGED )
759  end if
760 
761  '' iobytes can't be a top-level const
762  if( iobexpr ) then
763  if( typeIsConst( astGetFullType( iobexpr ) ) ) then
764  errReport( FB_ERRMSG_CONSTANTCANTBECHANGED )
765  end if
766  end if
767 
768  if( isarray = FALSE ) then
769  function = rtlFileGet( fileexpr, posexpr, dstexpr, elmexpr, iobexpr, isfunc )
770  else
771  function = rtlFileGetArray( fileexpr, posexpr, dstexpr, iobexpr, isfunc )
772  end if
773 
774 end function
775 
776 '':::::
777 '' FileOpen = OPEN Expression{str}
778 '' (FOR Expression)? (ENCODING Expression)?
779 '' (ACCESS Expression)?
780 '' (SHARED|LOCK (READ|WRITE|READ WRITE))?
781 '' AS '#'? Expression
782 '' (LEN '=' Expression)?
783 ''
784 '' OPEN ("O"|"I"|"B"|"R"|"A")',' '#'? Expression{int}',' Expression{str} (',' Expression{int})?
785 ''
786 function hFileOpen _
787  ( _
788  byval isfunc as integer _
789  ) as ASTNODE ptr
790 
791  dim as ASTNODE ptr filenum, filename, fmode, faccess, flock, flen, fencoding
792  dim as integer short_form
793  dim as integer file_mode, access_mode, lock_mode, record_len
794  dim as FBOPENKIND open_kind
795 
796  function = NULL
797 
798  open_kind = FB_FILE_TYPE_FILE
799 
800  short_form = FALSE
801 
802  '' if it's a qb-style open, we only get an identifier, or a literal
803  if( fbLangIsSet( FB_LANG_QB ) = FALSE ) then
804  '' special devices
805  select case ucase( *lexGetText( ) )
806  case "CONS"
807  '' not a symbol?
808  if( lexGetSymChain( ) = NULL ) then
809  lexSkipToken( )
810  open_kind = FB_FILE_TYPE_CONS
811  end if
812 
813  case "ERR"
814  lexSkipToken( )
815  open_kind = FB_FILE_TYPE_ERR
816 
817  case "PIPE"
818  '' not a symbol?
819  if( lexGetSymChain( ) = NULL ) then
820  lexSkipToken( )
821  open_kind = FB_FILE_TYPE_PIPE
822  end if
823 
824  case "SCRN"
825  '' not a symbol?
826  if( lexGetSymChain( ) = NULL ) then
827  lexSkipToken( )
828  open_kind = FB_FILE_TYPE_SCRN
829  end if
830 
831  case "LPT"
832  '' not a symbol?
833  if( lexGetSymChain( ) = NULL ) then
834  lexSkipToken( )
835  open_kind = FB_FILE_TYPE_LPT
836  end if
837 
838  case "COM"
839  '' not a symbol?
840  if( lexGetSymChain( ) = NULL ) then
841  lexSkipToken( )
842  open_kind = FB_FILE_TYPE_COM
843  end if
844  end select
845 
846  end if
847 
848  if( isfunc ) then
849  '' '('
850  hMatchLPRNT( )
851  end if
852 
853  '' if it's a qb-style open, we only get an identifier, or a literal
854  if( fbLangIsSet( FB_LANG_QB ) ) then
855  open_kind = FB_FILE_TYPE_QB
856  end if
857 
858  select case as const open_kind
859  case FB_FILE_TYPE_FILE, FB_FILE_TYPE_PIPE, FB_FILE_TYPE_LPT, _
860  FB_FILE_TYPE_COM, FB_FILE_TYPE_QB
861 
862  '' a filename is only valid for some file types
863 
864  hMatchExpressionEx( filename, FB_DATATYPE_STRING )
865 
866  if( isfunc ) then
867  '' ','?
868  hMatch( CHAR_COMMA )
869  end if
870 
871  ' only test for short OPEN form when using the "normal" OPEN
872  select case open_kind
873  case FB_FILE_TYPE_FILE, FB_FILE_TYPE_QB
874  if( isfunc ) then
875  select case lexGetToken( )
876  case FB_TK_FOR, FB_TK_ACCESS, FB_TK_AS
877  case else
878  short_form = TRUE
879  end select
880  else
881  if( hMatch( CHAR_COMMA ) ) then
882  '' ',' -> indicates the short form
883  short_form = TRUE
884  end if
885  end if
886  end select
887 
888  case else
889 
890  ' no file name provided for this kind of OPEN statmenets
891  filename = astNewCONSTstr( "" )
892 
893  end select
894 
895  if( short_form ) then
896  '' file mode ("I"|"O"|"A"|"B"|"R")
897  fmode = filename
898  filename = NULL
899 
900  '' '#'? file number
901  hMatch( CHAR_SHARP )
902  hMatchExpressionEx( filenum, FB_DATATYPE_INTEGER )
903 
904  hMatchCOMMA( )
905  '' file name
906  hMatchExpressionEx( filename, FB_DATATYPE_STRING )
907 
908  '' record length
909  if( hMatch( CHAR_COMMA ) ) then
910  if( lexGetToken( ) <> CHAR_COMMA ) then
911  hMatchExpressionEx( flen, FB_DATATYPE_INTEGER )
912  end if
913  '' access mode
914  if( hMatch( CHAR_COMMA ) ) then
915  if( lexGetToken( ) <> CHAR_COMMA ) then
916  hMatchExpressionEx( faccess, FB_DATATYPE_STRING )
917  end if
918  '' lock mode
919  if( hMatch( CHAR_COMMA ) ) then
920  hMatchExpressionEx( flock, FB_DATATYPE_STRING )
921  end if
922  end if
923  end if
924 
925  if( flen = NULL ) then
926  flen = astNewCONSTi( 0 )
927  end if
928 
929  if( faccess = NULL ) then
930  faccess = astNewCONSTstr( "" )
931  end if
932 
933  if( flock = NULL ) then
934  flock = astNewCONSTstr( "" )
935  end if
936 
937  if( isfunc ) then
938  '' ')'
939  hMatchRPRNT( )
940  end if
941 
942  return rtlFileOpenShort( filename, fmode, faccess, flock, _
943  filenum, flen, isfunc )
944  end if
945 
946  '' long form..
947 
948  '' (FOR (INPUT|OUTPUT|BINARY|RANDOM|APPEND))?
949  if( hMatch( FB_TK_FOR ) ) then
950  select case ucase( *lexGetText( ) )
951  case "INPUT"
952  file_mode = FB_FILE_MODE_INPUT
953  case "OUTPUT"
954  file_mode = FB_FILE_MODE_OUTPUT
955  case "BINARY"
956  file_mode = FB_FILE_MODE_BINARY
957  case "RANDOM"
958  file_mode = FB_FILE_MODE_RANDOM
959  case "APPEND"
960  file_mode = FB_FILE_MODE_APPEND
961  case else
962  exit function
963  end select
964 
965  lexSkipToken( )
966 
967  else
968  file_mode = FB_FILE_MODE_RANDOM
969  end if
970 
971  fmode = astNewCONSTi( file_mode )
972 
973  if( isfunc ) then
974  '' ','?
975  hMatch( CHAR_COMMA )
976  end if
977 
978  fencoding = NULL
979 
980  if( fbLangIsSet( FB_LANG_QB ) ) = FALSE then
981  '' ENCODING is only allowed in text-mode
982  select case file_mode
983  case FB_FILE_MODE_INPUT, FB_FILE_MODE_OUTPUT, FB_FILE_MODE_APPEND
984  '' (ENCODING Expression)?
985  if( hMatch( FB_TK_ENCODING ) ) then
986  hMatchExpressionEx( fencoding, FB_DATATYPE_STRING )
987 
988  if( isfunc ) then
989  '' ','?
990  hMatch( CHAR_COMMA )
991  end if
992  end if
993  end select
994  end if
995 
996  '' (ACCESS (READ|WRITE|READ WRITE))?
997  if( hMatchText( "ACCESS" ) ) then
998  select case ucase( *lexGetText( ) )
999  case "WRITE"
1000  lexSkipToken( )
1001  access_mode = FB_FILE_ACCESS_WRITE
1002 
1003  case "READ"
1004  lexSkipToken( )
1005  if( hMatch( FB_TK_WRITE ) ) then
1006  access_mode = FB_FILE_ACCESS_READWRITE
1007  else
1008  access_mode = FB_FILE_ACCESS_READ
1009  end if
1010  end select
1011  else
1012  access_mode = FB_FILE_ACCESS_ANY
1013  end if
1014 
1015  faccess = astNewCONSTi( access_mode )
1016 
1017  if( isfunc ) then
1018  '' ','?
1019  hMatch( CHAR_COMMA )
1020  end if
1021 
1022  '' (SHARED|LOCK (READ|WRITE|READ WRITE))?
1023  if( hMatch( FB_TK_SHARED ) ) then
1024  lock_mode = FB_FILE_LOCK_SHARED
1025 
1026  elseif( hMatchText( "LOCK" ) ) then
1027  select case ucase( *lexGetText( ) )
1028  case "WRITE"
1029  lexSkipToken( )
1030  lock_mode = FB_FILE_LOCK_WRITE
1031 
1032  case "READ"
1033  lexSkipToken( )
1034  if( hMatch( FB_TK_WRITE ) ) then
1035  lock_mode = FB_FILE_LOCK_READWRITE
1036  else
1037  lock_mode = FB_FILE_LOCK_READ
1038  end if
1039  end select
1040  else
1041  lock_mode = FB_FILE_LOCK_SHARED
1042  end if
1043 
1044  flock = astNewCONSTi( lock_mode )
1045 
1046  if( isfunc ) then
1047  '' ','?
1048  hMatch( CHAR_COMMA )
1049  end if
1050 
1051  '' AS '#'? Expression
1052  if( hMatch( FB_TK_AS ) = FALSE ) then
1053  errReport( FB_ERRMSG_EXPECTINGAS )
1054  end if
1055 
1056  hMatch( CHAR_SHARP )
1057 
1058  hMatchExpressionEx( filenum, FB_DATATYPE_INTEGER )
1059 
1060  if( isfunc ) then
1061  '' ','?
1062  hMatch( CHAR_COMMA )
1063  end if
1064 
1065  '' (LEN '=' Expression)?
1066  if( hMatchText( "LEN" ) ) then
1067  if( cAssignToken( ) = FALSE ) then
1068  errReport( FB_ERRMSG_EXPECTEDEQ )
1069  flen = astNewCONSTi( 0 )
1070  else
1071  hMatchExpressionEx( flen, FB_DATATYPE_INTEGER )
1072  end if
1073  else
1074  flen = astNewCONSTi( 0 )
1075  end if
1076 
1077  if( isfunc ) then
1078  '' ')'
1079  hMatchRPRNT( )
1080  end if
1081 
1082  ''
1083  function = rtlFileOpen( filename, fmode, faccess, flock, _
1084  filenum, flen, fencoding, isfunc, open_kind )
1085 
1086 end function
1087 
1088 '':::::
1089 function hFileRename _
1090  ( _
1091  byval isfunc as integer _
1092  ) as ASTNODE ptr
1093 
1094  dim as ASTNODE ptr filename_old, filename_new
1095  dim as integer matchprnt
1096 
1097  function = NULL
1098 
1099  '' '('
1100  if( isfunc ) then
1101  hMatchLPRNT( )
1102  else
1103  '' '('?
1104  matchprnt = hMatch( CHAR_LPRNT )
1105  end if
1106 
1107  hMatchExpressionEx( filename_old, FB_DATATYPE_STRING )
1108 
1109  if( isfunc ) then
1110  '' ','?
1111  hMatchCOMMA( )
1112  else
1113  if( hMatch( FB_TK_AS ) = FALSE ) then
1114  if( hMatch( CHAR_COMMA ) = FALSE ) then
1115  errReport( FB_ERRMSG_EXPECTINGAS )
1116  end if
1117  end if
1118  end if
1119 
1120  hMatchExpressionEx( filename_new, FB_DATATYPE_STRING )
1121 
1122  if( isfunc or matchprnt ) then
1123  '' ')'
1124  hMatchRPRNT( )
1125  end if
1126 
1127  ''
1128  function = rtlFileRename( filename_new, filename_old, isfunc )
1129 
1130 end function
1131 
1132 '':::::
1133 '' FileStmt = OPEN ...
1134 '' | CLOSE ...
1135 '' | SEEK ...
1136 '' | LOCK ...
1137 '' | ...
1138 function cFileStmt _
1139  ( _
1140  byval tk as FB_TOKEN _
1141  ) as integer
1142 
1143  dim as ASTNODE ptr filenum, expr1, expr2
1144  dim as integer islock
1145 
1146  function = FALSE
1147 
1148  select case as const tk
1149  case FB_TK_OPEN
1150  lexSkipToken( )
1151 
1152  function = (hFileOpen( FALSE ) <> NULL)
1153 
1154 
1155  '' CLOSE ('#'? Expression)*
1156  case FB_TK_CLOSE
1157 
1158  function = (hFileClose( FALSE ) <> NULL)
1159 
1160  '' SEEK '#'? Expression ',' Expression
1161  case FB_TK_SEEK
1162  lexSkipToken( )
1163  hMatch( CHAR_SHARP )
1164 
1165  hMatchExpressionEx( filenum, FB_DATATYPE_INTEGER )
1166 
1167  hMatchCOMMA( )
1168 
1169  hMatchExpressionEx( expr1, FB_DATATYPE_INTEGER )
1170 
1171  function = rtlFileSeek( filenum, expr1 )
1172 
1173  '' PUT '#' Expression ',' Expression? ',' Expression{str|int|float|array}
1174  case FB_TK_PUT
1175  if( lexGetLookAhead(1) <> CHAR_SHARP ) then
1176  exit function
1177  end if
1178 
1179  lexSkipToken( )
1180 
1181  function = (hFilePut( FALSE ) <> NULL)
1182 
1183  '' GET '#' Expression ',' Expression? ',' Variable{str|int|float|array}
1184  case FB_TK_GET
1185  if( lexGetLookAhead(1) <> CHAR_SHARP ) then
1186  exit function
1187  end if
1188 
1189  lexSkipToken( )
1190 
1191  function = (hFileGet( FALSE ) <> NULL)
1192 
1193  '' (LOCK|UNLOCK) '#'? Expression, Expression (TO Expression)?
1194  case FB_TK_LOCK, FB_TK_UNLOCK
1195  if( tk = FB_TK_LOCK ) then
1196  islock = TRUE
1197  else
1198  islock = FALSE
1199  end if
1200 
1201  lexSkipToken( )
1202 
1203  hMatch( CHAR_SHARP )
1204 
1205  hMatchExpressionEx( filenum, FB_DATATYPE_INTEGER )
1206 
1207  hMatchCOMMA( )
1208 
1209  hMatchExpressionEx( expr1, FB_DATATYPE_INTEGER )
1210 
1211  if( hMatch( FB_TK_TO ) ) then
1212  hMatchExpressionEx( expr2, FB_DATATYPE_INTEGER )
1213  else
1214  expr2 = astNewCONSTi( 0 )
1215  end if
1216 
1217  function = rtlFileLock( islock, filenum, expr1, expr2 )
1218 
1219  '' NAME oldfilespec$ AS newfilespec$
1220  case FB_TK_NAME
1221  lexSkipToken( )
1222 
1223  function = (hFileRename( FALSE ) <> NULL)
1224 
1225  end select
1226 
1227 end function
1228 
1229 '':::::
1230 '' FileFunct = SEEK '(' Expression ')' |
1231 '' INPUT '(' Expr, (',' '#'? Expr)? ')'.
1232 ''
1233 function cFileFunct(byval tk as FB_TOKEN) as ASTNODE ptr
1234  dim as ASTNODE ptr filenum, expr
1235 
1236  function = NULL
1237 
1238  '' SEEK '(' Expression ')'
1239  select case as const tk
1240  case FB_TK_SEEK
1241  lexSkipToken( )
1242  hMatchLPRNT( )
1243  hMatchExpressionEx( filenum, FB_DATATYPE_INTEGER )
1244  hMatchRPRNT( )
1245  function = rtlFileTell( filenum )
1246 
1247  '' INPUT|WINPUT '(' Expr (',' '#'? Expr)? ')'
1248  case FB_TK_INPUT, FB_TK_WINPUT
1249  lexSkipToken( )
1250  hMatchLPRNT( )
1251  hMatchExpressionEx( expr, FB_DATATYPE_INTEGER )
1252  if( hMatch( CHAR_COMMA ) ) then
1253  hMatch( CHAR_SHARP )
1254  hMatchExpressionEx( filenum, FB_DATATYPE_INTEGER )
1255  else
1256  filenum = astNewCONSTi( 0 )
1257  end if
1258  hMatchRPRNT( )
1259  function = rtlFileStrInput( expr, filenum, tk )
1260 
1261  '' OPEN '(' ... ')'
1262  case FB_TK_OPEN
1263  lexSkipToken( )
1264  function = hFileOpen( TRUE )
1265 
1266  '' CLOSE '(' '#'? Expr? ')'
1267  case FB_TK_CLOSE
1268  function = hFileClose( TRUE )
1269 
1270  '' PUT '(' '#'? Expr, Expr?, Expr ')'
1271  case FB_TK_PUT
1272  lexSkipToken( )
1273  hMatchLPRNT( )
1274  function = hFilePut( TRUE )
1275  hMatchRPRNT( )
1276 
1277  '' GET '(' '#'? Expr, Expr?, Expr ')'
1278  case FB_TK_GET
1279  lexSkipToken( )
1280  hMatchLPRNT( )
1281  function = hFileGet( TRUE )
1282  hMatchRPRNT( )
1283 
1284  '' NAME '(' oldfilespec$ ',' newfilespec$ ')'
1285  case FB_TK_NAME
1286  lexSkipToken( )
1287  function = hFileRename( TRUE )
1288 
1289  end select
1290 end function
1291