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