|
|
1.1 ! root 1: /* YACC parser for C syntax. ! 2: Copyright (C) 1987 Free Software Foundation, Inc. ! 3: ! 4: This file is part of GNU CC. ! 5: ! 6: GNU CC is distributed in the hope that it will be useful, ! 7: but WITHOUT ANY WARRANTY. No author or distributor ! 8: accepts responsibility to anyone for the consequences of using it ! 9: or for whether it serves any particular purpose or works at all, ! 10: unless he says so in writing. Refer to the GNU CC General Public ! 11: License for full details. ! 12: ! 13: Everyone is granted permission to copy, modify and redistribute ! 14: GNU CC, but only under the conditions described in the ! 15: GNU CC General Public License. A copy of this license is ! 16: supposed to have been given to you along with GNU CC so you ! 17: can know your rights and responsibilities. It should be in a ! 18: file named COPYING. Among other things, the copyright notice ! 19: and this notice must be preserved on all copies. */ ! 20: ! 21: ! 22: /* To whomever it may concern: I have heard that such a thing was once ! 23: written by AT&T, but I have never seen it. */ ! 24: ! 25: %{ ! 26: #include "config.h" ! 27: #include "tree.h" ! 28: #include "parse.h" ! 29: #include "c-tree.h" ! 30: %} ! 31: ! 32: %start program ! 33: ! 34: %union {long itype; tree ttype; enum tree_code code} ! 35: ! 36: /* all identifiers that are not reserved words ! 37: and are not declared typedefs in the current block */ ! 38: %token IDENTIFIER ! 39: /* all identifiers that are declared typedefs in the current block. ! 40: In some contexts, they are treated just like IDENTIFIER, ! 41: but they can also serve as typespecs in declarations. */ ! 42: %token TYPENAME ! 43: ! 44: /* reserved words that specify storage class. ! 45: yylval contains an IDENTIFER_NODE which indicates which one. */ ! 46: %token SCSPEC ! 47: ! 48: /* reserved words that specify type. ! 49: yylval contains an IDENTIFER_NODE which indicates which one. */ ! 50: %token TYPESPEC ! 51: ! 52: /* reserved words that modify type: "const" or "volatile". ! 53: yylval contains an IDENTIFER_NODE which indicates which one. */ ! 54: %token TYPEMOD ! 55: ! 56: /* character or numeric constants. ! 57: yylval is the node for the constant. */ ! 58: %token CONSTANT ! 59: ! 60: /* String constants in raw form. ! 61: yylval is a STRING_CST node. */ ! 62: %token STRING ! 63: ! 64: /* "...", used for functions with variable arglists. */ ! 65: %token ELLIPSIS ! 66: ! 67: /* the reserved words */ ! 68: %token SIZEOF ENUM STRUCT UNION IF ELSE WHILE DO FOR SWITCH CASE DEFAULT ! 69: %token BREAK CONTINUE RETURN GOTO ASM ! 70: ! 71: /* Define the operator tokens and their precedences. ! 72: The value is an integer because, if used, it is the tree code ! 73: to use in the expression made from the operator. */ ! 74: ! 75: %right <code> ASSIGN '=' ! 76: %right <code> '?' ':' ! 77: %left <code> OROR ! 78: %left <code> ANDAND ! 79: %left <code> '|' ! 80: %left <code> '^' ! 81: %left <code> '&' ! 82: %left <code> EQCOMPARE ! 83: %left <code> ARITHCOMPARE ! 84: %left <code> LSHIFT RSHIFT ! 85: %left <code> '+' '-' ! 86: %left <code> '*' '/' '%' ! 87: %right <code> UNARY PLUSPLUS MINUSMINUS ! 88: %left HYPERUNARY ! 89: %left <code> POINTSAT '.' ! 90: ! 91: %type <code> unop ! 92: ! 93: %type <ttype> identifier IDENTIFIER TYPENAME CONSTANT expr nonnull_exprlist exprlist ! 94: %type <ttype> expr_no_commas primary string STRING ! 95: %type <ttype> typed_declspecs scspecs typespecs typespec SCSPEC TYPESPEC TYPEMOD ! 96: %type <ttype> initdecls notype_initdecls initdcl notype_initdcl ! 97: %type <ttype> init initlist ! 98: ! 99: %type <ttype> declarator ! 100: %type <ttype> notype_declarator after_type_declarator ! 101: ! 102: %type <ttype> structsp component_decl_list component_decl components component_declarator ! 103: %type <ttype> enumlist enumerator ! 104: %type <ttype> typename absdcl absdcl1 typemods ! 105: %type <ttype> stmts ! 106: %type <ttype> pushlevel compstmt stmt xexpr parmlist parms parm identifiers ! 107: ! 108: %{ ! 109: /* the declaration found for the last IDENTIFIER token read in. ! 110: yylex must look this up to detect typedefs, which get token type TYPENAME, ! 111: so it is left around in case the identifier is not a typedef but is ! 112: used in a context which makes it a reference to a variable. */ ! 113: static tree lastiddecl; ! 114: ! 115: tree current_function_decl, current_switch_stmt, current_block; ! 116: tree current_continue_label, current_break_label; ! 117: tree continue_label_stack, break_label_stack; ! 118: ! 119: static void pushbreak(), popbreak(); ! 120: static tree finish_compound_stmt(); ! 121: static tree make_pointer_declarator (); ! 122: static tree combine_strings (); ! 123: ! 124: /* list of types and structure classes of the current declaration */ ! 125: tree current_declspecs; ! 126: ! 127: char *input_filename; /* file being read */ ! 128: %} ! 129: ! 130: %% ! 131: program: ! 132: extdefs ! 133: ; ! 134: ! 135: /* the reason for the strange actions in this rule ! 136: is so that notype_initdecls when reached via datadef ! 137: can find a valid list of type and sc specs in $0. */ ! 138: ! 139: extdefs: ! 140: {$<ttype>$ = NULL_TREE} extdef ! 141: | extdefs {$<ttype>$ = NULL_TREE} extdef ! 142: ; ! 143: ! 144: extdef: ! 145: fndef ! 146: | datadef ! 147: | ASM '(' STRING ')' ';' ! 148: { assemble_asm ($3); } ! 149: ; ! 150: ! 151: datadef: ! 152: setspecs notype_initdecls ';' ! 153: | scspecs setspecs notype_initdecls ';' ! 154: {} ! 155: | typed_declspecs setspecs initdecls ';' ! 156: {} ! 157: | scspecs ';' ! 158: { yyerror ("empty declaration"); } ! 159: | typed_declspecs ';' ! 160: { shadow_tag ($1); } ! 161: | error ';' ! 162: | error '}' ! 163: | ';' ! 164: ; ! 165: ! 166: fndef: ! 167: typed_declspecs setspecs declarator ! 168: { if (! start_function ($1, $3)) ! 169: YYFAIL; } ! 170: xdecls ! 171: { store_parm_decls (); } ! 172: compstmt ! 173: { finish_function (input_filename, @7.first_line, $7); } ! 174: | typed_declspecs setspecs declarator error ! 175: { } ! 176: | scspecs setspecs notype_declarator ! 177: { if (! start_function ($1, $3)) ! 178: YYFAIL; } ! 179: xdecls ! 180: { store_parm_decls (); } ! 181: compstmt ! 182: { finish_function (input_filename, @7.first_line, $7); } ! 183: | scspecs setspecs notype_declarator error ! 184: { } ! 185: | setspecs notype_declarator ! 186: { if (! start_function (0, $2)) ! 187: YYFAIL; } ! 188: xdecls ! 189: { store_parm_decls (); } ! 190: compstmt ! 191: { finish_function (input_filename, @6.first_line, $6); } ! 192: | setspecs notype_declarator error ! 193: ; ! 194: ! 195: identifier: ! 196: IDENTIFIER ! 197: | TYPENAME ! 198: ; ! 199: ! 200: unop: '&' ! 201: { $$ = ADDR_EXPR; } ! 202: | '-' ! 203: { $$ = NEGATE_EXPR; } ! 204: | '+' ! 205: { $$ = CONVERT_EXPR; } ! 206: | PLUSPLUS ! 207: { $$ = PREINCREMENT_EXPR; } ! 208: | MINUSMINUS ! 209: { $$ = PREDECREMENT_EXPR; } ! 210: | '~' ! 211: { $$ = BIT_NOT_EXPR; } ! 212: | '!' ! 213: { $$ = TRUTH_NOT_EXPR; } ! 214: ; ! 215: ! 216: expr: nonnull_exprlist ! 217: { $$ = build_compound_expr($1); } ! 218: ; ! 219: ! 220: exprlist: ! 221: /* empty */ ! 222: { $$ = NULL_TREE; } ! 223: | nonnull_exprlist ! 224: ; ! 225: ! 226: nonnull_exprlist: ! 227: expr_no_commas ! 228: { $$ = build_tree_list (NULL_TREE, $1); } ! 229: | nonnull_exprlist ',' expr_no_commas ! 230: { chainon ($1, build_tree_list (NULL_TREE, $3)); } ! 231: ; ! 232: ! 233: expr_no_commas: ! 234: primary ! 235: | '*' expr_no_commas %prec UNARY ! 236: { $$ = build_indirect_ref ($2); } ! 237: | unop expr_no_commas %prec UNARY ! 238: { $$ = build_unary_op ($1, $2, 0); } ! 239: | '(' typename ')' expr_no_commas %prec UNARY ! 240: { $$ = build_c_cast (groktypename($2), $4); } ! 241: | SIZEOF expr_no_commas %prec UNARY ! 242: { $$ = c_sizeof (TREE_TYPE ($2)); } ! 243: | SIZEOF '(' typename ')' %prec HYPERUNARY ! 244: { $$ = c_sizeof (groktypename($3)); } ! 245: | expr_no_commas '+' expr_no_commas ! 246: { $$ = build_binary_op ($2, $1, $3); } ! 247: | expr_no_commas '-' expr_no_commas ! 248: { $$ = build_binary_op ($2, $1, $3); } ! 249: | expr_no_commas '*' expr_no_commas ! 250: { $$ = build_binary_op ($2, $1, $3); } ! 251: | expr_no_commas '/' expr_no_commas ! 252: { $$ = build_binary_op ($2, $1, $3); } ! 253: | expr_no_commas '%' expr_no_commas ! 254: { $$ = build_binary_op ($2, $1, $3); } ! 255: | expr_no_commas LSHIFT expr_no_commas ! 256: { $$ = build_binary_op ($2, $1, $3); } ! 257: | expr_no_commas RSHIFT expr_no_commas ! 258: { $$ = build_binary_op ($2, $1, $3); } ! 259: | expr_no_commas ARITHCOMPARE expr_no_commas ! 260: { $$ = build_binary_op ($2, $1, $3); } ! 261: | expr_no_commas EQCOMPARE expr_no_commas ! 262: { $$ = build_binary_op ($2, $1, $3); } ! 263: | expr_no_commas '&' expr_no_commas ! 264: { $$ = build_binary_op ($2, $1, $3); } ! 265: | expr_no_commas '|' expr_no_commas ! 266: { $$ = build_binary_op ($2, $1, $3); } ! 267: | expr_no_commas '^' expr_no_commas ! 268: { $$ = build_binary_op ($2, $1, $3); } ! 269: | expr_no_commas ANDAND expr_no_commas ! 270: { $$ = build_binary_op (TRUTH_ANDIF_EXPR, $1, $3); } ! 271: | expr_no_commas OROR expr_no_commas ! 272: { $$ = build_binary_op (TRUTH_ORIF_EXPR, $1, $3); } ! 273: | expr_no_commas '?' expr ':' expr_no_commas ! 274: { $$ = build_conditional_expr($1, $3, $5); } ! 275: | expr_no_commas '=' expr_no_commas ! 276: { $$ = build_modify_expr($1, $3); } ! 277: | expr_no_commas ASSIGN expr_no_commas ! 278: { register tree tem ! 279: = duplicate_reference ($1); ! 280: $$ = build_modify_expr(tem, build_binary_op ($2, tem, $3)); } ! 281: ; ! 282: ! 283: primary: ! 284: IDENTIFIER ! 285: { $$ = lastiddecl; ! 286: if (!$$) ! 287: { ! 288: if (yychar == YYEMPTY) ! 289: yychar = YYLEX; ! 290: if (yychar == '(') ! 291: $$ = implicitly_declare($1); ! 292: else ! 293: { ! 294: yyerror("variable %s used but not declared", ! 295: IDENTIFIER_POINTER ($1)); ! 296: $$ = error_mark_node; ! 297: } ! 298: } ! 299: if (TREE_CODE ($$) == CONST_DECL) ! 300: $$ = DECL_INITIAL ($$); ! 301: } ! 302: | CONSTANT ! 303: | string ! 304: { $$ = combine_strings ($1); } ! 305: | '(' expr ')' ! 306: { $$ = $2; } ! 307: | '(' error ')' ! 308: { $$ = error_mark_node; } ! 309: | primary '(' exprlist ')' %prec '.' ! 310: { $$ = build_function_call ($1, $3); } ! 311: | primary '[' expr ']' %prec '.' ! 312: { $$ = build_array_ref ($1, $3); } ! 313: | primary '.' identifier ! 314: { $$ = build_component_ref($1, $3); } ! 315: | primary POINTSAT identifier ! 316: { $$ = build_component_ref(build_indirect_ref ($1), $3); } ! 317: | primary PLUSPLUS ! 318: { $$ = build_unary_op (POSTINCREMENT_EXPR, $1, 0); } ! 319: | primary MINUSMINUS ! 320: { $$ = build_unary_op (POSTDECREMENT_EXPR, $1, 0); } ! 321: ; ! 322: ! 323: /* Produces a STRING_CST with perhaps more STRING_CSTs chained onto it. */ ! 324: string: ! 325: STRING ! 326: | string STRING ! 327: { $$ = chainon ($1, $2); } ! 328: ; ! 329: ! 330: xdecls: ! 331: /* empty */ ! 332: | decls ! 333: ; ! 334: ! 335: decls: ! 336: decl ! 337: | errstmt ! 338: | decls decl ! 339: | decl errstmt ! 340: ; ! 341: ! 342: /* records the type and storage class specs to use for processing ! 343: the declarators that follow */ ! 344: setspecs: /* empty */ ! 345: { current_declspecs = $<ttype>0; } ! 346: ; ! 347: ! 348: decl: ! 349: typed_declspecs setspecs initdecls ';' ! 350: {} ! 351: | scspecs setspecs notype_initdecls ';' ! 352: {} ! 353: | typed_declspecs ';' ! 354: { shadow_tag ($1); } ! 355: | scspecs ';' ! 356: { warning ("empty declaration"); } ! 357: ; ! 358: ! 359: /* declspecs which contain at least one type specifier. ! 360: A typedef'd name following these is taken as a name to be declared. */ ! 361: typed_declspecs: ! 362: typespec ! 363: { $$ = build_tree_list (NULL_TREE, $1); } ! 364: | scspecs typespec ! 365: { $$ = tree_cons (NULL_TREE, $2, $1); } ! 366: | typed_declspecs TYPESPEC ! 367: { $$ = tree_cons (NULL_TREE, $2, $1); } ! 368: | typed_declspecs TYPEMOD ! 369: { $$ = tree_cons (NULL_TREE, $2, $1); } ! 370: | typed_declspecs structsp ! 371: { $$ = tree_cons (NULL_TREE, $2, $1); } ! 372: | typed_declspecs SCSPEC ! 373: { $$ = tree_cons (NULL_TREE, $2, $1); } ! 374: ; ! 375: ! 376: /* declspecs which contain no type specifiers. ! 377: The identifier to which they apply must not be a typedef'd name. */ ! 378: scspecs: SCSPEC ! 379: { $$ = build_tree_list (NULL_TREE, $1); } ! 380: | scspecs SCSPEC ! 381: { $$ = tree_cons (NULL_TREE, $2, $1); } ! 382: ; ! 383: ! 384: /* used instead of declspecs where storage classes are not allowed ! 385: (typenames, structure components, and parameters) */ ! 386: typespecs: ! 387: typespec ! 388: { $$ = build_tree_list (NULL_TREE, $1); } ! 389: | typespecs TYPESPEC ! 390: { $$ = tree_cons (NULL_TREE, $2, $1); } ! 391: | typespecs TYPEMOD ! 392: { $$ = tree_cons (NULL_TREE, $2, $1); } ! 393: | typespecs structsp ! 394: { $$ = tree_cons (NULL_TREE, $2, $1); } ! 395: ; ! 396: ! 397: typespec: TYPESPEC ! 398: | TYPEMOD ! 399: | structsp ! 400: | TYPENAME ! 401: ; ! 402: ! 403: initdecls: ! 404: initdcl ! 405: | initdecls ',' initdcl ! 406: ; ! 407: ! 408: notype_initdecls: ! 409: notype_initdcl ! 410: | notype_initdecls ',' initdcl ! 411: ; ! 412: ! 413: initdcl: ! 414: declarator '=' ! 415: { $<ttype>$ = start_decl ($1, current_declspecs, 1); } ! 416: init ! 417: /* Note how the declaration of the variable is in effect while its init is parsed! */ ! 418: { finish_decl (input_filename, @1.first_line, $<ttype>3, $4); } ! 419: | declarator ! 420: { tree d = start_decl ($1, current_declspecs, 0); ! 421: finish_decl (input_filename, @1.first_line, d, NULL_TREE); } ! 422: ; ! 423: ! 424: notype_initdcl: ! 425: notype_declarator '=' ! 426: { $<ttype>$ = start_decl ($1, current_declspecs, 1); } ! 427: init ! 428: /* Note how the declaration of the variable is in effect while its init is parsed! */ ! 429: { finish_decl (input_filename, @1.first_line, $<ttype>3, $4); } ! 430: | notype_declarator ! 431: { tree d = start_decl ($1, current_declspecs, 0); ! 432: finish_decl (input_filename, @1.first_line, d, NULL_TREE); } ! 433: ; ! 434: ! 435: init: ! 436: expr_no_commas ! 437: | '{' initlist '}' ! 438: { $$ = build1 (CONSTRUCTOR, nreverse ($2)); } ! 439: | '{' initlist ',' '}' ! 440: { $$ = build1 (CONSTRUCTOR, nreverse ($2)); } ! 441: ; ! 442: ! 443: /* This chain is built in reverse order, ! 444: and put in forward order where initlist is used. */ ! 445: initlist: ! 446: init ! 447: { $$ = build_tree_list (NULL_TREE, $1); } ! 448: | initlist ',' init ! 449: { $$ = tree_cons (NULL, $3, $1); } ! 450: ; ! 451: ! 452: /* Any kind of declarator (thus, all declarators allowed ! 453: after an explicit typespec). */ ! 454: ! 455: declarator: ! 456: after_type_declarator ! 457: | notype_declarator ! 458: ; ! 459: ! 460: /* A declarator that is allowed only after an explicit typespec. */ ! 461: ! 462: after_type_declarator: ! 463: after_type_declarator '(' parmlist ')' %prec '.' ! 464: { $$ = build2 (CALL_EXPR, $1, $3); } ! 465: | after_type_declarator '(' identifiers ')' %prec '.' ! 466: { $$ = build2 (CALL_EXPR, $1, $3); } ! 467: | after_type_declarator '(' error ')' %prec '.' ! 468: { $$ = build2 (CALL_EXPR, $1, NULL_TREE); } ! 469: | after_type_declarator '[' expr ']' %prec '.' ! 470: { $$ = build2 (ARRAY_REF, $1, $3); } ! 471: | after_type_declarator '[' ']' %prec '.' ! 472: { $$ = build2 (ARRAY_REF, $1, NULL_TREE); } ! 473: | TYPENAME ! 474: ; ! 475: ! 476: /* A declarator allowed whether or not there has been ! 477: an explicit typespec. These cannot redeclare a typedef-name. */ ! 478: ! 479: notype_declarator: ! 480: notype_declarator '(' parmlist ')' %prec '.' ! 481: { $$ = build2 (CALL_EXPR, $1, $3); } ! 482: | notype_declarator '(' identifiers ')' %prec '.' ! 483: { $$ = build2 (CALL_EXPR, $1, $3); } ! 484: | notype_declarator '(' error ')' %prec '.' ! 485: { $$ = build2 (CALL_EXPR, $1, NULL_TREE); } ! 486: | '(' notype_declarator ')' ! 487: { $$ = $2; } ! 488: | '*' typemods notype_declarator %prec UNARY ! 489: { $$ = make_pointer_declarator ($2, $3); } ! 490: | notype_declarator '[' expr ']' %prec '.' ! 491: { $$ = build2 (ARRAY_REF, $1, $3); } ! 492: | notype_declarator '[' ']' %prec '.' ! 493: { $$ = build2 (ARRAY_REF, $1, NULL_TREE); } ! 494: | IDENTIFIER ! 495: ; ! 496: ! 497: structsp: ! 498: STRUCT identifier '{' component_decl_list '}' ! 499: { $$ = build_struct (RECORD_TYPE, input_filename, @1.first_line, $2, $4, 0); } ! 500: | STRUCT '{' component_decl_list '}' ! 501: { $$ = build_struct (RECORD_TYPE, input_filename, @1.first_line, NULL_TREE, $3, 0); } ! 502: | STRUCT identifier ! 503: { $$ = build_struct (RECORD_TYPE, input_filename, @1.first_line, $2, NULL_TREE, 1); } ! 504: | UNION identifier '{' component_decl_list '}' ! 505: { $$ = build_struct (UNION_TYPE, input_filename, @1.first_line, $2, $4, 0); } ! 506: | UNION '{' component_decl_list '}' ! 507: { $$ = build_struct (UNION_TYPE, input_filename, @1.first_line, NULL_TREE, $3, 0); } ! 508: | UNION identifier ! 509: { $$ = build_struct (UNION_TYPE, input_filename, @1.first_line, $2, NULL_TREE, 1); } ! 510: | ENUM identifier '{' ! 511: { $$ = start_enum ($2); } ! 512: enumlist '}' ! 513: { $$ = finish_enum ($<ttype>4, nreverse ($5)); } ! 514: | ENUM '{' ! 515: { $$ = start_enum (NULL_TREE); } ! 516: enumlist '}' ! 517: { $$ = finish_enum ($<ttype>3, nreverse ($4)); } ! 518: | ENUM identifier ! 519: { $$ = xref_enum ($2); } ! 520: ; ! 521: ! 522: component_decl_list: /* empty */ ! 523: { $$ = NULL_TREE; } ! 524: | component_decl ! 525: | component_decl_list ';' component_decl ! 526: { $$ = chainon ($1, $3); } ! 527: | component_decl_list ';' ! 528: ; ! 529: ! 530: component_decl: ! 531: typespecs setspecs components ! 532: { $$ = $3; } ! 533: | error ! 534: { $$ == NULL_TREE; } ! 535: ; ! 536: ! 537: components: ! 538: /* empty */ ! 539: { $$ = NULL_TREE; } ! 540: | component_declarator ! 541: | components ',' component_declarator ! 542: { $$ = chainon ($1, $3); } ! 543: ; ! 544: ! 545: component_declarator: ! 546: declarator ! 547: { $$ = grokfield (input_filename, @1.first_line, $1, current_declspecs, NULL_TREE); } ! 548: | declarator ':' expr_no_commas ! 549: { $$ = grokfield (input_filename, @1.first_line, $1, current_declspecs, $3); } ! 550: | ':' expr_no_commas ! 551: { $$ = grokfield (input_filename, @1.first_line, NULL_TREE, current_declspecs, $2); } ! 552: ; ! 553: ! 554: /* We chain the enumerators in reverse order. ! 555: They are put in forward order where enumlist is used. ! 556: (The order used to be significant, but no longer is so. ! 557: However, we still maintain the order, just to be clean.) */ ! 558: ! 559: enumlist: ! 560: enumerator ! 561: | enumlist ',' enumerator ! 562: { $$ = chainon ($3, $1); } ! 563: | enumlist ',' ! 564: ; ! 565: ! 566: ! 567: enumerator: ! 568: identifier ! 569: { $$ = build_enumerator ($1, NULL_TREE); } ! 570: | identifier '=' expr_no_commas ! 571: { $$ = build_enumerator ($1, $3); } ! 572: ; ! 573: ! 574: typename: ! 575: typespecs absdcl ! 576: { $$ = build_tree_list ($1, $2); } ! 577: ; ! 578: ! 579: absdcl: /* an absolute declarator */ ! 580: /* empty */ ! 581: { $$ = NULL_TREE; } ! 582: | absdcl1 ! 583: ; ! 584: ! 585: typemods: ! 586: /* empty */ ! 587: { $$ = NULL_TREE; } ! 588: | typemods TYPEMOD ! 589: { $$ = tree_cons (NULL_TREE, $2, $1); } ! 590: ; ! 591: ! 592: absdcl1: /* a nonempty absolute declarator */ ! 593: '(' absdcl1 ')' ! 594: { $$ = $2; } ! 595: | '*' typemods absdcl1 %prec UNARY ! 596: { $$ = make_pointer_declarator ($2, $3); } ! 597: | '*' typemods %prec UNARY ! 598: { $$ = make_pointer_declarator ($2, NULL_TREE); } ! 599: | absdcl1 '(' parmlist ')' %prec '.' ! 600: { $$ = build2 (CALL_EXPR, $1, $3); } ! 601: | absdcl1 '[' expr ']' %prec '.' ! 602: { $$ = build2 (ARRAY_REF, $1, $3); } ! 603: | absdcl1 '[' ']' %prec '.' ! 604: { $$ = build2 (ARRAY_REF, $1, NULL_TREE); } ! 605: | '(' parmlist ')' %prec '.' ! 606: { $$ = build2 (CALL_EXPR, NULL_TREE, $2); } ! 607: | '[' expr ']' %prec '.' ! 608: { $$ = build2 (ARRAY_REF, NULL_TREE, $2); } ! 609: | '[' ']' %prec '.' ! 610: { $$ = build2 (ARRAY_REF, NULL_TREE, NULL_TREE); } ! 611: ; ! 612: ! 613: /* at least one statement, the first of which parses without error. */ ! 614: /* stmts is used only after decls, so an invalid first statement ! 615: is actually regarded as an invalid decl and part of the decls. */ ! 616: ! 617: /* To speed things up, we actually chain the statements in ! 618: reverse order and return them that way. ! 619: They are put into forward order where stmts is used. */ ! 620: stmts: ! 621: stmt ! 622: | stmts stmt ! 623: { $$ = chainon ($2, $1); } ! 624: | stmts errstmt ! 625: ; ! 626: ! 627: errstmt: error ';' ! 628: ; ! 629: ! 630: /* build the LET_STMT node before parsing its contents, ! 631: so that any LET_STMTs within the context can have their display pointers ! 632: set up to point at this one. */ ! 633: ! 634: pushlevel: /* empty */ ! 635: { pushlevel(); ! 636: $$ = current_block; ! 637: current_block ! 638: = build_let (input_filename, 0, 0, 0, $$, 0); ! 639: } ! 640: ; ! 641: ! 642: compstmt: '{' '}' ! 643: { $$ = build_compound (input_filename, @1.first_line, 0); } ! 644: | '{' pushlevel decls stmts '}' ! 645: { $$ = finish_compound_stmt (current_block, nreverse ($4), ! 646: $2, @1.first_line); } ! 647: | '{' pushlevel decls '}' ! 648: { $$ = finish_compound_stmt (current_block, NULL_TREE, ! 649: $2, @1.first_line); } ! 650: | '{' pushlevel error '}' ! 651: { $$ = error_mark_node; ! 652: current_block = $2; ! 653: poplevel(); } ! 654: | '{' pushlevel stmts '}' ! 655: { $$ = finish_compound_stmt (current_block, nreverse ($3), $2, ! 656: @1.first_line); } ! 657: ; ! 658: ! 659: stmt: compstmt ! 660: | expr ';' ! 661: { $$ = build_expr_stmt (input_filename, @1.first_line, $1); } ! 662: | IF '(' expr ')' stmt ! 663: { $$ = build_if (input_filename, @1.first_line, default_conversion ($3), $5, 0); } ! 664: | IF '(' expr ')' stmt ELSE stmt ! 665: { $$ = build_if (input_filename, @1.first_line, default_conversion ($3), $5, $7); } ! 666: | WHILE ! 667: { pushbreak(1); } ! 668: '(' expr ')' stmt ! 669: { $$ = build_loop (input_filename, @1.first_line, ! 670: chainon (build_exit (input_filename, @4.first_line, ! 671: default_conversion ($4)), ! 672: chainon ($6, current_continue_label))); ! 673: $$ = build_compound (input_filename, @1.first_line, chainon ($$, current_break_label)); ! 674: popbreak(1); } ! 675: | DO ! 676: { pushbreak(1); } ! 677: stmt WHILE '(' expr ')' ';' ! 678: { $$ = build_loop (input_filename, @1.first_line, ! 679: chainon ($3, chainon(current_continue_label, ! 680: build_exit (input_filename, @6.first_line, ! 681: default_conversion ($6))))); ! 682: $$ = build_compound (input_filename, @1.first_line, chainon ($$, current_break_label)); ! 683: popbreak(1); } ! 684: | FOR ! 685: { pushbreak(1); } ! 686: '(' xexpr ';' xexpr ';' xexpr ')' stmt ! 687: { $$ = build_compound (input_filename, @1.first_line, ! 688: chainon ($4 ? build_expr_stmt (input_filename, @4.first_line, $4) : NULL_TREE, ! 689: build_loop (input_filename, @1.first_line, ! 690: chainon ($6 ? build_exit (input_filename, @6.first_line, ! 691: default_conversion ($6)) ! 692: : NULL_TREE, ! 693: chainon (chainon ($10, current_continue_label), ! 694: $8 ? build_expr_stmt (input_filename, @8.first_line, $8) : NULL_TREE))))); ! 695: $$ = build_compound (input_filename, @1.first_line, chainon ($$, current_break_label)); ! 696: popbreak(1); } ! 697: | SWITCH '(' expr ')' ! 698: { $<ttype>$ = current_switch_stmt; ! 699: pushbreak(0); ! 700: current_switch_stmt ! 701: = build_switch_stmt (input_filename, @1.first_line, ! 702: default_conversion ($3)); } ! 703: stmt ! 704: { $$ = build_compound (input_filename, @1.first_line, ! 705: chainon(current_switch_stmt, ! 706: chainon($6, current_break_label))); ! 707: finish_switch_stmt (current_switch_stmt, current_break_label); ! 708: popbreak (0); ! 709: current_switch_stmt = $<ttype>5; } ! 710: | CASE expr ':' stmt ! 711: { register tree value = fold($2); ! 712: tree l = build_label (input_filename, @1.first_line, NULL_TREE, current_block); ! 713: ! 714: if (TREE_CODE (value) != INTEGER_CST) ! 715: { ! 716: yyerror("case label does not reduce to an integer constant"); ! 717: value = error_mark_node; ! 718: } ! 719: pushcase(value, l); ! 720: $$ = build_compound (input_filename, @1.first_line, chainon(l, $4)); ! 721: } ! 722: | DEFAULT ':' stmt ! 723: { ! 724: tree l = build_label (input_filename, @1.first_line, 0, current_block); ! 725: pushcase(NULL_TREE, l); ! 726: $$ = build_compound (input_filename, @1.first_line, chainon(l, $3)); ! 727: } ! 728: | BREAK ';' ! 729: { if (current_break_label) ! 730: $$ = build_goto (input_filename, @1.first_line, STMT_BODY (current_break_label)); ! 731: else ! 732: { ! 733: yyerror("break statement not within a do, for, while or switch statement"); ! 734: $$ = error_mark_node; ! 735: } ! 736: } ! 737: | CONTINUE ';' ! 738: { if (current_continue_label) ! 739: $$ = build_goto (input_filename, @1.first_line, STMT_BODY (current_continue_label)); ! 740: else ! 741: { ! 742: yyerror("continue statement not within a do, for or while statement"); ! 743: $$ = error_mark_node; ! 744: } ! 745: } ! 746: | RETURN ';' ! 747: { $$ = build_return (input_filename, @1.first_line, NULL_TREE); } ! 748: | RETURN expr ';' ! 749: { $$ = build_return_stmt (input_filename, @1.first_line, $2); } ! 750: | GOTO identifier ';' ! 751: { pushgoto($$ = build_goto (input_filename, @1.first_line, $2)); } ! 752: | ASM '(' STRING ')' ';' ! 753: { $$ = build_asm_stmt (input_filename, @1.first_line, $3); } ! 754: | identifier ':' stmt ! 755: { $$ = build_compound (input_filename, @1.first_line, chainon (build_label (input_filename, @1.first_line, $1, current_block), $3)); } ! 756: | ';' ! 757: { $$ = build_compound (input_filename, @1.first_line, 0); } ! 758: ; ! 759: ! 760: xexpr: ! 761: /* empty */ ! 762: { $$ = NULL_TREE; } ! 763: | expr ! 764: ; ! 765: ! 766: /* This is what appears inside the parens in a function declarator. ! 767: Is value is represented in the format that grokdeclarator expects. */ ! 768: parmlist: /* empty */ ! 769: { $$ = NULL_TREE; } ! 770: | parms ! 771: { $$ = chainon ($1, build_tree_list (NULL_TREE, ! 772: void_type_node)); } ! 773: | parms ',' ELLIPSIS ! 774: ; ! 775: ! 776: /* A nonempty list of parameter declarations or type names. */ ! 777: parms: ! 778: parm ! 779: { $$ = build_tree_list (NULL_TREE, $1); } ! 780: | parms ',' parm ! 781: { $$ = chainon ($1, build_tree_list (NULL_TREE, $3)); } ! 782: ; ! 783: ! 784: parm: ! 785: typespecs declarator ! 786: { $$ = build_tree_list ($1, $2) ; } ! 787: | typespecs absdcl ! 788: { $$ = build_tree_list ($1, $2); } ! 789: ; ! 790: ! 791: /* A nonempty list of identifiers. */ ! 792: identifiers: ! 793: IDENTIFIER ! 794: { $$ = build_tree_list (NULL_TREE, $1); } ! 795: | identifiers ',' IDENTIFIER ! 796: { $$ = chainon ($1, build_tree_list (NULL_TREE, $3)); } ! 797: ; ! 798: %% ! 799: ! 800: static tree ! 801: finish_compound_stmt(block, stmts, outer_block, line) ! 802: tree block, stmts, outer_block; ! 803: int line; ! 804: { ! 805: register tree decls = getdecls(); ! 806: register tree tags = gettags (); ! 807: ! 808: if (decls || tags) ! 809: { ! 810: finish_block (block, decls, tags, stmts); ! 811: poplevel(); ! 812: current_block = outer_block; ! 813: STMT_SOURCE_LINE (block) = line; ! 814: return block; ! 815: } ! 816: else ! 817: { ! 818: current_block = outer_block; ! 819: poplevel(); ! 820: return build_compound (input_filename, line, stmts); ! 821: } ! 822: } ! 823: ! 824: ! 825: ! 826: static void ! 827: pushbreak(a) ! 828: int a; ! 829: { ! 830: if (current_break_label) ! 831: TREE_CHAIN (current_break_label) = break_label_stack; ! 832: break_label_stack = current_break_label; ! 833: current_break_label = build_label (0, 0, NULL_TREE, current_block); ! 834: ! 835: if (a) ! 836: { ! 837: if (current_continue_label) ! 838: TREE_CHAIN (current_continue_label) = continue_label_stack; ! 839: continue_label_stack = current_continue_label; ! 840: current_continue_label = build_label (0, 0, NULL_TREE, current_block); ! 841: } ! 842: } ! 843: ! 844: static void ! 845: popbreak(a) ! 846: int a; ! 847: { ! 848: current_break_label = break_label_stack; ! 849: if (current_break_label) ! 850: break_label_stack = TREE_CHAIN (break_label_stack); ! 851: ! 852: if (a) ! 853: { ! 854: current_continue_label = continue_label_stack; ! 855: if (current_continue_label) ! 856: continue_label_stack = TREE_CHAIN (continue_label_stack); ! 857: } ! 858: ! 859: if (current_break_label) ! 860: TREE_CHAIN (current_break_label) = NULL; ! 861: if (current_continue_label) ! 862: TREE_CHAIN (current_continue_label) = NULL; ! 863: } ! 864: ! 865: /* Return something to represent absolute declarators containing a *. ! 866: TARGET is the absolute declarator that the * contains. ! 867: TYPEMODS is a list of modifiers such as const or volatile ! 868: to apply to the pointer type, represented as identifiers. ! 869: ! 870: We return an INDIRECT_REF whose "contents" are TARGET ! 871: and whose type is the modifier list. */ ! 872: ! 873: static tree ! 874: make_pointer_declarator (typemods, target) ! 875: tree typemods, target; ! 876: { ! 877: register tree t = build1 (INDIRECT_REF, target); ! 878: TREE_TYPE (t) = typemods; ! 879: return t; ! 880: } ! 881: ! 882: /* Given a chain of STRING_CST nodes, ! 883: concatenate them into one STRING_CST ! 884: and then return an ADDR_EXPR for it. */ ! 885: ! 886: static tree ! 887: combine_strings (strings) ! 888: tree strings; ! 889: { ! 890: register tree value, t; ! 891: ! 892: if (TREE_CHAIN (strings)) ! 893: { ! 894: /* More than one in the chain, so concatenate. */ ! 895: register char *p, *q; ! 896: register int length = 1; ! 897: ! 898: /* Don't include the \0 at the end of each substring, ! 899: except for the last one. */ ! 900: for (t = strings; t; t = TREE_CHAIN (t)) ! 901: length += TREE_STRING_LENGTH (t) - 1; ! 902: ! 903: p = (char *) oballoc (length); ! 904: ! 905: q = p; ! 906: for (t = strings; t; t = TREE_CHAIN (t)) ! 907: { ! 908: bcopy (TREE_STRING_POINTER (t), q, TREE_STRING_LENGTH (t) - 1); ! 909: q += TREE_STRING_LENGTH (t) - 1; ! 910: } ! 911: *q = 0; ! 912: ! 913: value = make_node (STRING_CST); ! 914: TREE_TYPE (value) = TREE_TYPE (strings); ! 915: TREE_STRING_POINTER (value) = p; ! 916: TREE_STRING_LENGTH (value) = length; ! 917: TREE_LITERAL (value) = 1; ! 918: } ! 919: else ! 920: value = strings; ! 921: ! 922: value = build1 (ADDR_EXPR, value); ! 923: TREE_TYPE (value) = string_type_node; ! 924: TREE_LITERAL (value) = 1; ! 925: return value; ! 926: } ! 927: ! 928: int lineno; /* current line number in file being read */ ! 929: ! 930: FILE *finput; /* input file. ! 931: Normally a pipe from the preprocessor. */ ! 932: ! 933: /* lexical analyzer */ ! 934: ! 935: static int maxtoken; /* Current length of token buffer */ ! 936: static char *token_buffer; /* Pointer to token buffer */ ! 937: ! 938: /* frw[i] is index in rw of the first word whose length is i. */ ! 939: ! 940: #define MAXRESERVED 9 ! 941: ! 942: static char frw[10] = ! 943: { 0, 0, 0, 2, 5, 13, 19, 27, 29, 33 }; ! 944: ! 945: static char *rw[] = ! 946: { "if", "do", "int", "for", "asm", ! 947: "case", "char", "auto", "goto", "else", "long", "void", "enum", ! 948: "float", "short", "union", "break", "while", "const", ! 949: "double", "static", "extern", "struct", "return", "sizeof", "switch", "signed", ! 950: "typedef", "default", ! 951: "unsigned", "continue", "register", "volatile" }; ! 952: ! 953: static short rtoken[] = ! 954: { IF, DO, TYPESPEC, FOR, ASM, ! 955: CASE, TYPESPEC, SCSPEC, GOTO, ELSE, TYPESPEC, TYPESPEC, ENUM, ! 956: TYPESPEC, TYPESPEC, UNION, BREAK, WHILE, TYPEMOD, ! 957: TYPESPEC, SCSPEC, SCSPEC, STRUCT, RETURN, SIZEOF, SWITCH, TYPESPEC, ! 958: SCSPEC, DEFAULT, ! 959: TYPESPEC, CONTINUE, SCSPEC, TYPEMOD }; ! 960: ! 961: /* This table corresponds to rw and rtoken. ! 962: Its element is an index in ridpointers */ ! 963: ! 964: #define NORID (enum rid) 0 ! 965: ! 966: static enum rid rid[] = ! 967: { NORID, NORID, RID_INT, NORID, NORID, ! 968: NORID, RID_CHAR, RID_AUTO, NORID, NORID, RID_LONG, RID_VOID, NORID, ! 969: RID_FLOAT, RID_SHORT, NORID, NORID, NORID, RID_CONST, ! 970: RID_DOUBLE, RID_STATIC, RID_EXTERN, NORID, NORID, NORID, NORID, RID_SIGNED, ! 971: RID_TYPEDEF, NORID, ! 972: RID_UNSIGNED, NORID, RID_REGISTER, RID_VOLATILE }; ! 973: ! 974: /* The elements of `ridpointers' are identifier nodes ! 975: for the reserved type names and storage classes. */ ! 976: ! 977: tree ridpointers[(int) RID_MAX]; ! 978: ! 979: static tree line_identifier; /* The identifier node named "line" */ ! 980: ! 981: void check_newline(); ! 982: ! 983: void ! 984: init_lex() ! 985: { ! 986: extern char *malloc(); ! 987: ! 988: /* Start it at 0, because check_newline is called atthe very beginning ! 989: and will increment it to 1. */ ! 990: lineno = 0; ! 991: current_function_decl = NULL; ! 992: current_switch_stmt = NULL; ! 993: current_block = NULL; ! 994: current_break_label = NULL; ! 995: current_continue_label = NULL; ! 996: break_label_stack = NULL; ! 997: continue_label_stack = NULL; ! 998: line_identifier = get_identifier("line"); ! 999: ! 1000: maxtoken = 40; ! 1001: token_buffer = malloc((unsigned)(maxtoken+1)); ! 1002: ridpointers[(int) RID_INT] = get_identifier("int"); ! 1003: ridpointers[(int) RID_CHAR] = get_identifier("char"); ! 1004: ridpointers[(int) RID_VOID] = get_identifier("void"); ! 1005: ridpointers[(int) RID_FLOAT] = get_identifier("float"); ! 1006: ridpointers[(int) RID_DOUBLE] = get_identifier("double"); ! 1007: ridpointers[(int) RID_SHORT] = get_identifier("short"); ! 1008: ridpointers[(int) RID_LONG] = get_identifier("long"); ! 1009: ridpointers[(int) RID_UNSIGNED] = get_identifier("unsigned"); ! 1010: ridpointers[(int) RID_SIGNED] = get_identifier("signed"); ! 1011: ridpointers[(int) RID_CONST] = get_identifier("const"); ! 1012: ridpointers[(int) RID_VOLATILE] = get_identifier("volatile"); ! 1013: ridpointers[(int) RID_AUTO] = get_identifier("auto"); ! 1014: ridpointers[(int) RID_STATIC] = get_identifier("static"); ! 1015: ridpointers[(int) RID_EXTERN] = get_identifier("extern"); ! 1016: ridpointers[(int) RID_TYPEDEF] = get_identifier("typedef"); ! 1017: ridpointers[(int) RID_REGISTER] = get_identifier("register"); ! 1018: } ! 1019: ! 1020: static int ! 1021: skip_white_space() ! 1022: { ! 1023: register int c; ! 1024: register int inside; ! 1025: ! 1026: c = getc(finput); ! 1027: ! 1028: for (;;) ! 1029: { ! 1030: switch (c) ! 1031: { ! 1032: case '/': ! 1033: c = getc(finput); ! 1034: if (c != '*') ! 1035: { ! 1036: ungetc(c, finput); ! 1037: return '/'; ! 1038: } ! 1039: ! 1040: c = getc(finput); ! 1041: ! 1042: inside = 1; ! 1043: while (inside) ! 1044: { ! 1045: if (c == '*') ! 1046: { ! 1047: while (c == '*') ! 1048: c = getc(finput); ! 1049: ! 1050: if (c == '/') ! 1051: { ! 1052: inside = 0; ! 1053: c = getc(finput); ! 1054: } ! 1055: } ! 1056: else if (c == '\n') ! 1057: { ! 1058: lineno++; ! 1059: c = getc(finput); ! 1060: } ! 1061: else if (c == EOF) ! 1062: yyerror("unterminated comment"); ! 1063: else ! 1064: c = getc(finput); ! 1065: } ! 1066: ! 1067: break; ! 1068: ! 1069: case '\n': ! 1070: check_newline(); ! 1071: ! 1072: case ' ': ! 1073: case '\t': ! 1074: case '\f': ! 1075: case '\r': ! 1076: case '\b': ! 1077: c = getc(finput); ! 1078: break; ! 1079: ! 1080: case '\\': ! 1081: c = getc(finput); ! 1082: if (c == '\n') ! 1083: lineno++; ! 1084: else ! 1085: yyerror("stray '\\' in program"); ! 1086: c = getc(finput); ! 1087: break; ! 1088: ! 1089: default: ! 1090: return (c); ! 1091: } ! 1092: } ! 1093: } ! 1094: ! 1095: ! 1096: ! 1097: /* make the token buffer longer, preserving the data in it. ! 1098: p should point to just beyond the last valid character in the old buffer ! 1099: and the value points to the corresponding place in the new one. */ ! 1100: ! 1101: static char * ! 1102: extend_token_buffer(p) ! 1103: char *p; ! 1104: { ! 1105: register char *newbuf; ! 1106: register char *value; ! 1107: int newlength = maxtoken * 2 + 10; ! 1108: register char *p2, *p1; ! 1109: extern char *malloc(); ! 1110: ! 1111: newbuf = malloc((unsigned)(newlength+1)); ! 1112: ! 1113: p2 = newbuf; ! 1114: p1 = newbuf + newlength + 1; ! 1115: while (p1 != p2) *p2++ = 0; ! 1116: ! 1117: value = newbuf; ! 1118: p2 = token_buffer; ! 1119: while (p2 != p) ! 1120: *value++ = *p2++; ! 1121: ! 1122: token_buffer = newbuf; ! 1123: ! 1124: maxtoken = newlength; ! 1125: ! 1126: return (value); ! 1127: } ! 1128: ! 1129: ! 1130: ! 1131: /* At the beginning of a line, ! 1132: increment the line number ! 1133: and handle a #line directive immediately following */ ! 1134: ! 1135: void ! 1136: check_newline () ! 1137: { ! 1138: register int c; ! 1139: register int token; ! 1140: ! 1141: while (1) ! 1142: { ! 1143: c = getc (finput); ! 1144: lineno++; ! 1145: ! 1146: if (c != '#') ! 1147: { ! 1148: /* If no #, unread the character, ! 1149: except don't bother if it is whitespace. */ ! 1150: if (c == ' ' || c == '\t') ! 1151: return; ! 1152: ungetc (c, finput); ! 1153: return; ! 1154: } ! 1155: ! 1156: /* Skip whitespace after the #. */ ! 1157: ! 1158: while (1) ! 1159: { ! 1160: c = getc (finput); ! 1161: if (! (c == ' ' || c == '\t')) ! 1162: break; ! 1163: } ! 1164: ! 1165: /* If the # is the only nonwhite char on the line, ! 1166: just ignore it. Check the new newline. */ ! 1167: if (c == '\n') ! 1168: continue; ! 1169: ! 1170: /* Something follows the #; read a token. */ ! 1171: ! 1172: ungetc (c, finput); ! 1173: token = yylex (); ! 1174: ! 1175: if (token == CONSTANT ! 1176: && TREE_CODE (yylval.ttype) == INTEGER_CST) ! 1177: { ! 1178: /* subtract one, because it is the following line that ! 1179: gets the specified number */ ! 1180: ! 1181: int l = TREE_INT_CST_LOW (yylval.ttype) - 1; ! 1182: ! 1183: token = yylex (); ! 1184: if (token != STRING || TREE_CODE (yylval.ttype) != STRING_CST) ! 1185: yyerror ("invalid #line"); ! 1186: ! 1187: input_filename ! 1188: = (char *) permalloc (TREE_STRING_LENGTH (yylval.ttype) + 1); ! 1189: strcpy (input_filename, TREE_STRING_POINTER (yylval.ttype)); ! 1190: lineno = l; ! 1191: } ! 1192: else ! 1193: yyerror ("undefined or invalid # directive"); ! 1194: ! 1195: /* skip the rest of this line. */ ! 1196: while ((c = getc (finput)) != '\n'); ! 1197: } ! 1198: } ! 1199: ! 1200: ! 1201: ! 1202: #define isalnum(char) ((char >= 'a' && char <= 'z') || (char >= 'A' && char <= 'Z') || (char >= '0' && char <= '9')) ! 1203: #define isdigit(char) (char >= '0' && char <= '9') ! 1204: #define ENDFILE -1 /* token that represents end-of-file */ ! 1205: ! 1206: ! 1207: static int ! 1208: readescape () ! 1209: { ! 1210: register int c = getc (finput); ! 1211: register int count, code; ! 1212: ! 1213: switch (c) ! 1214: { ! 1215: case 'x': ! 1216: code = 0; ! 1217: count = 0; ! 1218: while (1) ! 1219: { ! 1220: c = getc (finput); ! 1221: if (!(c >= 'a' && c <= 'f') ! 1222: && !(c >= 'A' && c <= 'F') ! 1223: && !(c >= '0' && c <= '9')) ! 1224: { ! 1225: ungetc (c, finput); ! 1226: break; ! 1227: } ! 1228: if (c >= 'a' && c <= 'z') ! 1229: c -= 'a' - 'A'; ! 1230: code *= 16; ! 1231: if (c >= 'a' && c <= 'f') ! 1232: code += c - 'a' + 10; ! 1233: if (c >= 'A' && c <= 'F') ! 1234: code += c - 'A' + 10; ! 1235: if (c >= '0' && c <= '9') ! 1236: code += c - '0'; ! 1237: count++; ! 1238: if (count == 3) ! 1239: break; ! 1240: } ! 1241: if (count == 0) ! 1242: yyerror ("\\x used with no following hex digits"); ! 1243: return code; ! 1244: ! 1245: case '0': case '1': case '2': case '3': case '4': ! 1246: case '5': case '6': case '7': ! 1247: code = 0; ! 1248: count = 0; ! 1249: while ((c <= '7') && (c >= '0') && (count++ < 3)) ! 1250: { ! 1251: code = (code * 8) + (c - '0'); ! 1252: c = getc (finput); ! 1253: } ! 1254: ungetc (c, finput); ! 1255: return code; ! 1256: ! 1257: case '\\': case '\'': case '"': ! 1258: return c; ! 1259: ! 1260: case '\n': ! 1261: lineno++; ! 1262: return -1; ! 1263: ! 1264: case 'n': ! 1265: return TARGET_NEWLINE; ! 1266: ! 1267: case 't': ! 1268: return TARGET_TAB; ! 1269: ! 1270: case 'r': ! 1271: return TARGET_CR; ! 1272: ! 1273: case 'f': ! 1274: return TARGET_FF; ! 1275: ! 1276: case 'b': ! 1277: return TARGET_BS; ! 1278: ! 1279: case 'a': ! 1280: return TARGET_BELL; ! 1281: ! 1282: case 'v': ! 1283: return TARGET_VT; ! 1284: } ! 1285: return c; ! 1286: } ! 1287: ! 1288: ! 1289: static int ! 1290: yylex() ! 1291: { ! 1292: register int c; ! 1293: register char *p; ! 1294: register int value; ! 1295: ! 1296: c = skip_white_space(); ! 1297: ! 1298: yylloc.first_line = lineno; ! 1299: ! 1300: switch (c) ! 1301: { ! 1302: case EOF: ! 1303: value = ENDFILE; break; ! 1304: ! 1305: case 'A': case 'B': case 'C': case 'D': case 'E': ! 1306: case 'F': case 'G': case 'H': case 'I': case 'J': ! 1307: case 'K': case 'L': case 'M': case 'N': case 'O': ! 1308: case 'P': case 'Q': case 'R': case 'S': case 'T': ! 1309: case 'U': case 'V': case 'W': case 'X': case 'Y': ! 1310: case 'Z': ! 1311: case 'a': case 'b': case 'c': case 'd': case 'e': ! 1312: case 'f': case 'g': case 'h': case 'i': case 'j': ! 1313: case 'k': case 'l': case 'm': case 'n': case 'o': ! 1314: case 'p': case 'q': case 'r': case 's': case 't': ! 1315: case 'u': case 'v': case 'w': case 'x': case 'y': ! 1316: case 'z': ! 1317: case '_': ! 1318: p = token_buffer; ! 1319: while (isalnum(c) || (c == '_')) ! 1320: { ! 1321: if (p >= token_buffer + maxtoken) ! 1322: p = extend_token_buffer(p); ! 1323: *p++ = c; ! 1324: c = getc(finput); ! 1325: } ! 1326: ! 1327: *p = 0; ! 1328: ungetc(c, finput); ! 1329: ! 1330: value = IDENTIFIER; ! 1331: yylval.itype = 0; ! 1332: ! 1333: if (p - token_buffer <= MAXRESERVED) ! 1334: { ! 1335: register int lim = frw [p - token_buffer + 1]; ! 1336: register int i; ! 1337: ! 1338: for (i = frw[p - token_buffer]; i < lim; i++) ! 1339: if (rw[i][0] == token_buffer[0] && !strcmp(rw[i], token_buffer)) ! 1340: { ! 1341: if (rid[i]) ! 1342: yylval.ttype = ridpointers[(int) rid[i]]; ! 1343: value = (int) rtoken[i]; ! 1344: break; ! 1345: } ! 1346: } ! 1347: ! 1348: if (value == IDENTIFIER) ! 1349: { ! 1350: yylval.ttype = get_identifier(token_buffer); ! 1351: lastiddecl = lookup_name (yylval.ttype); ! 1352: ! 1353: if (lastiddecl != 0 && TREE_CODE (lastiddecl) == TYPE_DECL) ! 1354: value = TYPENAME; ! 1355: } ! 1356: ! 1357: break; ! 1358: ! 1359: case '0': case '1': case '2': case '3': case '4': ! 1360: case '5': case '6': case '7': case '8': case '9': ! 1361: case '.': ! 1362: { ! 1363: int base = 10; ! 1364: int count = 0; ! 1365: /* for multi-precision arithmetic, we store only 8 live bits in each short, ! 1366: giving us 64 bits of reliable precision */ ! 1367: short shorts[8]; ! 1368: char *floatflag = NULL; /* set nonzero if we learn this is a floating constant */ ! 1369: /* in fact, it points to the first fractional digit. */ ! 1370: ! 1371: for (count = 0; count < 8; count++) ! 1372: shorts[count] = 0; ! 1373: ! 1374: p = token_buffer; ! 1375: *p++ = c; ! 1376: ! 1377: if (c == '0') ! 1378: { ! 1379: *p++ = (c = getc(finput)); ! 1380: if ((c == 'x') || (c == 'X')) ! 1381: { ! 1382: base = 16; ! 1383: *p++ = (c = getc(finput)); ! 1384: } ! 1385: else ! 1386: { ! 1387: base = 8; ! 1388: } ! 1389: } ! 1390: ! 1391: while (c == '.' ! 1392: || (isalnum (c) && (c != 'l') && (c != 'L') ! 1393: && (c != 'u') && (c != 'U'))) ! 1394: { ! 1395: if (c == '.') ! 1396: { ! 1397: floatflag = p - 1; ! 1398: p[-1] = c = getc(finput); /* omit the decimal point from ! 1399: the token buffer. */ ! 1400: /* Accept '.' as the start of a floating-point number ! 1401: only when it is followed by a digit. ! 1402: Otherwise, unread the following non-digit ! 1403: and use the '.' as a structural token. */ ! 1404: if (floatflag == token_buffer && !isdigit (c)) ! 1405: { ! 1406: if (c == '.') ! 1407: { ! 1408: c = getc (finput); ! 1409: if (c == '.') ! 1410: return ELLIPSIS; ! 1411: yyerror ("syntax error"); ! 1412: } ! 1413: ungetc (c, finput); ! 1414: return '.'; ! 1415: } ! 1416: } ! 1417: else ! 1418: { ! 1419: if (isdigit(c)) ! 1420: { ! 1421: c = c - '0'; ! 1422: } ! 1423: else if (base <= 10) ! 1424: { ! 1425: if ((c&~040) == 'E') ! 1426: { ! 1427: if (floatflag == 0) ! 1428: floatflag = p - 1; ! 1429: break; /* start of exponent */ ! 1430: } ! 1431: yyerror("nondigits in number and not hexadecimal"); ! 1432: c = 0; ! 1433: } ! 1434: else if (c >= 'a') ! 1435: { ! 1436: c = c - 'a' + 10; ! 1437: } ! 1438: else ! 1439: { ! 1440: c = c - 'A' + 10; ! 1441: } ! 1442: if (c >= base) ! 1443: yyerror("numeric constant contains digits beyond the radix"); ! 1444: ! 1445: for (count = 0; count < 8; count++) ! 1446: { ! 1447: (shorts[count] *= base); ! 1448: if (count) ! 1449: { ! 1450: shorts[count] += (shorts[count-1] >> 8); ! 1451: shorts[count-1] &= (1<<8)-1; ! 1452: } ! 1453: else shorts[0] += c; ! 1454: } ! 1455: ! 1456: *p++ = (c = getc(finput)); ! 1457: } ! 1458: } ! 1459: ! 1460: /* Remove terminating char from the token buffer and delimit the string */ ! 1461: *--p = 0; ! 1462: ! 1463: if (floatflag) ! 1464: { ! 1465: register ex = -(p - floatflag); /* exponent is minus # digits after decimal pt */ ! 1466: ! 1467: tree type = double_type_node; ! 1468: ! 1469: /* read explicit exponent if any, and add into ex. */ ! 1470: ! 1471: if ((c == 'e') || (c == 'E')) ! 1472: { ! 1473: register int exval = 0; ! 1474: register int exsign = 1; ! 1475: ! 1476: c = getc(finput); ! 1477: if ((c == '+') || (c == '-')) ! 1478: { ! 1479: if (c == '-') exsign = -1; ! 1480: c = getc(finput); ! 1481: } ! 1482: while (isdigit(c)) ! 1483: { ! 1484: exval *= 10; ! 1485: exval += c - '0'; ! 1486: c = getc(finput); ! 1487: } ! 1488: ex += exsign*exval; ! 1489: } ! 1490: ! 1491: while (1) ! 1492: { ! 1493: if (c == 'f' || c == 'F') ! 1494: type = float_type_node; ! 1495: else if (c == 'l' || c == 'L') ! 1496: type = long_double_type_node; ! 1497: else break; ! 1498: c = getc (finput); ! 1499: } ! 1500: ! 1501: ungetc(c, finput); ! 1502: ! 1503: yylval.ttype = build_real_from_string (token_buffer, ex); ! 1504: TREE_TYPE (yylval.ttype) = type; ! 1505: } ! 1506: else ! 1507: { ! 1508: tree type; ! 1509: int spec_unsigned = 0; ! 1510: int spec_long = 0; ! 1511: ! 1512: while (1) ! 1513: { ! 1514: if (c == 'u' || c == 'U') ! 1515: { ! 1516: spec_unsigned = 1; ! 1517: c = getc (finput); ! 1518: } ! 1519: else if (c == 'l' || c == 'L') ! 1520: { ! 1521: spec_long = 1; ! 1522: c = getc (finput); ! 1523: } ! 1524: else break; ! 1525: } ! 1526: ! 1527: ungetc (c, finput); ! 1528: ! 1529: /* This is simplified by the fact that our constant ! 1530: is always positive. */ ! 1531: yylval.ttype ! 1532: = build_int_2 ((shorts[3]<<24) + (shorts[2]<<16) + (shorts[1]<<8) + shorts[0], ! 1533: (shorts[7]<<24) + (shorts[6]<<16) + (shorts[5]<<8) + shorts[4]); ! 1534: ! 1535: if (!spec_long && !spec_unsigned ! 1536: && int_fits_type_p (yylval.ttype, integer_type_node)) ! 1537: type = integer_type_node; ! 1538: ! 1539: else if (!spec_long && base != 10 ! 1540: && int_fits_type_p (yylval.ttype, unsigned_type_node)) ! 1541: type = unsigned_type_node; ! 1542: ! 1543: else if (!spec_unsigned ! 1544: && int_fits_type_p (yylval.ttype, long_integer_type_node)) ! 1545: type = long_integer_type_node; ! 1546: ! 1547: else ! 1548: type = long_unsigned_type_node; ! 1549: ! 1550: TREE_TYPE (yylval.ttype) = type; ! 1551: } ! 1552: ! 1553: value = CONSTANT; break; ! 1554: } ! 1555: ! 1556: case '\'': ! 1557: c = getc(finput); ! 1558: { ! 1559: register int code = 0; ! 1560: ! 1561: tryagain: ! 1562: ! 1563: if (c == '\\') ! 1564: { ! 1565: c = readescape (); ! 1566: if (c < 0) ! 1567: goto tryagain; ! 1568: } ! 1569: code = c; ! 1570: c = getc (finput); ! 1571: if (c != '\'') ! 1572: yyerror("malformatted character constant"); ! 1573: ! 1574: if (char_type_node == unsigned_char_type_node ! 1575: || (c >> (BITS_PER_UNIT - 1)) == 0) ! 1576: yylval.ttype = build_int_2 (code, 0); ! 1577: else ! 1578: yylval.ttype = build_int_2 (code | (1 << BITS_PER_UNIT), -1); ! 1579: ! 1580: TREE_TYPE (yylval.ttype) = char_type_node; ! 1581: value = CONSTANT; break; ! 1582: } ! 1583: ! 1584: case '"': ! 1585: { ! 1586: c = getc(finput); ! 1587: p = token_buffer; ! 1588: ! 1589: while (c != '"') ! 1590: { ! 1591: if (c == '\\') ! 1592: { ! 1593: c = readescape (); ! 1594: if (c < 0) ! 1595: goto skipnewline; ! 1596: } ! 1597: else if (c == '\n') ! 1598: { ! 1599: lineno++; ! 1600: } ! 1601: ! 1602: if (p == token_buffer + maxtoken) ! 1603: p = extend_token_buffer(p); ! 1604: *p++ = c; ! 1605: ! 1606: skipnewline: ! 1607: c = getc (finput); ! 1608: } ! 1609: ! 1610: *p++ = 0; ! 1611: ! 1612: yylval.ttype = build_string (p - token_buffer, token_buffer); ! 1613: TREE_TYPE (yylval.ttype) = char_array_type_node; ! 1614: ! 1615: value = STRING; break; ! 1616: } ! 1617: ! 1618: case '+': ! 1619: case '-': ! 1620: case '&': ! 1621: case '|': ! 1622: case '<': ! 1623: case '>': ! 1624: case '*': ! 1625: case '/': ! 1626: case '%': ! 1627: case '^': ! 1628: case '!': ! 1629: case '=': ! 1630: { ! 1631: register int c1; ! 1632: ! 1633: combine: ! 1634: ! 1635: switch (c) ! 1636: { ! 1637: case '+': ! 1638: yylval.code = PLUS_EXPR; break; ! 1639: case '-': ! 1640: yylval.code = MINUS_EXPR; break; ! 1641: case '&': ! 1642: yylval.code = BIT_AND_EXPR; break; ! 1643: case '|': ! 1644: yylval.code = BIT_IOR_EXPR; break; ! 1645: case '*': ! 1646: yylval.code = MULT_EXPR; break; ! 1647: case '/': ! 1648: yylval.code = TRUNC_DIV_EXPR; break; ! 1649: case '%': ! 1650: yylval.code = TRUNC_MOD_EXPR; break; ! 1651: case '^': ! 1652: yylval.code = BIT_XOR_EXPR; break; ! 1653: case LSHIFT: ! 1654: yylval.code = LSHIFT_EXPR; break; ! 1655: case RSHIFT: ! 1656: yylval.code = RSHIFT_EXPR; break; ! 1657: case '<': ! 1658: yylval.code = LT_EXPR; break; ! 1659: case '>': ! 1660: yylval.code = GT_EXPR; break; ! 1661: } ! 1662: ! 1663: c1 = getc(finput); ! 1664: ! 1665: if (c1 == '=') ! 1666: { ! 1667: switch (c) ! 1668: { ! 1669: case '<': ! 1670: value = ARITHCOMPARE; yylval.code = LE_EXPR; goto done; ! 1671: case '>': ! 1672: value = ARITHCOMPARE; yylval.code = GE_EXPR; goto done; ! 1673: case '!': ! 1674: value = EQCOMPARE; yylval.code = NE_EXPR; goto done; ! 1675: case '=': ! 1676: value = EQCOMPARE; yylval.code = EQ_EXPR; goto done; ! 1677: } ! 1678: value = ASSIGN; goto done; ! 1679: } ! 1680: else if (c == c1) ! 1681: switch (c) ! 1682: { ! 1683: case '+': ! 1684: value = PLUSPLUS; goto done; ! 1685: case '-': ! 1686: value = MINUSMINUS; goto done; ! 1687: case '&': ! 1688: value = ANDAND; goto done; ! 1689: case '|': ! 1690: value = OROR; goto done; ! 1691: case '<': ! 1692: c = LSHIFT; ! 1693: goto combine; ! 1694: case '>': ! 1695: c = RSHIFT; ! 1696: goto combine; ! 1697: } ! 1698: else if ((c == '-') && (c1 == '>')) ! 1699: { value = POINTSAT; goto done; } ! 1700: ungetc (c1, finput); ! 1701: ! 1702: if ((c == '<') || (c == '>')) ! 1703: value = ARITHCOMPARE; ! 1704: else value = c; ! 1705: goto done; ! 1706: } ! 1707: ! 1708: default: ! 1709: value = c; ! 1710: } ! 1711: ! 1712: done: ! 1713: yylloc.last_line = lineno; ! 1714: ! 1715: return (value); ! 1716: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.