1 /*
   2  * Copyright (c) 2008, 2014, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 grammar JSL;
  27 
  28 options {
  29     backtrack=true;
  30 }
  31 
  32 tokens {
  33     STAR  = '*'  ;
  34     SLASH = '/'  ;
  35     PLUS  = '+'  ;
  36     DASH  = '-'  ;
  37     LT    = '<'  ;
  38     GT    = '>'  ;
  39     LTEQ  = '<=' ;
  40     GTEQ  = '>=' ;
  41     EQEQ  = '==' ;
  42     NEQ   = '!=' ;
  43     AND   = '&&' ;
  44     XOR   = '^^' ;
  45     OR    = '||' ;
  46     INC   = '++' ;
  47     DEC   = '--' ;
  48 
  49     STAREQ  = '*=' ;
  50     SLASHEQ = '/=' ;
  51     PLUSEQ  = '+=' ;
  52     DASHEQ  = '-=' ;
  53 
  54     LEFT_PAREN    = '(' ;
  55     RIGHT_PAREN   = ')' ;
  56     LEFT_BRACKET  = '[' ;
  57     RIGHT_BRACKET = ']' ;
  58     LEFT_BRACE    = '{' ;
  59     RIGHT_BRACE   = '}' ;
  60 
  61     LEFT_FRENCH   = '<<' ;
  62     RIGHT_FRENCH  = '>>' ;
  63 
  64     DOT           = '.' ;
  65     COMMA         = ',' ;
  66     EQUAL         = '=' ;
  67     BANG          = '!' ;
  68     TILDE         = '~' ;
  69     QUESTION      = '?' ;
  70     COLON         = ':' ;
  71     SEMICOLON     = ';' ;
  72 
  73     IF    = 'if'    ;
  74     ELSE  = 'else'  ;
  75     WHILE = 'while' ;
  76     DO    = 'do'    ;
  77     FOR   = 'for'   ;
  78 
  79     UNROLL = 'unroll' ;
  80 
  81     CONTINUE = 'continue' ;
  82     BREAK    = 'break'    ;
  83     DISCARD  = 'discard'  ;
  84     RETURN   = 'return'   ;
  85 
  86     VOID = 'void' ;
  87 }
  88 
  89 @header {
  90     package com.sun.scenario.effect.compiler;
  91 
  92     import com.sun.scenario.effect.compiler.model.*;
  93     import com.sun.scenario.effect.compiler.tree.*;
  94 }
  95 
  96 @lexer::header {
  97     package com.sun.scenario.effect.compiler;
  98 }
  99 
 100 @lexer::members {
 101     // allow tests to turn on quiet mode, to reduce spewage
 102     public static boolean quiet;
 103 
 104     public void emitErrorMessage(String error) {
 105         if (quiet) return;
 106         super.emitErrorMessage(error);
 107     }
 108 }
 109 
 110 @members {
 111     private SymbolTable symbols = new SymbolTable();
 112     private TreeMaker tm = new TreeMaker(symbols);
 113 
 114     public SymbolTable getSymbolTable() {
 115         return symbols;
 116     }
 117 
 118     // fail on first error for now
 119     // TODO: collect errors and recover...
 120     protected void mismatch(IntStream input, int tokenType, BitSet follow) throws RecognitionException {
 121         MismatchedTokenException ex = new MismatchedTokenException(tokenType, input);
 122         System.err.println("Token mismatch at " + ex.line + ":" + ex.charPositionInLine);
 123         throw ex;
 124     }
 125     
 126     public void recoverFromMismatchedSet(IntStream input, int ttype, BitSet follow)
 127         throws RecognitionException {
 128         throw new MissingTokenException(ttype, input, null);
 129     }
 130 }
 131 
 132 @rulecatch {
 133     catch (RecognitionException ex) {
 134         throw ex;
 135     }
 136 }
 137 
 138 field_selection returns [String fields]
 139         : r=RGBA_FIELDS { $fields = $r.text; }
 140         | x=XYZW_FIELDS { $fields = $x.text; }
 141         ;
 142 
 143 primary_expression returns [Expr expr]
 144         : IDENTIFIER    { $expr = tm.variable($IDENTIFIER.text); }
 145         | INTCONSTANT   { $expr = tm.literal(Type.INT, Integer.valueOf($INTCONSTANT.text)); }
 146         | FLOATCONSTANT { $expr = tm.literal(Type.FLOAT, Float.valueOf($FLOATCONSTANT.text)); }
 147         | BOOLCONSTANT  { $expr = tm.literal(Type.BOOL, Boolean.valueOf($BOOLCONSTANT.text)); }
 148         | LEFT_PAREN e=expression RIGHT_PAREN { $expr = tm.parenExpr($e.expr); }
 149         ;
 150 
 151 primary_or_call returns [Expr expr]
 152         : e=primary_expression { $expr = $e.expr; }
 153         | f=function_call      { $expr = $f.expr; }
 154         ;
 155 
 156 //
 157 // TODO: not sure how to do this properly without mutual left-recursion;
 158 // for now we hack it to allow:
 159 //   arr[3].rgb
 160 //   arr[3]
 161 //   val.rgb
 162 //   val++
 163 //   val--
 164 //   val
 165 // but not things like:
 166 //   arr[3].r++
 167 //
 168 postfix_expression returns [Expr expr]
 169         : e=primary_or_call LEFT_BRACKET ae=expression RIGHT_BRACKET fs=field_selection
 170               { $expr = tm.fieldSelect(tm.arrayAccess($e.expr, $ae.expr), $fs.fields); }
 171         | e=primary_or_call LEFT_BRACKET ae=expression RIGHT_BRACKET
 172               { $expr = tm.arrayAccess($e.expr, $ae.expr); }
 173         | e=primary_or_call fs=field_selection
 174               { $expr = tm.fieldSelect($e.expr, $fs.fields); }
 175         | e=primary_or_call INC
 176               { $expr = tm.unary(UnaryOpType.INC, $e.expr); }
 177         | e=primary_or_call DEC
 178               { $expr = tm.unary(UnaryOpType.DEC, $e.expr); }
 179         | e=primary_or_call
 180               { $expr = $e.expr; }
 181         ;
 182 
 183 // From the GLSL spec...
 184 // Grammar Note: Constructors look like functions, but lexical
 185 // analysis recognized most of them as keywords.  They are now
 186 // recognized through "type_specifier".
 187 
 188 function_call returns [Expr expr]
 189         : id=IDENTIFIER LEFT_PAREN p=function_call_parameter_list? RIGHT_PAREN
 190             {
 191                 $expr = tm.call($id.text, p!=null ? $p.exprList : null);
 192             }
 193         | ts=type_specifier LEFT_PAREN p=function_call_parameter_list? RIGHT_PAREN
 194             {
 195                 Type type = Type.fromToken($ts.text);
 196                 $expr = tm.vectorCtor(type, p!=null ? $p.exprList : null);
 197             }
 198         ;
 199         
 200 function_call_parameter_list returns [List<Expr> exprList = new ArrayList<Expr>()]
 201         : a=assignment_expression { $exprList.add($a.expr); }
 202           (COMMA a=assignment_expression {$exprList.add($a.expr); }
 203           )*
 204         ;
 205         
 206 unary_expression returns [Expr expr]
 207         : p=postfix_expression     { $expr = $p.expr; }
 208         | INC   u=unary_expression { $expr = tm.unary(UnaryOpType.INC,     $u.expr); }
 209         | DEC   u=unary_expression { $expr = tm.unary(UnaryOpType.DEC,     $u.expr); }
 210         | PLUS  u=unary_expression { $expr = tm.unary(UnaryOpType.PLUS,    $u.expr); }
 211         | DASH  u=unary_expression { $expr = tm.unary(UnaryOpType.MINUS,   $u.expr); }
 212         | BANG  u=unary_expression { $expr = tm.unary(UnaryOpType.NOT,     $u.expr); }
 213         ;
 214 
 215 // From the GLSL spec...
 216 // Grammar Note:  No traditional style type casts.
 217 
 218 // From the GLSL spec...
 219 // Grammar Note:  No '*' or '&' unary ops.  Pointers are not supported.
 220 
 221 multiplicative_expression returns [Expr expr]
 222         : a=unary_expression { $expr = $a.expr; }
 223           (STAR  b=multiplicative_expression { $expr = tm.binary(BinaryOpType.MUL, $expr, $b.expr); }
 224           |SLASH b=multiplicative_expression { $expr = tm.binary(BinaryOpType.DIV, $expr, $b.expr); }
 225           )*
 226         ;
 227         
 228 additive_expression returns [Expr expr]
 229         : a=multiplicative_expression { $expr = $a.expr; }
 230           (PLUS b=multiplicative_expression { $expr = tm.binary(BinaryOpType.ADD, $expr, $b.expr); }
 231           |DASH b=multiplicative_expression { $expr = tm.binary(BinaryOpType.SUB, $expr, $b.expr); }
 232           )*
 233         ;
 234 
 235 relational_expression returns [Expr expr]
 236         : a=additive_expression { $expr = $a.expr; }
 237           (LTEQ b=additive_expression { $expr = tm.binary(BinaryOpType.LTEQ, $expr, $b.expr); }
 238           |GTEQ b=additive_expression { $expr = tm.binary(BinaryOpType.GTEQ, $expr, $b.expr); }
 239           |LT   b=additive_expression { $expr = tm.binary(BinaryOpType.LT,   $expr, $b.expr); }
 240           |GT   b=additive_expression { $expr = tm.binary(BinaryOpType.GT,   $expr, $b.expr); }
 241           )*
 242         ;
 243 
 244 equality_expression returns [Expr expr]
 245         : a=relational_expression { $expr = $a.expr; }
 246           (EQEQ b=relational_expression { $expr = tm.binary(BinaryOpType.EQEQ, $expr, $b.expr); }
 247           | NEQ b=relational_expression { $expr = tm.binary(BinaryOpType.NEQ,  $expr, $b.expr); }
 248           )*
 249         ;
 250         
 251 logical_and_expression returns [Expr expr]
 252         : a=equality_expression { $expr = $a.expr; }
 253           (AND b=equality_expression { $expr = tm.binary(BinaryOpType.AND, $expr, $b.expr); }
 254           )*
 255         ;
 256         
 257 logical_xor_expression returns [Expr expr]
 258         : a=logical_and_expression { $expr = $a.expr; }
 259           (XOR b=logical_and_expression { $expr = tm.binary(BinaryOpType.XOR, $expr, $b.expr); }
 260           )*
 261         ;
 262         
 263 logical_or_expression returns [Expr expr]
 264         : a=logical_xor_expression { $expr = $a.expr; }
 265           (OR b=logical_xor_expression { $expr = tm.binary(BinaryOpType.OR, $expr, $b.expr); }
 266           )*
 267         ;
 268         
 269 ternary_part
 270         : QUESTION expression COLON assignment_expression
 271         ;
 272 
 273 // TODO: handle ternary
 274 conditional_expression returns [Expr expr]
 275         : a=logical_or_expression ternary_part? { $expr = $a.expr; }
 276         ;
 277 
 278 assignment_expression returns [Expr expr]
 279         : a=unary_expression op=assignment_operator b=assignment_expression
 280               { $expr = tm.binary(BinaryOpType.forSymbol($op.text), $a.expr, $b.expr); }
 281         | c=conditional_expression
 282               { $expr = $c.expr; }
 283         ;
 284 
 285 assignment_operator
 286         : EQUAL
 287         | STAREQ
 288         | SLASHEQ
 289         | PLUSEQ
 290         | DASHEQ
 291         ;
 292 
 293 // TODO: handle expression lists?
 294 //expression returns [List<Expr> exprList = new ArrayList<Expr>()]
 295 //        : e=assignment_expression { $exprList.add($e.expr); }
 296 //          (COMMA e=assignment_expression { $exprList.add($e.expr); })*
 297 //        ;
 298 
 299 expression returns [Expr expr]
 300         : e=assignment_expression { $expr = $e.expr; }
 301         ;
 302 
 303 function_prototype returns [Function func]
 304         : t=type_specifier id=IDENTIFIER LEFT_PAREN p=parameter_declaration_list? RIGHT_PAREN
 305             {
 306                 Type type = Type.fromToken($t.text);
 307                 $func = symbols.declareFunction($id.text, type, (p != null) ? $p.paramList : null);
 308             }
 309         ;
 310         
 311 parameter_declaration returns [Param param]
 312         : t=type_specifier id=IDENTIFIER
 313             {
 314                 Type type = Type.fromToken($t.text);
 315                 $param = new Param($id.text, type);
 316             }
 317         ;
 318 
 319 parameter_declaration_list returns [List<Param> paramList = new ArrayList<Param>()]
 320         : p=parameter_declaration { $paramList.add($p.param); }
 321           (COMMA p=parameter_declaration { $paramList.add($p.param); } )*
 322         ;
 323         
 324 declaration_identifier_and_init returns [String name, Expr arrayInit, Expr init]
 325         : id=IDENTIFIER { $name = $id.text; }
 326           (LEFT_BRACKET ae=constant_expression { $arrayInit = $ae.expr; } RIGHT_BRACKET)?
 327           (EQUAL e=initializer { $init = $e.expr; })?
 328         ;
 329 
 330 single_declaration returns [VarDecl decl]
 331         : t=fully_specified_type d=declaration_identifier_and_init
 332           {
 333               int arraySize = -1;
 334               Expr ainit = $d.arrayInit;
 335               if (ainit != null) {
 336                   if (ainit instanceof LiteralExpr) {
 337                       Object val = ((LiteralExpr)ainit).getValue();
 338                       if (!(val instanceof Integer)) {
 339                           throw new RuntimeException("Array size must be an integer");
 340                       }
 341                       arraySize = ((Integer)val).intValue();
 342                   } else if (ainit instanceof VariableExpr) {
 343                       Variable var = ((VariableExpr)ainit).getVariable();
 344                       Object val = var.getConstValue();
 345                       if (!(val instanceof Integer) || var.getQualifier() != Qualifier.CONST) {
 346                           throw new RuntimeException("Array size must be a constant integer");
 347                       }
 348                       arraySize = ((Integer)val).intValue();
 349                   }
 350               }
 351 
 352               Object constValue = null;
 353               if ($t.qual == Qualifier.CONST) {
 354                   Expr cinit = $d.init;
 355                   if (cinit == null) {
 356                       throw new RuntimeException("Constant value must be initialized");
 357                   }
 358                   // TODO: for now, allow some basic expressions on the rhs
 359                   // of the constant declaration...
 360                   //if (!(cinit instanceof LiteralExpr)) {
 361                   //    throw new RuntimeException("Constant initializer must be a literal (for now)");
 362                   //}
 363                   Type ctype = cinit.getResultType();
 364                   if (ctype != $t.type) {
 365                       throw new RuntimeException("Constant type must match that of initializer");
 366                   }
 367                   if (cinit instanceof LiteralExpr) {
 368                       constValue = ((LiteralExpr)cinit).getValue();
 369                   } else {
 370                       // TODO: This is gross, but to support complex constant
 371                       // initializers (such as "const FOO = BAR / 42.0;") we
 372                       // will just save the full text of the rhs and hope that
 373                       // the backend does the right thing with it.  The real
 374                       // solution obviously would be to evaluate the expression
 375                       // now and reduce it to a single value.
 376                       constValue = $d.init.toString();
 377                   }
 378               }
 379 
 380               Variable var =
 381                   symbols.declareVariable($d.name,
 382                                           $t.type, $t.qual, $t.precision,
 383                                           arraySize, constValue);
 384               $decl = tm.varDecl(var, $d.init);
 385           }
 386         ;
 387         
 388 declaration returns [List<VarDecl> declList = new ArrayList<VarDecl>()]
 389         : s=single_declaration { $declList.add($s.decl); }
 390           (COMMA d=declaration_identifier_and_init
 391           {
 392               Variable base = $s.decl.getVariable();
 393               Variable var =
 394                   symbols.declareVariable($d.name,
 395                                           base.getType(),
 396                                           base.getQualifier(),
 397                                           base.getPrecision());
 398               $declList.add(tm.varDecl(var, $d.init));
 399           }
 400           )* SEMICOLON
 401         ;
 402         
 403 // From GLSL spec...
 404 // Grammar Note:  No 'enum', or 'typedef'. 
 405 
 406 fully_specified_type returns [Qualifier qual, Precision precision, Type type]
 407         : tq=type_qualifier tp=type_precision ts=type_specifier
 408             {
 409                 $qual = Qualifier.fromToken($tq.text);
 410                 $precision = Precision.fromToken($tp.text);
 411                 $type = Type.fromToken($ts.text);
 412             }
 413         | tq=type_qualifier ts=type_specifier
 414             {
 415                 $qual = Qualifier.fromToken($tq.text);
 416                 $type = Type.fromToken($ts.text);
 417             }
 418         | tp=type_precision ts=type_specifier
 419             {
 420                 $precision = Precision.fromToken($tp.text);
 421                 $type = Type.fromToken($ts.text);
 422             }
 423         | ts=type_specifier
 424             {
 425                 $type = Type.fromToken($ts.text);
 426             }
 427         ;
 428         
 429 type_qualifier
 430         : 'const'
 431         | 'param'
 432         ;
 433 
 434 type_precision
 435         : 'lowp'
 436         | 'mediump'
 437         | 'highp'
 438         ;
 439         
 440 type_specifier
 441         : type_specifier_nonarray array_brackets?
 442         ;
 443         
 444 array_brackets
 445         : LEFT_BRACKET constant_expression RIGHT_BRACKET
 446         ;
 447        
 448 type_specifier_nonarray
 449         : TYPE
 450         | VOID
 451         ;
 452         
 453 initializer returns [Expr expr]
 454         : e=assignment_expression { $expr = $e.expr; }
 455         ;
 456         
 457 declaration_statement returns [Stmt stmt]
 458         : d=declaration { $stmt = tm.declStmt($d.declList); }
 459         ;
 460         
 461 statement returns [Stmt stmt]
 462         : c=compound_statement { $stmt = $c.stmt; }
 463         | s=simple_statement   { $stmt = $s.stmt; }
 464         ;
 465 
 466 // From GLSL spec...
 467 // Grammar Note:  No labeled statements; 'goto' is not supported. 
 468 
 469 simple_statement returns [Stmt stmt]
 470         : d=declaration_statement { $stmt = $d.stmt; }
 471         | e=expression_statement  { $stmt = $e.stmt; }
 472         | s=selection_statement   { $stmt = $s.stmt; }
 473         | i=iteration_statement   { $stmt = $i.stmt; }
 474         | j=jump_statement        { $stmt = $j.stmt; }
 475         ;
 476         
 477 compound_statement returns [Stmt stmt]
 478 @init {
 479     List<Stmt> stmtList = new ArrayList<Stmt>();
 480 }
 481         : LEFT_BRACE (s=statement { stmtList.add($s.stmt); })* RIGHT_BRACE
 482           { $stmt = tm.compoundStmt(stmtList); }
 483         ;
 484         
 485 statement_no_new_scope returns [Stmt stmt]
 486         : c=compound_statement_no_new_scope { $stmt = $c.stmt; }
 487         | s=simple_statement                { $stmt = $s.stmt; }
 488         ;
 489         
 490 compound_statement_no_new_scope returns [Stmt stmt]
 491 @init {
 492     List<Stmt> stmtList = new ArrayList<Stmt>();
 493 }
 494         : LEFT_BRACE (s=statement { stmtList.add($s.stmt); })* RIGHT_BRACE
 495           { $stmt = tm.compoundStmt(stmtList); }
 496         ;
 497         
 498 expression_statement returns [Stmt stmt]
 499         : SEMICOLON              { $stmt = tm.exprStmt(null); }
 500         | e=expression SEMICOLON { $stmt = tm.exprStmt($e.expr); }
 501         ;
 502         
 503 constant_expression returns [Expr expr]
 504         : c=conditional_expression { $expr = $c.expr; }
 505         ;
 506 
 507 selection_statement returns [Stmt stmt]
 508         : IF LEFT_PAREN e=expression RIGHT_PAREN a=statement (ELSE b=statement)?
 509               { $stmt = tm.selectStmt($e.expr, $a.stmt, (b != null) ? $b.stmt : null); }
 510         ;
 511 
 512 // TODO: implement second half?
 513 condition returns [Expr expr]
 514         : e=expression {$expr = $e.expr; }
 515 //        | fully_specified_type IDENTIFIER EQUAL initializer
 516         ;
 517 
 518 iteration_statement returns [Stmt stmt]
 519         : WHILE LEFT_PAREN c=condition RIGHT_PAREN snns=statement_no_new_scope
 520               { $stmt = tm.whileStmt($c.expr, $snns.stmt); }
 521         | DO s=statement WHILE LEFT_PAREN e=expression RIGHT_PAREN SEMICOLON
 522               { $stmt = tm.doWhileStmt($s.stmt, $e.expr); }
 523         | u=unroll_modifier FOR LEFT_PAREN init=for_init_statement rem=for_rest_statement RIGHT_PAREN snns=statement_no_new_scope
 524               { $stmt = tm.forStmt($init.stmt, $rem.cond, $rem.expr, $snns.stmt, $u.max, $u.check); }
 525         | FOR LEFT_PAREN init=for_init_statement rem=for_rest_statement RIGHT_PAREN snns=statement_no_new_scope
 526               { $stmt = tm.forStmt($init.stmt, $rem.cond, $rem.expr, $snns.stmt, -1, -1); }
 527         ;
 528 
 529 unroll_modifier returns [int max, int check]
 530         : UNROLL LEFT_PAREN m=INTCONSTANT COMMA c=INTCONSTANT RIGHT_PAREN
 531               { $max = Integer.valueOf($m.text); $check = Integer.valueOf($c.text); }
 532         ;
 533 
 534 for_init_statement returns [Stmt stmt]
 535         : e=expression_statement  { $stmt = $e.stmt; }
 536         | d=declaration_statement { $stmt = $d.stmt; }
 537         ;
 538         
 539 for_rest_statement returns [Expr cond, Expr expr]
 540         : c=condition SEMICOLON e=expression? { $cond = $c.expr; if (e != null) $expr = $e.expr; }
 541         | SEMICOLON e=expression? { if (e != null) $expr = $e.expr; }
 542         ;
 543         
 544 jump_statement returns [Stmt stmt]
 545         : CONTINUE SEMICOLON            { $stmt = tm.continueStmt(); }
 546         | BREAK SEMICOLON               { $stmt = tm.breakStmt(); }
 547         | DISCARD SEMICOLON             { $stmt = tm.discardStmt(); }
 548         | RETURN SEMICOLON              { $stmt = tm.returnStmt(null); }
 549         | RETURN e=expression SEMICOLON { $stmt = tm.returnStmt($e.expr); }
 550         ;
 551         
 552 // From GLSL spec...
 553 // Grammar Note:  No 'goto'.  Gotos are not supported. 
 554 
 555 translation_unit returns [ProgramUnit prog]
 556 @init {
 557     List<ExtDecl> declList = new ArrayList<ExtDecl>();
 558 }
 559         : (e=external_declaration { declList.addAll($e.res); } )+
 560             { $prog = tm.programUnit(declList); }
 561         ;
 562         
 563 external_declaration returns [List<ExtDecl> res = new ArrayList<ExtDecl>()]
 564         : f=function_definition { $res.add($f.def); }
 565         | d=declaration         { $res.addAll($d.declList); }
 566         | g=glue_block          { $res.add($g.block); }
 567         ;
 568 
 569 // From GLSL spec...
 570 // Grammar Note:  No 'switch'.  Switch statements not supported. 
 571 
 572 function_definition returns [FuncDef def]
 573 @init {
 574         symbols.enterFrame();
 575 }
 576         : p=function_prototype s=compound_statement_no_new_scope { $def = tm.funcDef($p.func, $s.stmt); }
 577         ;
 578 finally {
 579         symbols.exitFrame();
 580 }
 581 
 582 glue_block returns [GlueBlock block]
 583         : g=GLUE_BLOCK { $block = tm.glueBlock($g.text.substring(2, $g.text.length()-2)); }
 584         ;
 585 
 586 TYPE
 587         : 'float2'
 588         | 'float3'
 589         | 'float4'
 590         | 'float'
 591         | 'int2'
 592         | 'int3'
 593         | 'int4'
 594         | 'int'
 595         | 'bool2'
 596         | 'bool3'
 597         | 'bool4'
 598         | 'bool'
 599         | 'sampler'
 600         | 'lsampler'
 601         | 'fsampler'
 602         ;
 603 
 604 BOOLCONSTANT
 605         : 'true'
 606         | 'false'
 607         ;
 608 
 609 RGBA_FIELDS
 610         : DOT RFIELD RFIELD RFIELD RFIELD
 611         | DOT RFIELD RFIELD RFIELD
 612         | DOT RFIELD RFIELD
 613         | DOT RFIELD
 614         ;
 615 
 616 fragment
 617 RFIELD   : 'r' | 'g' | 'b' | 'a' ;
 618 
 619 XYZW_FIELDS
 620         : DOT XFIELD XFIELD XFIELD XFIELD
 621         | DOT XFIELD XFIELD XFIELD
 622         | DOT XFIELD XFIELD
 623         | DOT XFIELD
 624         ;
 625 
 626 fragment
 627 XFIELD   : 'x' | 'y' | 'z' | 'w' ;
 628 
 629 IDENTIFIER
 630         : LETTER (LETTER|DIGIT)*
 631         ;
 632 
 633 fragment
 634 LETTER
 635         : '$'
 636         | 'A'..'Z'
 637         | 'a'..'z'
 638         | '_'
 639         ;
 640 
 641 INTCONSTANT : ('0' | '1'..'9' DIGIT*) ;
 642 
 643 FLOATCONSTANT
 644         : DIGIT+ '.' DIGIT*
 645         |  '.' DIGIT+
 646         ;
 647 
 648 fragment
 649 DIGIT   : '0'..'9' ;
 650 
 651 WS  :  (' '|'\r'|'\t'|'\u000C'|'\n') {$channel=HIDDEN;}
 652     ;
 653 
 654 COMMENT
 655     :   '/*' ( options {greedy=false;} : . )* '*/' {$channel=HIDDEN;}
 656     ;
 657 
 658 LINE_COMMENT
 659     : '//' ~('\n'|'\r')* '\r'? '\n' {$channel=HIDDEN;}
 660     ;
 661 
 662 GLUE_BLOCK
 663     : LEFT_FRENCH .* RIGHT_FRENCH
 664     ;