1header{
2    import basic
3}
4options {
5    language=Python;
6}
7
8
9class basic_p extends Parser;
10options {
11    k = 4;              // two token lookahead
12    exportVocab=TinyBasic;      // Call its vocabulary "TinyBasic"
13    //codeGenMakeSwitchThreshold = 2;  // Some optimizations
14    //codeGenBitsetTestThreshold = 3;
15    defaultErrorHandler = false;     // Don't generate parser error handlers
16    //analyzerDebug=true;
17    buildAST = true;
18}
19
20tokens {
21    WS;
22}
23
24{
25}
26
27
28imaginaryTokenDefinitions
29    :
30        SLIST
31        TYPE
32        PROGRAM_DEF SUBROUTINE_DEF  FUNCTION_DEF
33        EXIT_MODULE
34        PARAMETERS  PARAMETER_DEF
35        LABELED_STAT    NUMBERED_STAT
36        UNARY_MINUS UNARY_PLUS
37        CASE_GROUP  ARGLIST
38        FOR_LOOP    FOR_FROM    FOR_TO
39        FOR_BY      FOR_BY_ONE  FOR_BODY
40
41        INT_FN_EXECUTE  FLT_FN_EXECUTE  STR_FN_EXECUTE
42        SUB_EXECUTE
43
44        EQ_COMP
45        INDEX_OP    SUBSTRING_OP    DOT
46        ARRAY1D     ARRAY2D     ARRAY3D
47        ARRAY1D_PROXY   ARRAY2D_PROXY   ARRAY3D_PROXY
48        VAR_PROXY
49
50        WHEN_ERROR_CALL WHEN_ERROR_IN
51
52        PRINT_ASCII PRINT_TAB
53        PRINT_NUMERIC   PRINT_STRING
54        PRINT_COMMA PRINT_SEMI
55        IF_THEN_BLOCK   IF_BLOCK    ELSE_IF_BLOCK   ELSE_BLOCK
56        CODE_BLOCK  CONDITION
57    ;
58
59// Compilation Unit: In TinyBasic, this is a single file.  This is the start
60//   rule for this parser
61compilationUnit[context] returns [r]
62    {
63        if not context:
64            context = basic.Context()
65        self.theContext=context;
66        r = self.theContext
67    }
68    :
69        // A compilation unit starts with an optional program definition
70        (   programDefinition
71        |   /* nothing */
72        )
73
74        // Next we have a series of zero or more sub/function blocks
75        (   subroutineDefinition
76        |   functionDefinition
77        )*
78
79        EOF!
80    ;
81
82
83// PROGRAM ( parameter, parameter)
84programDefinition
85    options {defaultErrorHandler = true;} // let ANTLR handle errors
86    {
87        pVector=None
88    }
89    :   "program"!
90        {
91
92            self.theContext.setProgramScope()
93        }
94        pVector=parameters  eol!
95        // now parse the body
96        cb:procedureBlock
97        quit:"end"      eol!
98        {
99            #quit.setType(EXIT_MODULE);
100            #programDefinition = #(#[PROGRAM_DEF,"PROGRAM_DEF"],#programDefinition);
101            self.theContext.popScope();
102        }
103
104    ;
105
106// SUB IDENT ( parameter)*
107subroutineDefinition
108    options {defaultErrorHandler = true;} // let ANTLR handle errors
109    {   pVector=None; }
110    :   p:"sub"! n:subName
111            {
112                self.theContext.pushSubroutineScope();
113            }
114            pVector=params:parameters   eol!
115        // now parse the body of the class
116        cb:procedureBlock
117        quit:"end" "sub"! eol!
118        {
119
120            #quit.setType(EXIT_MODULE);
121            #subroutineDefinition = #(#[SUBROUTINE_DEF,"SUBROUTINE_DEF"],#subroutineDefinition);
122            sub=basic.DTSubroutine(#subroutineDefinition,#cb,self.theContext.getCurrentScope(),pVector,#n.getText());
123            self.theContext.popScope();
124            self.theContext.insertSubroutine(#n.getText(),sub);
125        }
126
127    ;
128
129// FUNCTION IDENT ( parameter)*
130functionDefinition
131    options {defaultErrorHandler = true;} // let ANTLR handle errors
132    {
133    }
134    :   p:"function"^ fnType=n:newFunction {#p.setType(FUNCTION_DEF);}
135        {
136
137            self.theContext.pushScope(basic.FunctionScope(self.theContext.getCurrentScope()));
138        }
139        pVector=params:parameters   eol!
140        // now parse the body of the class
141        cb:procedureBlock
142        quit:"end" "function"! eol!
143        {
144
145            #quit.setType(EXIT_MODULE);
146            fnc=basic.DTFunction(fnType,#params,#cb,self.theContext.getCurrentScope(),pVector,#n.getText());
147            #functionDefinition = #(#[FUNCTION_DEF,"FUNCTION_DEF"],#functionDefinition);
148            self.theContext.popScope();
149            self.theContext.insertFunction(#n.getText(),fnc);
150        }
151    ;
152
153
154
155//funcName
156//  :
157//      INT_FN
158//  |   FLT_FN
159//  |   STR_FN
160//  ;
161
162newFunction returns [r]
163    :
164        INT_FN      { r=INT_FN; }
165    |   STR_FN      { r=STR_FN; }
166    |   FLT_FN      { r=FLT_FN; }
167    ;
168
169
170
171// This is the body of a procedure.
172procedureBlock
173    :
174        codeBlock
175    ;
176
177
178statement
179    :
180    nl
181    (
182        singleStatement
183    |   ifStatements
184    |   compoundStatement
185    )
186    ;
187
188
189parameters returns [r]
190    { r = [] }
191    :
192        (   (LPAREN)=>
193            LPAREN! parameterDeclarationList[r] RPAREN!
194        |
195        )
196        ;
197
198
199// A list of formal parameters
200parameterDeclarationList [r]
201    { tbd=None; }
202    :   tbd=parameterDeclaration
203            {
204                r.append(tbd);
205            }
206            ( COMMA! tbd=parameterDeclaration
207                {
208                    r.append(tbd);
209                }
210            )*
211        {#parameterDeclarationList = #(#[PARAMETERS,"PARAMETERS"],
212                                    #parameterDeclarationList);}
213    ;
214
215
216
217parameterDeclaration returns [r]
218        {
219            varType=0
220            r = None
221        }
222    :
223        varType=v:newVariable
224            (   LPAREN! //d1:integerExpression
225                (
226                    COMMA!  //d2:integerExpression
227                    (
228                        COMMA!  //d3:integerExpression
229                        {
230
231                            r = basic.DTDataTypeProxy(varType,self.theContext.getCurrentScope(),3);
232                        }
233                    |
234                        {
235
236                            r = basic.DTDataTypeProxy(varType,self.theContext.getCurrentScope(),2);
237                        }
238                    )
239                |
240                {
241
242                        r = basic.DTDataTypeProxy(varType,self.theContext.getCurrentScope(),1);
243                    }
244                )   RPAREN!
245            |
246                {
247
248                    r = basic.DTDataTypeProxy(varType,self.theContext.getCurrentScope(),0);
249                }
250            )
251            {
252                #parameterDeclaration = #([VAR_PROXY], #parameterDeclaration);
253                self.theContext.insertVariable(#v.getText(),r);
254            }
255    ;
256
257
258
259compoundStatement
260    :
261        forNextBlock
262    |   doUntilLoopBlock
263    |   doLoopUntilBlock
264    |   selectCaseBlock
265    |   eventCompoundStatements
266    ;
267
268ifThenBlock
269    :
270        ifBlock
271            (
272                options {
273                    warnWhenFollowAmbig = false;
274                }
275                :
276                elseIfBlock
277            )*
278
279            (
280                options {
281                    warnWhenFollowAmbig = false;
282                }
283                :
284                elseBlock
285            )?
286        endIfBlock
287        { #ifThenBlock = #(#[IF_THEN_BLOCK,"IF_THEN_BLOCK"],#ifThenBlock);}
288    ;
289
290ifStatements
291    :
292
293        (ifStatement)=> ifStatement
294    |   ifThenBlock
295    ;
296
297ifStatement
298    :
299        "if"!  condition "then"! singleStatement eol!
300    ;
301
302ifBlock
303    :
304        "if"!  condition "then"! eol!
305        codeBlock
306        { #ifBlock = #(#[IF_BLOCK,"IF_BLOCK"],#ifBlock);}
307    ;
308
309elseIfBlock
310    :
311        nl ("else"! "if"! | "elseif"! ) condition "then"! eol!
312        codeBlock
313        { #elseIfBlock = #(#[ELSE_IF_BLOCK,"ELSE_IF_BLOCK"],#elseIfBlock);}
314    ;
315
316elseBlock
317    :
318        nl "else"! eol!
319        codeBlock
320        { #elseBlock = #(#[ELSE_BLOCK,"ELSE_BLOCK"],#elseBlock);}
321    ;
322
323endIfBlock
324    :
325        nl ("end"! "if"! | "endif"! ) eol!
326    ;
327
328condition
329    :
330        relationalExpression
331        { #condition = #(#[CONDITION,"CONDITION"],#condition);}
332    ;
333
334codeBlock
335    :
336        (
337            options {
338                warnWhenFollowAmbig = false;
339            }
340            :
341            statement
342        )*
343        {#codeBlock = #(#[CODE_BLOCK,"CODE_BLOCK"],#codeBlock);}
344    ;
345
346forNextBlock
347    :
348        "for"!  (
349                // I=1    TO 2    (BY 1)?
350                forFrom   forTo   forBy        eol!
351                forBody
352            )
353        {#forNextBlock = #(#[FOR_LOOP,"FOR_LOOP"],#forNextBlock);}
354    ;
355
356// The initializer for a for loop
357forFrom
358    :   numericStore EQ^ numericExpression
359        {#forFrom = #(#[FOR_FROM,"FOR_FROM"],#forFrom);}
360    ;
361
362forTo
363    :    "to"! numericExpression
364        {#forTo = #(#[FOR_TO,"FOR_TO"],#forTo);}
365    ;
366
367forBy
368    :
369        (   "by"! numericExpression
370            {#forBy = #(#[FOR_BY,"FOR_BY"],#forBy);}
371        |
372            {#forBy = #(#[FOR_BY_ONE,"FOR_BY_ONE"],#forBy);}
373        )
374    ;
375
376forBody
377    :
378                codeBlock
379                nextStatement!
380                {#forBody = #(#[FOR_BODY,"FOR_BODY"],#forBody);}
381    ;
382
383nextStatement
384    :
385        nl "next" numericStore eol!
386    ;
387doUntilLoopBlock
388    :
389        "do"! "until"^  condition eol!
390                codeBlock
391        nl "loop"! eol!
392    ;
393
394doLoopUntilBlock
395    :
396        "do"^  eol!
397                codeBlock
398        nl "loop"! "until"!  condition eol!
399    ;
400
401selectCaseBlock
402    :
403        "select"^ "case"! expression eol
404            (casesGroup)*
405        nl "end" "select" eol!
406    ;
407
408singleStatement
409    :
410    (
411        "library"^  STR_CONST
412    |   "dim"^      dimensionedVariables
413    |   "global"^   parameterDeclarationList[[]]
414    |   "beep"
415    |   "chain"^    stringExpression    ("with" LPAREN! argList RPAREN!)?
416    |   "gosub"^    lineLabel
417    |   "goto"^ lineLabel
418    |   callSubroutineStatement
419    |   "return"^ (expression)?
420    |   ex:"exit"^ "sub"!   {#ex.setType(EXIT_MODULE);}
421
422    |   ("let"!)?   assignmentExpression
423    |   ("on" numericExpression)=>
424        "on"^ numericExpression ("goto"^    | "gosub"^ ) lineLabel  (COMMA! lineLabel)*
425    |   eventSingleStatements
426    |   "option"^   "base"  INT_CONST
427    |   "out"^  integerExpression COMMA! integerExpression
428    |   "pause"^    (numericExpression)?
429    |   "redim"^    dimensionedVariables
430    |   "poke"^
431            integerExpression COMMA!
432            integerExpression COMMA!
433            integerExpression
434    |   "randomize"^    integerExpression
435    |   graphicsOutput
436    |   inputOutput
437    |   line_stuff
438    |   set_stuff
439    )   eol!
440    ;
441
442
443callSubroutineStatement
444    :
445        call:"call"^ subName (LPAREN! argList RPAREN!)?
446        { #call.setType(SUB_EXECUTE); }
447    ;
448dimensionedVariables
449    { av=None; varType=0;}
450    :
451    (
452        varType=v:newVariable   LPAREN! d1:integerExpression
453            (
454                COMMA!  d2:integerExpression
455                (
456                    COMMA!  d3:integerExpression
457                    {
458
459                        av= basic.DTArray3D(varType,self.theContext.getCurrentScope());
460                        #dimensionedVariables = #([ARRAY3D, "ARRAY3D"], #dimensionedVariables);
461                    }
462                |
463                    {
464
465                        av= basic.DTArray2D(varType,self.theContext.getCurrentScope());
466                        #dimensionedVariables = #([ARRAY2D, "ARRAY2D"], #dimensionedVariables);
467                    }
468                )
469            |
470                {
471
472                    av= basic.DTArray1D(varType,self.theContext.getCurrentScope());
473                    #dimensionedVariables = #([ARRAY1D, "ARRAY1D"], #dimensionedVariables);
474                }
475            )   RPAREN!
476            { self.theContext.insertVariable(#v.getText(),av);}
477    )
478    (
479        COMMA dimensionedVariables
480    )?
481    ;
482
483
484
485lineLabel
486    :
487        INT_CONST
488    |   IDENT
489    ;
490
491nl
492    :
493    (
494    options {
495            warnWhenFollowAmbig = false;
496        }
497        :
498        IDENT^ c:COLON! {#c.setType(LABELED_STAT);}
499    |   INT_CONST^  {#c.setType(NUMBERED_STAT);}
500    )?
501    ;
502
503constant
504    :
505        stringConstant
506    |   floatNumber
507    ;
508
509binaryReadVariables
510    :
511        (   numericStore
512        |   stringStore "until" integerExpression
513        )   (COMMA binaryReadVariables)?
514    ;
515
516printList
517    :
518        (
519            tabExpression
520        |   printString
521        |   printNumeric
522        )   (
523                (   c:COMMA { #c.setType(PRINT_COMMA);}
524                |   s:SEMI  { #s.setType(PRINT_SEMI);}
525                ) (printList)?
526            )?
527
528    ;
529tabExpression
530    :
531        "tab"! LPAREN! numericExpression RPAREN!
532        { #tabExpression = #(#[PRINT_TAB,"PRINT_TAB"],#tabExpression);}
533    ;
534
535printString
536    :
537        stringExpression    { #printString = #(#[PRINT_STRING,"PRINT_STRING"],#printString);}
538    ;
539
540printNumeric
541    :
542        numericExpression   { #printNumeric = #(#[PRINT_NUMERIC,"PRINT_NUMERIC"],#printNumeric);}
543    ;
544
545inputList
546    :
547        (   numericStore
548        |   stringStore
549        )   (COMMA inputList)?
550
551    ;
552
553inputOutput
554    :
555        "close"^ (POUND! integerExpression)?
556        //| "cominfo"
557    |   "data"^ constant (COMMA! constant)*
558    |   "deletefile"    stringExpression
559        //| "fileinfo"
560    |   "input"
561        (
562            "binary"    (chanNumber)? binaryReadVariables
563        |   chanAndPrompt inputList
564        )
565    |   "open"  chanNumber stringExpression
566        (
567            COMMA
568            (
569                "access"
570                    (
571                        "input"
572                    |   "output"
573                    |   "outin"
574                    |   "append"
575                    )
576            |   "organization"
577                    (
578                        "sequential"
579                    |   "random"
580                    |   "stream"
581                    |   "append"
582                    )
583            |   "recsize" integerExpression
584            )
585        )+
586    //| "output"
587    |   print_ascii
588    |   "print" "binary" (chanNumber)? printList
589    |   "read"  inputList
590    |   "restore"
591    ;
592
593set_stuff
594    :
595        "set"
596        (
597            "timer" numericExpression
598        |   "loc"   LPAREN integerExpression COMMA integerExpression RPAREN
599        |   (chanNumber)? specifier integerExpression
600        )
601    ;
602print_ascii
603    :
604        "print"!    (chanNumber)?   ("using" stringExpression)? printList
605        {#print_ascii = #([PRINT_ASCII, "PRINT_ASCII"], #print_ascii);}
606    ;
607specifier
608    :
609        "margin"
610    |   "zonewidth"
611    |   "address"
612    |   "record"
613    ;
614
615chanNumber
616    :
617        POUND   integerExpression COLON
618    ;
619
620prompt
621    :
622        "prompt" stringExpression COLON
623    ;
624
625chanAndPrompt
626    :
627        (chanNumber)? (prompt)?
628    ;
629casesGroup
630    :
631        aCase
632        codeBlock
633        {#casesGroup = #([CASE_GROUP, "CASE_GROUP"], #casesGroup);}
634    ;
635
636
637
638integerArray
639    :
640        argArray
641    ;
642
643symbolicAddress
644    :
645        stringExpression
646    ;
647
648deviceAddress
649    :
650        (adapterAddress COMMA!)?    primaryAddress  (COMMA! secondaryAddress)?
651    ;
652
653primaryAddress
654    :
655        integerExpression
656    ;
657
658secondaryAddress
659    :
660        integerExpression
661    ;
662
663
664adapterAddress
665    :
666        stringExpression
667    |   "@" integerExpression
668    ;
669
670
671combinationAddress
672    :
673        (deviceAddress)=>   deviceAddress
674    |   adapterAddress
675
676    ;
677
678aCase
679    :   "case"^ expression (COMMA! expression)* eol!
680    ;
681
682
683
684integerArrayVariable
685    :
686        integerVariable
687    ;
688
689stringArrayVariable
690    :
691        stringVariable
692    ;
693
694floatArrayVariable
695    :
696        floatVariable
697    ;
698
699
700arrayVariable
701    :
702        integerArrayVariable
703    |   stringArrayVariable
704    |   floatArrayVariable
705    ;
706
707graphicsOutput
708    :
709        "brush"^    integerExpression
710    |   "circle"^   LPAREN! integerExpression COMMA integerExpression   RPAREN!
711                COMMA   integerExpression ( COMMA integerExpression )?
712    |   "clear"^    ("metafileon" | "metafileoff" )?
713    |   "ellipse"^  LPAREN! integerExpression COMMA integerExpression   RPAREN!
714            MINUS   LPAREN! integerExpression COMMA integerExpression   RPAREN!
715                ( COMMA integerExpression )?
716    |   "font"^     integerExpression
717                ( COMMA integerExpression ( COMMA integerExpression )? )?
718    |   "loc"^      integerStore COMMA integerStore
719    |   "pen"^      integerExpression COMMA integerExpression COMMA integerExpression
720    |   "picture"^  stringExpression
721                COMMA LPAREN!   integerExpression COMMA integerExpression   RPAREN!
722                ( COMMA integerExpression )?
723    |   "polyline"^ integerArrayVariable LPAREN COMMA RPAREN
724                ( COMMA integerExpression )?
725    |   "rectangle"^    LPAREN! integerExpression COMMA integerExpression   RPAREN!
726            MINUS   LPAREN! integerExpression COMMA integerExpression   RPAREN!
727                ( COMMA integerExpression )?
728    |   "screen"^   ( "normal" | "condensed" | "display" | "zoom" | "unzoom" | "close_basic" )
729    ;
730
731line_stuff  // ambiguity forced left factoring
732    :
733        "line"
734            (
735                "input" (chanNumber)? stringStore
736            |   "enter"         combinationAddress
737                        (prompt)?   stringStore ("until" integerExpression)?
738            |   (LPAREN!    integerExpression COMMA integerExpression   RPAREN!)?
739                MINUS   LPAREN! integerExpression COMMA integerExpression   RPAREN!
740                ( COMMA integerExpression )?
741
742            )
743
744    ;
745
746
747
748eventSingleStatements
749    :
750        "cause"     ("error")?  integerExpression
751    |   "cause"     "event"     integerExpression
752    |   ("disable" | "enable") ("srq"|"timer"|"gpib") ("discard")?
753    |   ("disable" | "enable") "event"  integerExpression ("discard")?
754    |   "error"
755            (
756                "abort" integerExpression
757            |   "retry"
758            |   "continue"
759            |   "stop"
760            )
761    |   "on"
762        (
763            "event" integerExpression
764        |   "srq"
765        |   "timer"
766        |   "gpib"
767        )   "call"  subName
768    ;
769
770eventCompoundStatements
771    :
772        w:"when"^ "error"
773        (
774            "call"^ subName (LPAREN!    argList RPAREN!)? eol!
775            {#w.setType(WHEN_ERROR_CALL);}
776        |   "in"!       eol!
777            {#w.setType(WHEN_ERROR_IN);}
778                (singleStatement)+
779            "use"^              eol!
780                (singleStatement)+
781            ("end"! "when"! | "endwhen"!)   eol
782        )
783    ;
784
785
786subName
787    :
788        IDENT
789    ;
790
791expression
792    :
793        numericExpression
794    |   stringExpression
795    ;
796
797argList
798    :   arg ( COMMA! arg )*
799        {#argList = #(#[ARGLIST,"ARGLIST"], argList);}
800    ;
801
802arg
803    :
804            //(variable LPAREN COMMA)=>
805            //variable LPAREN COMMA {dimCount=2;} (  COMMA {dimCount++;} )* RPAREN
806        (argArray)=>argArray
807            //| (variable LPAREN RPAREN)=>
808            //variable LPAREN   RPAREN
809    |   expression
810    ;
811
812argArray
813    :
814        (variable LPAREN COMMA)=>
815        v23:variable LPAREN! COMMA!
816                (   COMMA!
817                    { #v23.setType(ARRAY3D); }
818                |
819                    { #v23.setType(ARRAY2D); }
820                ) RPAREN!
821    |   //(variable LPAREN RPAREN)=>
822        v1:variable LPAREN   RPAREN
823            { #v1.setType(ARRAY1D); }
824    ;
825
826
827
828// assignment expression (level 13)
829assignmentExpression
830    :
831        stringStore     EQ^     stringExpression
832    |   integerStore        EQ^ integerExpression
833    |   floatStore      EQ^ numericExpression
834    ;
835
836stringStore
837    :
838        (stringVariable LPAREN)=>
839        {self.theContext.isArrayVariable(self.LT(1).getText())}?
840        stringVariable  lp:LPAREN^  {#lp.setType(INDEX_OP);}
841                    indices
842                RPAREN
843    |   (stringVariable LBRACK)=>
844        stringVariable  lb:LBRACK^  {#lb.setType(SUBSTRING_OP);}
845                    integerExpression COLON!  integerExpression
846                RBRACK!
847    |   stringVariable
848    ;
849
850integerStore
851    :
852        ( integerVariable LPAREN )=>
853        {self.theContext.isArrayVariable(self.LT(1).getText())}?
854        integerVariable lp:LPAREN^  {#lp.setType(INDEX_OP);}
855                    indices
856                RPAREN!
857    |   integerVariable
858    ;
859
860floatStore
861    :
862        ( floatVariable LPAREN )=>
863        {self.theContext.isArrayVariable(self.LT(1).getText())}?
864        floatVariable   lp:LPAREN^  {#lp.setType(INDEX_OP);}
865                    indices
866                RPAREN!
867    |   floatVariable
868    ;
869
870numericStore
871    :
872        integerStore
873    |   floatStore
874    ;
875
876stringVariable
877    :
878        STR_VAR
879    ;
880
881integerVariable
882    :
883        INT_VAR
884    ;
885
886floatVariable
887    :
888    (
889        FLT_VAR
890    |   IDENT
891    )
892    ;
893
894
895// boolean relational expressions (level 5)
896
897relationalExpression
898    :       relationalXORExpression
899    ;
900
901relationalXORExpression
902    :       relationalORExpression  (   "xor"^  relationalORExpression  )*
903    ;
904
905
906
907relationalORExpression
908    :       relationalANDExpression     (   "or"^   relationalANDExpression     )*
909    ;
910
911
912relationalANDExpression
913    :       relationalNOTExpression     (   "and"^  relationalNOTExpression     )*
914    ;
915
916relationalNOTExpression
917    : ("not"^)? primaryRelationalExpression
918    ;
919
920
921
922primaryRelationalExpression
923    :
924        (numericExpression)=>
925        numericExpression
926            (   LT^
927            |   GT^
928            |   LE^
929            |   GE^
930            |   e1:EQ^  {#e1.setType( EQ_COMP );}
931            |   NE_COMP^
932            )
933            numericExpression
934    |   stringExpression
935            (   LT^
936            |   GT^
937            |   LE^
938            |   GE^
939            |   e2:EQ^  {#e2.setType( EQ_COMP );}
940            |   NE_COMP^
941            )
942            stringExpression
943    |   LPAREN! relationalExpression    RPAREN!
944    ;
945
946
947numericValuedFunctionExpression
948    :
949        "abs"^      LPAREN! numericExpression   RPAREN!
950    |   "acos"^     LPAREN! numericExpression   RPAREN!
951    |   "asc"^      LPAREN! stringExpression    RPAREN!
952    |   "atn"^      LPAREN! numericExpression   RPAREN!
953    |   "cos"^      LPAREN! numericExpression   RPAREN!
954    |   "dround"^   LPAREN! numericExpression COMMA! integerExpression  RPAREN!
955    |   "errl"^
956    |   "errn"^
957    |   "exp"^      LPAREN! numericExpression   RPAREN!
958    |   "fract"^    LPAREN! numericExpression   RPAREN!
959    |   "get_event"^    LPAREN! numericExpression   RPAREN!
960    |   "in"^       LPAREN! numericExpression   RPAREN!
961    |   "instr"^    LPAREN! stringExpression COMMA! stringExpression    RPAREN!
962    |   "int"^      LPAREN! numericExpression   RPAREN!
963    |   "ival"^     LPAREN! stringExpression    RPAREN!
964    |   "len"^      LPAREN! stringExpression    RPAREN!
965    |   "lgt"^      LPAREN! numericExpression   RPAREN!
966    |   "log"^      LPAREN! numericExpression   RPAREN!
967    |   "max"^      LPAREN! (numericExpression)+    RPAREN!
968    |   "min"^      LPAREN! (numericExpression)+    RPAREN!
969    |   "peek"^     LPAREN! numericExpression COMMA! integerExpression  RPAREN!
970    |   "pi"^
971    |   "rnd"^
972    |   "sgn"^      LPAREN! numericExpression   RPAREN!
973    |   "signed"^   LPAREN! integerExpression   RPAREN!
974    |   "sin"^      LPAREN! numericExpression   RPAREN!
975    |   "sqr"^      LPAREN! numericExpression   RPAREN!
976    |   "tan"^      LPAREN! numericExpression   RPAREN!
977    |   "time"^
978    |   "ubound"^   LPAREN! stringExpression    COMMA!  integerExpression   RPAREN!
979    |   "val"^      LPAREN! stringExpression    RPAREN!
980    |   "andb"^     LPAREN! integerExpression COMMA! integerExpression      RPAREN!
981    |   "orb"^      LPAREN! integerExpression COMMA! integerExpression      RPAREN!
982    |   "notb"^     LPAREN! integerExpression   RPAREN!
983    |   "shiftb"^   LPAREN! integerExpression COMMA! integerExpression      RPAREN!
984    |   "xorb"^     LPAREN! integerExpression COMMA! integerExpression      RPAREN!
985    ;
986
987integerExpression
988    :
989        numericExpression
990    ;
991
992stringValuedFunctionExpression
993    :
994        "chr$"^     LPAREN! integerExpression   RPAREN!
995    |   "date$"^
996    |   "dround$"^  LPAREN! numericExpression   COMMA! integerExpression    RPAREN!
997    |   "errl$"^
998    |   "errn$"^    LPAREN! integerExpression   RPAREN!
999    |   "inchr$"^
1000    |   "ival$"^    LPAREN! integerExpression   COMMA! integerExpression    RPAREN!
1001    |   "lwc$"^     LPAREN! stringExpression    RPAREN!
1002    |   "rpt$"^     LPAREN! stringExpression    COMMA! integerExpression    RPAREN!
1003    |   "time$"^
1004    |   "upc$"^     LPAREN! stringExpression    RPAREN!
1005    |   "val$"^     LPAREN! numericExpression   RPAREN!
1006    ;
1007
1008//numericExpression
1009//  :   numericAdditiveExpression
1010//  ;
1011
1012
1013// binary addition/subtraction (level 3)
1014numericExpression
1015    :
1016        numericMultiplicativeExpression
1017        (
1018            options {
1019                warnWhenFollowAmbig = false;
1020            }
1021            :
1022            (PLUS^ | MINUS^) numericMultiplicativeExpression
1023        )*
1024    ;
1025
1026
1027// multiplication/division/modulo (level 2)
1028numericMultiplicativeExpression
1029    :   numericExponentialExpression ((STAR^ | "div"^ | "mod"^ | SLASH^ ) numericExponentialExpression)*
1030    ;
1031
1032numericExponentialExpression
1033    :       numericUnaryExpression ( EXPO^  numericUnaryExpression)*
1034    ;
1035
1036numericUnaryExpression
1037:
1038        (
1039            p:PLUS^ {#p.setType(UNARY_PLUS);}
1040        |   m:MINUS^    {#m.setType(UNARY_MINUS);}
1041        )?  numericPrimaryExpression
1042    ;
1043
1044numericPrimaryExpression
1045    :
1046        floatNumber
1047    |   numericStore
1048    |   //(FLT_FN|INT_FN)=>
1049        (   FLT_FN^     {#FLT_FN.setType(FLT_FN_EXECUTE);}
1050        |   INT_FN^     {#INT_FN.setType(INT_FN_EXECUTE);}
1051        )
1052            (
1053                (LPAREN)=>
1054                LPAREN  argList RPAREN
1055            |
1056            )
1057    |   numericValuedFunctionExpression
1058    |   e:LPAREN! numericExpression RPAREN!
1059    ;
1060
1061floatNumber
1062    :
1063        integerNumber
1064    |   FLT_CONST
1065    ;
1066
1067
1068stringExpression
1069    :   stringConcatanateExpression
1070    ;
1071
1072// binary addition/subtraction (level 3)
1073stringConcatanateExpression
1074    :   stringPrimaryExpression ( AMPERSAND^ stringConcatanateExpression)?
1075    ;
1076
1077
1078stringPrimaryExpression
1079    :
1080        stringStore
1081    |   stringConstant
1082    |   STR_FN^ ((LPAREN)=>LPAREN!  argList RPAREN!)? {#STR_FN.setType(STR_FN_EXECUTE);}
1083    |   stringValuedFunctionExpression
1084    ;
1085
1086
1087indices
1088    :
1089        numericExpression (COMMA! indices)?
1090    ;
1091
1092stringConstant
1093    :
1094        STR_CONST
1095    ;
1096
1097
1098
1099
1100integerNumber
1101    :
1102        INT_CONST
1103    |   BINARY_INTEGER
1104    |   OCTAL_INTEGER
1105    |   HEXADECIMAL_INTEGER
1106    ;
1107
1108
1109
1110newVariable returns [r]
1111    { r=0;}
1112    :
1113        INT_VAR     { r=INT_VAR; }
1114    |   STR_VAR     { r=STR_VAR; }
1115    |   FLT_VAR     { r=FLT_VAR; }
1116    |   IDENT       { r=FLT_VAR; }
1117    ;
1118
1119variable
1120    :
1121        numericStore
1122    |   stringStore
1123    ;
1124
1125
1126
1127eol!
1128    :
1129    (
1130    options {
1131            warnWhenFollowAmbig = false;
1132        }
1133        :
1134        EOL!
1135    )+
1136    ;
1137
1138//----------------------------------------------------------------------------
1139//----------------------------------------------------------------------------
1140// The TinyBasic scanner
1141//----------------------------------------------------------------------------
1142//----------------------------------------------------------------------------
1143class basic_l extends Lexer;
1144
1145options {
1146    importVocab=TinyBasic;  // call the vocabulary "TinyBasic"
1147    testLiterals=true;     // automatically test for literals
1148    k=6;                   // four characters of lookahead
1149    caseSensitive=false;
1150    caseSensitiveLiterals = false;
1151}
1152
1153
1154
1155// OPERATORS
1156AMPERSAND       :   '&'     ;
1157LPAREN          :   '('     ;
1158RPAREN          :   ')'     ;
1159LBRACK          :   '['     ;
1160RBRACK          :   ']'     ;
1161COLON           :   ':'     ;
1162COMMA           :   ','     ;
1163//DOT           :   '.'     ;
1164EQ          :   '='     ;
1165NE_COMP         :   "<>"        ;
1166//BNOT          :   '~'     ;
1167SLASH           :   '/'     ;
1168PLUS            :   '+'     ;
1169MINUS           :   '-'     ;
1170STAR            :   '*'     ;
1171GE          :   ">="        ;
1172GT          :   ">"     ;
1173LE          :   "<="        ;
1174LT          :   '<'     ;
1175SEMI            :   ';'     ;
1176POUND           :   '#'     ;
1177
1178
1179BINARY_INTEGER
1180    :
1181        "&b" ('0' | '1' ) +
1182    ;
1183
1184OCTAL_INTEGER
1185    :
1186        "&o" ('0'..'7' ) +
1187    ;
1188
1189HEXADECIMAL_INTEGER
1190    :
1191        "&h" ('0'..'9' | 'a'..'f' ) +
1192    ;
1193
1194// Whitespace -- ignored
1195WS  :
1196        (   ' '
1197        |   '\t'
1198        |   '\f'
1199        )
1200        { _ttype = Token.SKIP; }
1201    ;
1202
1203EOL
1204    :
1205        (   "\r\n"  // Evil DOS
1206        |   '\r'    // Macintosh
1207        |   '\n'    // Unix (the right way)
1208        )
1209        { self.newline(); }
1210    ;
1211
1212// Single-line comments
1213SL_COMMENT
1214    :   '!'
1215        (~('\n'|'\r'))*
1216        //('\n'|'\r'('\n')?)
1217        {
1218            $setType(Token.SKIP);
1219            //newline();
1220        }
1221
1222    ;
1223
1224
1225// character literals
1226CHAR_LITERAL
1227    :   '\'' ( (ESCc)=> ESCc | ~'\'' ) '\''
1228    ;
1229
1230// string literals
1231STR_CONST
1232    :   '"'! ( (ESCs)=> ESCs | (ESCqs)=> ESCqs | ~('"'))* '"'!
1233    ;
1234
1235protected
1236ESCc
1237    :   '<' ('0'..'9')+ '>'
1238    ;
1239
1240protected
1241ESCs
1242    :   "<<"    ('0'..'9')+ ">>"
1243    ;
1244
1245protected
1246ESCqs
1247    :
1248        '"' '"'!
1249    ;
1250// hexadecimal digit (again, note it's protected!)
1251protected
1252HEX_DIGIT
1253    :   ('0'..'9'|'a'..'f')
1254    ;
1255
1256
1257// a dummy rule to force vocabulary to be all characters (except special
1258//   ones that ANTLR uses internally (0 to 2)
1259protected
1260VOCAB
1261    :   '\3'..'\377'
1262    ;
1263
1264
1265// an identifier.  Note that testLiterals is set to true!  This means
1266// that after we match the rule, we look in the literals table to see
1267// if it's a literal or really an identifer
1268IDENT
1269    options {testLiterals=true;}
1270    :   ('a'..'z') ('a'..'z'|'0'..'9'|'_'|'.')*
1271            (
1272                '$'
1273                {
1274                    if $getText[0:2].lower() == "fn" :
1275                        _ttype=STR_FN;
1276                    else:
1277                        _ttype=STR_VAR;
1278                }
1279            |   '%'
1280                {
1281                    if $getText[0:2].lower() == "fn" :
1282                        _ttype=INT_FN;
1283                    else:
1284                        _ttype=INT_VAR;
1285                }
1286            |   '#'
1287                {
1288                    if $getText[0:2].lower() == "fn" :
1289                        _ttype=FLT_FN;
1290                    else:
1291                        _ttype=FLT_VAR;
1292                }
1293            |
1294                {
1295                    if $getText[0:2].lower() == "fn" :
1296                        _ttype=FLT_FN;
1297                }
1298
1299            )
1300    ;
1301
1302
1303// a numeric literal
1304INT_CONST
1305    {
1306        isDecimal=False
1307    }
1308    :   '.' { $setType(DOT) }
1309            (('0'..'9')+ (EXPONENT)? (FLT_SUFFIX)? { $setType(FLT_CONST) })?
1310    |   (   '0' {isDecimal = True} // special case for just '0'
1311            (   ('x')
1312                (                                           // hex
1313                    // the 'e'|'E' and float suffix stuff look
1314                    // like hex digits, hence the (...)+ doesn't
1315                    // know when to stop: ambig.  ANTLR resolves
1316                    // it correctly by matching immediately.  It
1317                    // is therefor ok to hush warning.
1318                    options {
1319                        warnWhenFollowAmbig=false;
1320                    }
1321                :   HEX_DIGIT
1322                )+
1323            |   ('0'..'7')+                                 // octal
1324            )?
1325        |   ('1'..'9') ('0'..'9')*  {isDecimal=True}       // non-zero decimal
1326        )
1327        (   ('l')
1328
1329        // only check to see if it's a float if looks like decimal so far
1330        |   {isDecimal}?
1331            (   '.' ('0'..'9')* (EXPONENT)? (FLT_SUFFIX)?
1332            |   EXPONENT (FLT_SUFFIX)?
1333            |   FLT_SUFFIX
1334            )
1335            { $setType(FLT_CONST); }
1336        )?
1337    ;
1338
1339
1340// a couple protected methods to assist in matching floating point numbers
1341protected
1342EXPONENT
1343    :   ('e') ('+'|'-')? ('0'..'9')+
1344    ;
1345
1346
1347protected
1348FLT_SUFFIX
1349    :   'f'|'d'
1350    ;
1351
1352