1/* 2 * Copyright (c) 2003 Sun Microsystems, Inc. All Rights Reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions are 6 * met: 7 * 8 * - Redistribution of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 11 * - Redistribution in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 15 * Neither the name of Sun Microsystems, Inc. or the names of 16 * contributors may be used to endorse or promote products derived from 17 * this software without specific prior written permission. 18 * 19 * This software is provided "AS IS," without a warranty of any kind. ALL 20 * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, 21 * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A 22 * PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN 23 * MIDROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE FOR 24 * ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR 25 * DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR 26 * ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR 27 * DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE 28 * DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY, 29 * ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, EVEN IF 30 * SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. 31 * 32 * You acknowledge that this software is not designed or intended for use 33 * in the design, construction, operation or maintenance of any nuclear 34 * facility. 35 * 36 * Sun gratefully acknowledges that this software was originally authored 37 * and developed by Kenneth Bradley Russell and Christopher John Kline. 38 */ 39 40header { 41 package com.sun.gluegen.cgram; 42 43 import java.io.*; 44 import java.util.*; 45 46 import antlr.CommonAST; 47 import com.sun.gluegen.cgram.types.*; 48} 49 50class HeaderParser extends GnuCTreeParser; 51options { 52 k = 1; 53} 54 55{ 56 /** Name assigned to a anonymous EnumType (e.g., "enum { ... }"). */ 57 public static final String ANONYMOUS_ENUM_NAME = "<anonymous>"; 58 59 /** Set the dictionary mapping typedef names to types for this 60 HeaderParser. Must be done before parsing. */ 61 public void setTypedefDictionary(TypeDictionary dict) { 62 this.typedefDictionary = dict; 63 } 64 65 /** Returns the typedef dictionary this HeaderParser uses. */ 66 public TypeDictionary getTypedefDictionary() { 67 return typedefDictionary; 68 } 69 70 /** Set the dictionary mapping struct names (i.e., the "foo" in 71 "struct foo { ... };") to types for this HeaderParser. Must be done 72 before parsing. */ 73 public void setStructDictionary(TypeDictionary dict) { 74 this.structDictionary = dict; 75 } 76 77 /** Returns the struct name dictionary this HeaderParser uses. */ 78 public TypeDictionary getStructDictionary() { 79 return structDictionary; 80 } 81 82 /** Get the canonicalization map, which is a regular HashMap 83 mapping Type to Type and which is used for looking up the unique 84 instances of e.g. pointer-to-structure types that have been typedefed 85 and therefore have names. */ 86 public Map getCanonMap() { 87 return canonMap; 88 } 89 90 /** Pre-define the list of EnumTypes for this HeaderParser. Must be 91 done before parsing. */ 92 public void setEnums(List/*<EnumType>*/ enumTypes) { 93 // FIXME: Need to take the input set of EnumTypes, extract all 94 // the enumerates from each EnumType, and fill in the enumHash 95 // so that each enumerate maps to the enumType to which it 96 // belongs. 97 throw new RuntimeException("setEnums is Unimplemented!"); 98 } 99 100 /** Returns the EnumTypes this HeaderParser processed. */ 101 public List/*<EnumType>*/ getEnums() { 102 return new ArrayList(enumHash.values()); 103 } 104 105 /** Clears the list of functions this HeaderParser has parsed. 106 Useful when reusing the same HeaderParser for more than one 107 header file. */ 108 public void clearParsedFunctions() { 109 functions.clear(); 110 } 111 112 /** Returns the list of FunctionSymbols this HeaderParser has parsed. */ 113 public List getParsedFunctions() { 114 return functions; 115 } 116 117 private CompoundType lookupInStructDictionary(String typeName, 118 CompoundTypeKind kind, 119 int cvAttrs) { 120 CompoundType t = (CompoundType) structDictionary.get(typeName); 121 if (t == null) { 122 t = new CompoundType(null, null, kind, cvAttrs); 123 t.setStructName(typeName); 124 structDictionary.put(typeName, t); 125 } 126 return t; 127 } 128 129 private Type lookupInTypedefDictionary(String typeName) { 130 Type t = typedefDictionary.get(typeName); 131 if (t == null) { 132 throw new RuntimeException("Undefined reference to typedef name " + typeName); 133 } 134 return t; 135 } 136 137 static class ParameterDeclaration { 138 private String id; 139 private Type type; 140 141 ParameterDeclaration(String id, Type type) { 142 this.id = id; 143 this.type = type; 144 } 145 String id() { return id; } 146 Type type() { return type; } 147 } 148 149 // A box for a Type. Allows type to be passed down to be modified by recursive rules. 150 static class TypeBox { 151 private Type origType; 152 private Type type; 153 private boolean isTypedef; 154 155 TypeBox(Type type) { 156 this(type, false); 157 } 158 159 TypeBox(Type type, boolean isTypedef) { 160 this.origType = type; 161 this.isTypedef = isTypedef; 162 } 163 164 Type type() { 165 if (type == null) { 166 return origType; 167 } 168 return type; 169 } 170 void setType(Type type) { 171 this.type = type; 172 } 173 void reset() { 174 type = null; 175 } 176 177 boolean isTypedef() { return isTypedef; } 178 179 // for easier debugging 180 public String toString() { 181 String tStr = "Type=NULL_REF"; 182 if (type == origType) { 183 tStr = "Type=ORIG_TYPE"; 184 } else if (type != null) { 185 tStr = "Type: name=\"" + type.getCVAttributesString() + " " + 186 type.getName() + "\"; signature=\"" + type + "\"; class " + 187 type.getClass().getName(); 188 } 189 String oStr = "OrigType=NULL_REF"; 190 if (origType != null) { 191 oStr = "OrigType: name=\"" + origType.getCVAttributesString() + " " + 192 origType.getName() + "\"; signature=\"" + origType + "\"; class " + 193 origType.getClass().getName(); 194 } 195 return "<["+tStr + "] [" + oStr + "] " + " isTypedef=" + isTypedef+">"; 196 } 197 } 198 199 private boolean doDeclaration; // Used to only process function typedefs 200 private String declId; 201 private List parameters; 202 private TypeDictionary typedefDictionary; 203 private TypeDictionary structDictionary; 204 private List/*<FunctionSymbol>*/ functions = new ArrayList(); 205 // hash from name of an enumerated value to the EnumType to which it belongs 206 private HashMap/*<String,EnumType>*/ enumHash = new HashMap(); 207 208 // Storage class specifiers 209 private static final int AUTO = 1 << 0; 210 private static final int REGISTER = 1 << 1; 211 private static final int TYPEDEF = 1 << 2; 212 // Function storage class specifiers 213 private static final int EXTERN = 1 << 3; 214 private static final int STATIC = 1 << 4; 215 private static final int INLINE = 1 << 5; 216 // Type qualifiers 217 private static final int CONST = 1 << 6; 218 private static final int VOLATILE = 1 << 7; 219 private static final int SIGNED = 1 << 8; 220 private static final int UNSIGNED = 1 << 9; 221 222 private void initDeclaration() { 223 doDeclaration = false; 224 declId = null; 225 } 226 227 private void doDeclaration() { 228 doDeclaration = true; 229 } 230 231 private void processDeclaration(Type returnType) { 232 if (doDeclaration) { 233 FunctionSymbol sym = new FunctionSymbol(declId, new FunctionType(null, null, returnType, 0)); 234 if (parameters != null) { // handle funcs w/ empty parameter lists (e.g., "foo()") 235 for (Iterator iter = parameters.iterator(); iter.hasNext(); ) { 236 ParameterDeclaration pd = (ParameterDeclaration) iter.next(); 237 sym.addArgument(pd.type(), pd.id()); 238 } 239 } 240 functions.add(sym); 241 } 242 } 243 244 private int attrs2CVAttrs(int attrs) { 245 int cvAttrs = 0; 246 if ((attrs & CONST) != 0) { 247 cvAttrs |= CVAttributes.CONST; 248 } 249 if ((attrs & VOLATILE) != 0) { 250 cvAttrs |= CVAttributes.VOLATILE; 251 } 252 return cvAttrs; 253 } 254 255 /** Helper routine which handles creating a pointer or array type 256 for [] expressions */ 257 private void handleArrayExpr(TypeBox tb, AST t) { 258 if (t != null) { 259 try { 260 // FIXME: this doesn't take into account struct alignment, which may be necessary 261 // See also FIXMEs in ArrayType.java 262 int len = parseIntConstExpr(t); 263 tb.setType(canonicalize(new ArrayType(tb.type(), SizeThunk.mul(SizeThunk.constant(len), tb.type().getSize()), len, 0))); 264 return; 265 } catch (RecognitionException e) { 266 // Fall through 267 } 268 } 269 tb.setType(canonicalize(new PointerType(SizeThunk.POINTER, 270 tb.type(), 271 0))); 272 } 273 274 private int parseIntConstExpr(AST t) throws RecognitionException { 275 return intConstExpr(t); 276 } 277 278 /** Utility function: creates a new EnumType with the given name, or 279 returns an existing one if it has already been created. */ 280 private EnumType getEnumType(String enumTypeName) { 281 EnumType enumType = null; 282 Iterator it = enumHash.values().iterator(); 283 while (it.hasNext()) { 284 EnumType potentialMatch = (EnumType)it.next(); 285 if (potentialMatch.getName().equals(enumTypeName)) { 286 enumType = potentialMatch; 287 break; 288 } 289 } 290 291 if (enumType == null) { 292 // This isn't quite correct. In theory the enum should expand to 293 // the size of the largest element, so if there were a long long 294 // entry the enum should expand to e.g. int64. However, using 295 // "long" here (which is what used to be the case) was 296 // definitely incorrect and caused problems. 297 enumType = new EnumType(enumTypeName, SizeThunk.INT); 298 } 299 300 return enumType; 301 } 302 303 // Map used to canonicalize types. For example, we may typedef 304 // struct foo { ... } *pfoo; subsequent references to struct foo* should 305 // point to the same PointerType object that had its name set to "pfoo". 306 private Map canonMap = new HashMap(); 307 private Type canonicalize(Type t) { 308 Type res = (Type) canonMap.get(t); 309 if (res != null) { 310 return res; 311 } 312 canonMap.put(t, t); 313 return t; 314 } 315} 316 317declarator[TypeBox tb] returns [String s] { 318 initDeclaration(); 319 s = null; 320 List params = null; 321 String funcPointerName = null; 322 TypeBox dummyTypeBox = null; 323} 324 : #( NDeclarator 325 ( pointerGroup[tb] )? 326 327 ( id:ID { s = id.getText(); } 328 | LPAREN funcPointerName = declarator[dummyTypeBox] RPAREN 329 ) 330 331 ( #( NParameterTypeList 332 ( 333 params = parameterTypeList 334 | (idList)? 335 ) 336 RPAREN 337 ) { 338 if (id != null) { 339 declId = id.getText(); 340 parameters = params; // FIXME: Ken, why are we setting this class member here? 341 doDeclaration(); 342 } else if ( funcPointerName != null ) { 343 /* TypeBox becomes function pointer in this case */ 344 FunctionType ft = new FunctionType(null, null, tb.type(), 0); 345 if (params == null) { 346 // If the function pointer has no declared parameters, it's a 347 // void function. I'm not sure if the parameter name is 348 // ever referenced anywhere when the type is VoidType, so 349 // just in case I'll set it to a comment string so it will 350 // still compile if written out to code anywhere. 351 ft.addArgument(new VoidType(0), "/*unnamed-void*/"); 352 } else { 353 for (Iterator iter = params.iterator(); iter.hasNext(); ) { 354 ParameterDeclaration pd = (ParameterDeclaration) iter.next(); 355 ft.addArgument(pd.type(), pd.id()); 356 } 357 } 358 tb.setType(canonicalize(new PointerType(SizeThunk.POINTER, 359 ft, 360 0))); 361 s = funcPointerName; 362 } 363 } 364 | LBRACKET ( e:expr )? RBRACKET { handleArrayExpr(tb, e); } 365 )* 366 ) 367 ; 368 369typelessDeclaration { 370 TypeBox tb = null; 371} 372 : #(NTypeMissing initDeclList[tb] SEMI) 373 ; 374 375declaration { 376 TypeBox tb = null; 377} 378 : #( NDeclaration 379 tb = declSpecifiers 380 ( 381 initDeclList[tb] 382 )? 383 ( SEMI )+ 384 ) { processDeclaration(tb.type()); } 385 ; 386 387parameterTypeList returns [List l] { l = new ArrayList(); ParameterDeclaration decl = null; } 388 : ( decl = parameterDeclaration { if (decl != null) l.add(decl); } ( COMMA | SEMI )? )+ ( VARARGS )? 389 ; 390 391parameterDeclaration returns [ParameterDeclaration pd] { 392 Type t = null; 393 String decl = null; 394 pd = null; 395 TypeBox tb = null; 396} 397 : #( NParameterDeclaration 398 tb = declSpecifiers 399 (decl = declarator[tb] | nonemptyAbstractDeclarator[tb])? 400 ) { pd = new ParameterDeclaration(decl, tb.type()); } 401 ; 402 403functionDef { 404 TypeBox tb = null; 405} 406 : #( NFunctionDef 407 ( functionDeclSpecifiers)? 408 declarator[tb] 409 (declaration | VARARGS)* 410 compoundStatement 411 ) 412 ; 413 414declSpecifiers returns [TypeBox tb] { 415 tb = null; 416 Type t = null; 417 int x = 0; 418 int y = 0; 419} 420 : ( y = storageClassSpecifier { x |= y; } 421 | y = typeQualifier { x |= y; } 422 | t = typeSpecifier[x] 423 )+ 424{ 425 if (t == null && 426 (x & (SIGNED | UNSIGNED)) != 0) { 427 t = new IntType("int", SizeThunk.INT, ((x & UNSIGNED) != 0), attrs2CVAttrs(x)); 428 } 429 tb = new TypeBox(t, ((x & TYPEDEF) != 0)); 430} 431 ; 432 433storageClassSpecifier returns [int x] { x = 0; } 434 : "auto" { x |= AUTO; } 435 | "register" { x |= REGISTER; } 436 | "typedef" { x |= TYPEDEF; } 437 | x = functionStorageClassSpecifier 438 ; 439 440 441functionStorageClassSpecifier returns [int x] { x = 0; } 442 : "extern" { x |= EXTERN; } 443 | "static" { x |= STATIC; } 444 | "inline" { x |= INLINE; } 445 ; 446 447 448typeQualifier returns [int x] { x = 0; } 449 : "const" { x |= CONST; } 450 | "volatile" { x |= VOLATILE; } 451 | "signed" { x |= SIGNED; } 452 | "unsigned" { x |= UNSIGNED; } 453 ; 454 455typeSpecifier[int attributes] returns [Type t] { 456 t = null; 457 int cvAttrs = attrs2CVAttrs(attributes); 458 boolean unsigned = ((attributes & UNSIGNED) != 0); 459} 460 : "void" { t = new VoidType(cvAttrs); } 461 | "char" { t = new IntType("char" , SizeThunk.CHAR, unsigned, cvAttrs); } 462 | "short" { t = new IntType("short", SizeThunk.SHORT, unsigned, cvAttrs); } 463 | "int" { t = new IntType("int" , SizeThunk.INT, unsigned, cvAttrs); } 464 | "long" { t = new IntType("long" , SizeThunk.LONG, unsigned, cvAttrs); } 465 | "__int32" { t = new IntType("__int32", SizeThunk.INT, unsigned, cvAttrs); } 466 | "__int64" { t = new IntType("__int64", SizeThunk.INT64, unsigned, cvAttrs); } 467 | "float" { t = new FloatType("float", SizeThunk.FLOAT, cvAttrs); } 468 | "double" { t = new DoubleType("double", SizeThunk.DOUBLE, cvAttrs); } 469 | t = structSpecifier[cvAttrs] ( attributeDecl )* 470 | t = unionSpecifier [cvAttrs] ( attributeDecl )* 471 | t = enumSpecifier [cvAttrs] 472 | t = typedefName [cvAttrs] 473 | #("typeof" LPAREN 474 ( (typeName )=> typeName 475 | expr 476 ) 477 RPAREN 478 ) 479 | "__complex" 480 ; 481 482typedefName[int cvAttrs] returns [Type t] { t = null; } 483 : #(NTypedefName id : ID) 484 { 485 t = canonicalize(lookupInTypedefDictionary(id.getText()).getCVVariant(cvAttrs)); 486 } 487 ; 488 489structSpecifier[int cvAttrs] returns [Type t] { t = null; } 490 : #( "struct" t = structOrUnionBody[CompoundTypeKind.STRUCT, cvAttrs] ) 491 ; 492 493unionSpecifier[int cvAttrs] returns [Type t] { t = null; } 494 : #( "union" t = structOrUnionBody[CompoundTypeKind.UNION, cvAttrs] ) 495 ; 496 497structOrUnionBody[CompoundTypeKind kind, int cvAttrs] returns [CompoundType t] { 498 t = null; 499} 500 : ( (ID LCURLY) => id:ID LCURLY { 501 t = (CompoundType) canonicalize(lookupInStructDictionary(id.getText(), kind, cvAttrs)); 502 } ( structDeclarationList[t] )? 503 RCURLY { t.setBodyParsed(); } 504 | LCURLY { t = new CompoundType(null, null, kind, cvAttrs); } 505 ( structDeclarationList[t] )? 506 RCURLY { t.setBodyParsed(); } 507 | id2:ID { t = (CompoundType) canonicalize(lookupInStructDictionary(id2.getText(), kind, cvAttrs)); } 508 ) 509 ; 510 511structDeclarationList[CompoundType t] 512 : ( structDeclaration[t] )+ 513 ; 514 515structDeclaration[CompoundType containingType] { 516 Type t = null; 517 boolean addedAny = false; 518} 519 : t = specifierQualifierList addedAny = structDeclaratorList[containingType, t] { 520 if (!addedAny) { 521 if (t != null) { 522 CompoundType ct = t.asCompound(); 523 if (ct.isUnion()) { 524 // Anonymous union 525 containingType.addField(new Field(null, t, null)); 526 } 527 } 528 } 529 } 530 ; 531 532specifierQualifierList returns [Type t] { 533 t = null; int x = 0; int y = 0; 534} 535 : ( 536 t = typeSpecifier[x] 537 | y = typeQualifier { x |= y; } 538 )+ { 539 if (t == null && 540 (x & (SIGNED | UNSIGNED)) != 0) { 541 t = new IntType("int", SizeThunk.INT, ((x & UNSIGNED) != 0), attrs2CVAttrs(x)); 542 } 543} 544 ; 545 546structDeclaratorList[CompoundType containingType, Type t] returns [boolean addedAny] { 547 addedAny = false; 548 boolean y = false; 549} 550 : ( y = structDeclarator[containingType, t] { addedAny = y; })+ 551 ; 552 553structDeclarator[CompoundType containingType, Type t] returns [boolean addedAny] { 554 addedAny = false; 555 String s = null; 556 TypeBox tb = new TypeBox(t); 557} 558 : 559 #( NStructDeclarator 560 ( s = declarator[tb] { containingType.addField(new Field(s, tb.type(), null)); addedAny = true; } )? 561 ( COLON expr { /* FIXME: bit types not handled yet */ } ) ? 562 ( attributeDecl )* 563 ) 564 ; 565 566// FIXME: this will not correctly set the name of the enumeration when 567// encountering a declaration like this: 568// 569// typedef enum { } enumName; 570// 571// In this case calling getName() on the EnumType return value will 572// incorrectly return HeaderParser.ANONYMOUS_ENUM_NAME instead of 573// "enumName" 574// 575// I haven't implemented it yet because I'm not sure how to get the 576// "enumName" *before* executing the enumList rule. 577enumSpecifier [int cvAttrs] returns [Type t] { 578 t = null; 579} 580 : #( "enum" 581 ( ( ID LCURLY )=> i:ID LCURLY enumList[(EnumType)(t = getEnumType(i.getText()))] RCURLY 582 | LCURLY enumList[(EnumType)(t = getEnumType(ANONYMOUS_ENUM_NAME))] RCURLY 583 | ID { t = getEnumType(i.getText()); } 584 ) 585 ) 586 ; 587 588enumList[EnumType enumeration] { 589 long defaultEnumerantValue = 0; 590} 591 : ( defaultEnumerantValue = enumerator[enumeration, defaultEnumerantValue] )+ 592 ; 593 594enumerator[EnumType enumeration, long defaultValue] returns [long newDefaultValue] { 595 newDefaultValue = defaultValue; 596} 597 : eName:ID ( ASSIGN eVal:expr )? { 598 long value = 0; 599 if (eVal != null) { 600 String vTxt = eVal.getAllChildrenText(); 601 if (enumHash.containsKey(vTxt)) { 602 EnumType oldEnumType = (EnumType) enumHash.get(vTxt); 603 value = oldEnumType.getEnumValue(vTxt); 604 } else { 605 try { 606 value = Long.decode(vTxt).longValue(); 607 } catch (NumberFormatException e) { 608 System.err.println("NumberFormatException: ID[" + eName.getText() + "], VALUE=[" + vTxt + "]"); 609 throw e; 610 } 611 } 612 } else { 613 value = defaultValue; 614 } 615 616 newDefaultValue = value+1; 617 String eTxt = eName.getText(); 618 if (enumHash.containsKey(eTxt)) { 619 EnumType oldEnumType = (EnumType) enumHash.get(eTxt); 620 long oldValue = oldEnumType.getEnumValue(eTxt); 621 System.err.println("WARNING: redefinition of enumerated value '" + eTxt + "';" + 622 " existing definition is in enumeration '" + oldEnumType.getName() + 623 "' with value " + oldValue + " and new definition is in enumeration '" + 624 enumeration.getName() + "' with value " + value); 625 // remove old definition 626 oldEnumType.removeEnumerate(eTxt); 627 } 628 // insert new definition 629 enumeration.addEnum(eTxt, value); 630 enumHash.put(eTxt, enumeration); 631 //System.err.println("ENUM [" + enumeration.getName() + "]: " + eTxt + " = " + enumeration.getEnumValue(eTxt) + 632 // " (new default = " + newDefaultValue + ")"); 633 } 634 ; 635 636initDeclList[TypeBox tb] 637 : ( initDecl[tb] )+ 638 ; 639 640initDecl[TypeBox tb] { 641 String declName = null; 642} 643 : #( NInitDecl 644 declName = declarator[tb] { 645 //System.err.println("GOT declName: " + declName + " TB=" + tb); 646 } 647 ( attributeDecl )* 648 ( ASSIGN initializer 649 | COLON expr 650 )? 651 ) 652{ 653 if ((declName != null) && (tb != null) && tb.isTypedef()) { 654 Type t = tb.type(); 655 //System.err.println("Adding typedef mapping: [" + declName + "] -> [" + t + "]"); 656 if (!t.hasTypedefName()) { 657 t.setName(declName); 658 } 659 t = canonicalize(t); 660 typedefDictionary.put(declName, t); 661 // Clear out PointerGroup effects in case another typedef variant follows 662 tb.reset(); 663 } 664} 665 ; 666 667pointerGroup[TypeBox tb] { int x = 0; int y = 0; } 668 : #( NPointerGroup ( STAR { x = 0; y = 0; } ( y = typeQualifier { x |= y; } )* 669 { 670 //System.err.println("IN PTR GROUP: TB=" + tb); 671 if (tb != null) { 672 tb.setType(canonicalize(new PointerType(SizeThunk.POINTER, 673 tb.type(), 674 attrs2CVAttrs(x)))); 675 } 676 } 677 )+ ) 678 ; 679 680 681functionDeclSpecifiers 682 : 683 ( functionStorageClassSpecifier 684 | typeQualifier 685 | typeSpecifier[0] 686 )+ 687 ; 688 689typeName { 690 TypeBox tb = null; 691} 692 : specifierQualifierList (nonemptyAbstractDeclarator[tb])? 693 ; 694 695 696/* FIXME: the handling of types in this rule has not been well thought 697 out and is known to be incomplete. Currently it is only used to handle 698 pointerGroups for unnamed parameters. */ 699nonemptyAbstractDeclarator[TypeBox tb] 700 : #( NNonemptyAbstractDeclarator 701 ( pointerGroup[tb] 702 ( (LPAREN 703 ( nonemptyAbstractDeclarator[tb] 704 | parameterTypeList 705 )? 706 RPAREN) 707 | (LBRACKET (e1:expr)? RBRACKET) { handleArrayExpr(tb, e1); } 708 )* 709 710 | ( (LPAREN 711 ( nonemptyAbstractDeclarator[tb] 712 | parameterTypeList 713 )? 714 RPAREN) 715 | (LBRACKET (e2:expr)? RBRACKET) { handleArrayExpr(tb, e2); } 716 )+ 717 ) 718 ) 719 ; 720 721/* Helper routine for parsing expressions which evaluate to integer 722 constants. Can be made more complicated as necessary. */ 723intConstExpr returns [int i] { i = -1; } 724 : n:Number { return Integer.parseInt(n.getText()); } 725 ; 726