home *** CD-ROM | disk | FTP | other *** search
/ The C Users' Group Library 1994 August / wc-cdrom-cusersgrouplibrary-1994-08.iso / vol_300 / 355_02 / slk2.exe / SPP / DCL.C next >
C/C++ Source or Header  |  1991-06-09  |  16KB  |  795 lines

  1. /*
  2.     Shelock Preprocessor -- Part II -- Declaration parsing routines.
  3.  
  4.     Source: dcl.c
  5.     Started: September 26, 1987
  6.     Version:
  7.         May 24, 1988
  8.         February 16, 1989
  9.             periods removed from error messages.
  10.             Spurious warning removed from type_ntail().
  11.             Set prev_dcl = 0 to get rid of error message.
  12.         June 22, 1989
  13.             Bug fix in type_tail().
  14.             curly_ok_flag kludge in i_list().
  15.  
  16.  
  17.     PUBLIC DOMAIN SOFTWARE
  18.  
  19.     Sherlock, including the SPP, SDEL and SDIF programs, was placed in
  20.     the public domain on June 15, 1991, by its author,
  21.  
  22.         Edward K. Ream
  23.         166 North Prospect Ave.
  24.         Madison, WI 53705.
  25.         (608) 257-0802
  26.  
  27.     Sherlock may be used for any commercial or non-commercial purpose.
  28.  
  29.  
  30.     DISCLAIMER OF WARRANTIES
  31.  
  32.     Edward K. Ream (Ream) specifically disclaims all warranties,
  33.     expressed or implied, with respect to this computer software,
  34.     including but not limited to implied warranties of merchantability
  35.     and fitness for a particular purpose.  In no event shall Ream be
  36.     liable for any loss of profit or any commercial damage, including
  37.     but not limited to special, incidental consequential or other damages.
  38. */
  39.  
  40. #include "spp.h"
  41.  
  42. /* Declare local routines of this file. */
  43. static void    array        (void);
  44. static void    dcl_enum    (void);
  45. static void    dcl_struct    (void);
  46. static void    fp_list        (en_scope);
  47. static void    function    (en_scope);
  48. static void    initializer    (void);
  49. static void    i_list        (void);
  50. static void    t_list        (void);
  51. static bool    type_head    (en_scope scope);
  52. static en_tokens type_tail    (en_scope scope);
  53. static void    type_ntail    (void);
  54.  
  55.  
  56. /* =============== Global variables =============== */
  57.  
  58. /* Indicates inside function definition. Used by function() and dcl().      */
  59. /* Set to FALSE by program.  Set to true by function().              */
  60. static bool    func_def;    /* TRUE if a function DEFINTION was seen. */
  61.  
  62. /* Used by function() to see whether function def should give a warning.  */
  63. static int    prev_dcl;    /* Number of previous sub-declarations.    */
  64.  
  65. /* =============== Global routines =============== */
  66.  
  67. /*
  68.     Parse the local variables of a block.
  69. */
  70. void
  71. block_dcls(void)
  72. {
  73.     SL_NAME(fn_name, "block_dcls");
  74.     TRACETOK(fn_name);
  75.  
  76.     while (is_type()) {
  77.         dcl(BLOCK_SCOPE);
  78.     }
  79.  
  80.     RETURN_VOID(fn_name);
  81. }
  82.  
  83. /*
  84.     Parse a single declaration or function definition.
  85.     Semicolon ends a declaration but not a function definition.
  86. */
  87. void
  88. dcl(en_scope scope)
  89. {
  90.     SL_NAME(fn_name, "dcl");
  91.     TRACETOK(fn_name);
  92.     TRACEPN(fn_name, printf("(%s)\n", pr_scope(scope)));
  93.  
  94.     /* Reset semantics for a new declaration. */
  95.     sd_dcl(scope);
  96.  
  97.     allow_mkeys();
  98.     if (type_head(scope) == TRUE) {
  99.         if (func_def && scope == OUTER_SCOPE) {
  100.             /* We saw a bare function definition. */
  101.             TRACEP(fn_name, printf("bare function complete\n"));
  102.  
  103.             prev_dcl = 0;
  104.             RETURN_VOID(fn_name);
  105.         }
  106.         else {
  107.             /* We saw a stand-alone struct\union or enum. */
  108.             must(SEMICOLON_TOK);
  109.             RETURN_VOID(fn_name);
  110.         }
  111.     }
  112.  
  113.     /* 2/16/89 */
  114.     for (prev_dcl = 0; ;) {
  115.  
  116.         type_tail(scope);
  117.         if (scope == OUTER_SCOPE && func_def) {
  118.             /* We ARE at the end of the dcl. */
  119.             if (is(COMMA_TOK)) {
  120.                 error("Comma following function body ignored");
  121.                 get_token();
  122.             }
  123.             /* 2/16/89 */
  124.             prev_dcl = 0;
  125.             break;
  126.         }
  127.         else if (is(COMMA_TOK)) {
  128.             sd_end(scope, COMMA_TOK);
  129.             get_token();
  130.             /* 2/16/89 */
  131.             prev_dcl++;
  132.         }
  133.         else if (is(SEMICOLON_TOK)) {
  134.             sd_end(scope, SEMICOLON_TOK);
  135.             get_token();
  136.             /* 2/16/89 */
  137.             prev_dcl = 0;
  138.             break;
  139.         }
  140.         else {
  141.             err3(    "Unexpected end of declaration at '",
  142.                 pr_tok(),
  143.                 "', comma or semicolon expected");
  144.             needend(SEMICOLON_TOK);
  145.             /* 2/16/89 */
  146.             prev_dcl = 0;
  147.             break;
  148.         }
  149.     }
  150.     RETURN_VOID(fn_name);
  151. }
  152.  
  153.  
  154. /*
  155.     A program is nothing but a list of declarations and definitions.
  156. */
  157. void
  158. program(void)
  159. {
  160.     SL_NAME(fn_name, "program");
  161.     TRACETOK(fn_name);
  162.  
  163.     /* Get the first token of the program. */
  164.     get_token();
  165.  
  166.     for (;;) {
  167.         /* Not in function definition yet. */
  168.         func_def = FALSE;
  169.  
  170.         allow_mkeys();
  171.         if (is_type() || is(ID_TOK)) {
  172.             dcl(OUTER_SCOPE);
  173.         }
  174.         else if (is(EOP_TOK)) {
  175.             RETURN_VOID(fn_name);
  176.         }
  177.         else if (is(COMMA_TOK)) {
  178.             error("External comma ignored");
  179.             get_token();
  180.         }
  181.         else if (is(SEMICOLON_TOK)) {
  182.             error("External semicolon ignored");
  183.             get_token();
  184.         }
  185.         else if (is(RCURLY_TOK)) {
  186.             error("External '}' ignored");
  187.             get_token();
  188.         }
  189.         else if (is(LCURLY_TOK)) {
  190.             error("Check program structure: { in outer context");
  191.             get_token();
  192.         }
  193.         else {
  194.             err3(    "'",
  195.                 pr_tok(),
  196.                 "' ignored: outer declaration expected");
  197.             get_token();
  198.         }
  199.     }
  200. }
  201.  
  202. /* =============== Local routines =============== */
  203.  
  204. /*
  205.     Skip over any special modifier keywords used by
  206.     Microsoft C or Turbo C.
  207.  
  208.     Turboc:     asm interrupt
  209.     Microsoft:  fortran 
  210.     Both:       cdecl, far, huge, near, pascal
  211. */
  212. void
  213. allow_mkeys(void)
  214. {
  215.     char * p;
  216.  
  217.     TRACETOK("allow_mkeys");
  218.  
  219.     p = &t_symbol[0];
  220.     while (is(ID_TOK)) {
  221.         if (    str_eq(p, "asm") ||
  222.             str_eq(p, "cdecl") ||
  223.             str_eq(p, "far") ||
  224.             str_eq(p, "fortran") ||
  225.             str_eq(p, "interrupt") ||
  226.             str_eq(p, "huge") ||
  227.             str_eq(p, "near") ||
  228.             str_eq(p, "pascal")
  229.         ) {
  230.             get_token();
  231.         }
  232.         else {
  233.             break;
  234.         }
  235.     }
  236.     RETURN_VOID("allow_mkeys");
  237. }
  238.  
  239.  
  240. /*
  241.     Parse a formal paramenter list.
  242.     This may be an old style list (id's only) or a new style list.
  243.     The opening paren has already been read.
  244. */
  245. static void
  246. fp_list(en_scope scope)
  247. {
  248.     bool no_tail;
  249.     en_scope this_scope;
  250.  
  251.     SL_NAME(fn_name, "fp_list");
  252.     TRACETOK(fn_name);
  253.     TRACEPN(fn_name, printf("(%s)\n", pr_scope(scope)));
  254.  
  255.     /* Set scope to NULL_SCOPE on recursive entry to this routines. */
  256.     if (    scope == NULL_SCOPE ||
  257.         scope == NEW_FORMAL_SCOPE ||
  258.         scope == OLD_FORMAL_SCOPE) {
  259.         this_scope = NULL_SCOPE;
  260.     }
  261.     else {
  262.         this_scope = NEW_FORMAL_SCOPE;
  263.     }
  264.  
  265.     while (!is(RPAREN_TOK)) {
  266.  
  267.         /* Parse the id (old style) or the dcl (new style) */
  268.         allow_mkeys();
  269.         if(is_type() || is(ID_TOK)) {
  270.             sd_dcl(this_scope);
  271.             no_tail = type_head(this_scope);
  272.             if (!no_tail) {
  273.                 type_tail(this_scope);
  274.             }
  275.             sd_end(this_scope, SEMICOLON_TOK);
  276.         }
  277.         else if (is(DOTS3)) {
  278.             /* Variable number of parameters. */
  279.             get_token();
  280.         }
  281.         else {
  282.             goto bad_list;
  283.         }
  284.  
  285.         if (is(COMMA_TOK)) {
  286.             get_token();
  287.         }
  288.         else if (is(RPAREN_TOK)) {
  289.             break;
  290.         }
  291.         else {
  292.             goto bad_list;
  293.         }
  294.     }
  295.  
  296.     /* Eat the closing paren. */
  297.     get_token();
  298.     RETURN_VOID(fn_name);
  299.  
  300. bad_list:
  301.     err3(  "Unexpected '",
  302.         pr_tok(),
  303.         "' seen in formal parameter list");
  304.     needend(RPAREN_TOK);
  305.     RETURN_VOID(fn_name);
  306. }
  307.  
  308. /*
  309.     Parse the old style of declaration of argument types.
  310. */
  311.  
  312. static void
  313. t_list(void)
  314. {
  315.     SL_NAME(fn_name, "t_list");
  316.     TRACETOK(fn_name);
  317.  
  318.     while(is_type()) {
  319.         dcl(OLD_FORMAL_SCOPE);
  320.     }
  321.  
  322.     RETURN_VOID(fn_name);
  323. }
  324.  
  325. /* Parse a list of declarations of array bounds. */
  326. static void
  327. array(void)
  328. {
  329.     SL_NAME(fn_name, "array");
  330.     TRACETOK(fn_name);
  331.  
  332.     while (is(LBRACK_TOK)) {
  333.         get_token();
  334.         if (is(RBRACK_TOK)) {
  335.             /* [] is valid as an array bounds (sometimes). */
  336.             get_token();
  337.         }
  338.         else {
  339.             con_expr(RBRACK_TOK);
  340.             need(RBRACK_TOK);
  341.         }
  342.     }
  343.     RETURN_VOID(fn_name);
  344. }
  345.  
  346. /*
  347.     Parse a function declaration or definition.
  348.     The opening '(' of the formal parameter list has alread been eaten.
  349. */
  350. void
  351. function(en_scope scope)
  352. {
  353.     SL_NAME(fn_name, "function");
  354.     TRACETOK(fn_name);
  355.     TRACEPN(fn_name, printf("(%s)\n", pr_scope(scope)));
  356.  
  357.     /* Make sure a function definition is valid here. */
  358.     if (scope == STRUCT_SCOPE) {
  359.         error("Function defined in struct or union");
  360.     }
  361.     else if (scope != OUTER_SCOPE) {
  362.         error("Nested function definition");
  363.     }
  364.     else if (prev_dcl > 0) {
  365.         warning("Function not expected here");
  366.     }
  367.  
  368.     /* Parse the old-style list of parameter types. */
  369.     t_list();
  370.  
  371.     /*
  372.         We have a function DEFINITION.
  373.         Indicate that '}' ends dcl instead of ';'
  374.         WARNING:  t_list won't work if func_def is TRUE.
  375.     */
  376.     func_def = TRUE;
  377.  
  378.     if (!is(LCURLY_TOK)) {
  379.         error("Expecting '{' following formal declarations");
  380.         RETURN_VOID(fn_name);
  381.     }
  382.  
  383.     /* Set the name of the current function. */
  384.     sd_func();
  385.  
  386.     /* Parse the body of the function. */
  387.     body();
  388.  
  389.     RETURN_VOID(fn_name);
  390. }
  391.  
  392. /* Parse an initializer. */
  393. static void
  394. initializer(void)
  395. {
  396.     SL_NAME(fn_name, "initializer");
  397.     TRACETOK(fn_name);
  398.  
  399.     if (is(LCURLY_TOK)) {
  400.         get_token();
  401.         i_list();
  402.         need(RCURLY_TOK);
  403.     }
  404.     else {
  405.         con_expr(SEMICOLON_TOK);
  406.     }
  407.     RETURN_VOID(fn_name);
  408. }
  409.  
  410. /* Parse a list of initializers. */
  411. static void
  412. i_list(void)
  413. {
  414.     SL_NAME(fn_name, "i_list");
  415.     TRACETOK(fn_name);
  416.  
  417.     for (;;) {
  418.  
  419.         /* Parse the next item in the list. */
  420.         if (is(LCURLY_TOK)) {
  421.             get_token();
  422.             i_list();
  423.             need(RCURLY_TOK);
  424.         }
  425.         else {
  426.             /* Allow { and } as delimiters. */
  427.             curly_ok_flag  = TRUE;
  428.             con_expr(COMMA_TOK);
  429.             curly_ok_flag = FALSE;
  430.         }
  431.  
  432.         /* Look for comma and/or '}'. */
  433.         if (is(COMMA_TOK)) {
  434.             get_token();
  435.  
  436.             /* Comma followed by '}' is valid. */
  437.             if (is(RCURLY_TOK)) {
  438.                 RETURN_VOID(fn_name);
  439.             }
  440.         }
  441.         else if (is(RCURLY_TOK)) {
  442.             RETURN_VOID(fn_name);
  443.         }
  444.         else {
  445.             err3(    "Unexpected end of initializer at '",
  446.                 pr_tok(),
  447.                 "'");
  448.             get_token();
  449.         }
  450.     }
  451. }
  452.  
  453. /*
  454.     Parse a type name and the closing paren.
  455.     The opening paren has already been eaten.
  456.  
  457.     Type names used in casts and sizeof expressions.
  458. */
  459. void
  460. type_name(void)
  461. {
  462.     SL_NAME(fn_name, "type_name");
  463.     TRACETOK(fn_name);
  464.  
  465.     type_head(NULL_SCOPE);
  466.     type_ntail();
  467.     need(RPAREN_TOK);
  468.  
  469.     RETURN_VOID(fn_name);
  470. }
  471.  
  472. static void
  473. type_ntail(void)
  474. {
  475.     bool paren_seen = FALSE;
  476.  
  477.     SL_NAME(fn_name, "type_ntail");
  478.     TRACETOK(fn_name);
  479.  
  480.     /* Count leading stars. */
  481.     allow_mkeys();
  482.     while (is(STAR_TOK)) {
  483.         get_token();
  484.     }
  485.  
  486.     /* Issue a warning for identifier. */
  487.     allow_mkeys();
  488.     if (is(ID_TOK)) {
  489.         /* 2/16/89 This is not a user mistake. */
  490.         /* -----
  491.         warning("Identifier in type name ignored");
  492.         ----- */
  493.         get_token();
  494.     }
  495.     else if (is(LPAREN_TOK)) {
  496.  
  497.         get_token();
  498.  
  499.         /* () or (type) denotes a param list. */
  500.         allow_mkeys();
  501.         if (is(RPAREN_TOK) || is_type()) {
  502.             paren_seen = TRUE;
  503.         }
  504.         else {
  505.             /* The assumed id is in here. */
  506.             type_ntail();
  507.             need(RPAREN_TOK);
  508.         }
  509.     }
  510.  
  511.     /* The "non-id" part:  the id has already been seen. */
  512.     if (paren_seen || is(LPAREN_TOK)) {
  513.         if (is(LPAREN_TOK)) {
  514.             get_token();
  515.         }
  516.         fp_list(NULL_SCOPE);
  517.     }
  518.     else if (is(LBRACK_TOK)) {
  519.         array();
  520.     }
  521.  
  522.     RETURN_VOID(fn_name);
  523. }
  524.  
  525. /*
  526.     Parse the common type portion of a declaration.
  527.  
  528.     Return TRUE if no tail is required because of
  529.         1.  struct\union.        struct tag {...};
  530.         2.  enum            enum hue {...}
  531.         3.  old-style formal parameter    f(g);
  532. */
  533. static bool
  534. type_head(en_scope scope)
  535. {
  536.     char * old_id;
  537.  
  538.     SL_NAME(fn_name, "type_head");
  539.     TRACETOK(fn_name);
  540.     TRACEPN(fn_name, printf("(%s)\n", pr_scope(scope)));
  541.  
  542.     /* Compensate for misspelled typedef id's. */
  543.     allow_mkeys();
  544.     if(is(ID_TOK) && !is_type()) {
  545.         /*
  546.             Depending on scope, we might have either
  547.             1.  a "bare" function definition or declaration or
  548.             2.  a misspelled typedef id or
  549.             3.  an old-style formal parameter.
  550.         */
  551.         old_id = str_alloc(t_symbol);
  552.         get_token();
  553.         if (    scope == NEW_FORMAL_SCOPE &&
  554.             (is(COMMA_TOK) || is(RPAREN_TOK)) 
  555.            ) {
  556.  
  557.             /* An old-style declaration. */
  558.             sd_id(scope, old_id);
  559.             m_free(old_id);
  560.             RETURN_BOOL(fn_name, TRUE);
  561.         }
  562.         else if (scope == OUTER_SCOPE && is(LPAREN_TOK)) {
  563.             /* Looks like a bare function def or dcl. */
  564.             get_token();
  565.             sd_id(scope, old_id);
  566.             m_free(old_id);
  567.             fp_list(scope);
  568.             if (is(LCURLY_TOK) || is_type()) {
  569.                 function(scope);
  570.                 RETURN_BOOL(fn_name, TRUE);
  571.             }
  572.         }
  573.         else if (is(ID_TOK) || is_type()) {
  574.             err2("Possibly misspelled typedef: ", old_id);
  575.             m_free(old_id);
  576.         }
  577.     }
  578.  
  579.     while (is_type() && !is(K_STRUCT) && !is(K_UNION) &&!is(K_ENUM)) {
  580.         if (is(K_TYPEDEF)) {
  581.             /* Set typedef flag. */
  582.             sd_typedef(scope);
  583.         }
  584.         else {
  585.             /* Base type or typedef. */
  586.             sd_htype(scope, token);
  587.             if (is(K_ENUM)) {
  588.                 break;
  589.             }
  590.         }
  591.         get_token();
  592.     }
  593.  
  594.     if (is(K_ENUM)) {
  595.         sd_htype(scope, token);
  596.         dcl_enum();
  597.         RETURN_BOOL(fn_name, is(SEMICOLON_TOK));
  598.     }
  599.     else if (is(K_STRUCT) || is(K_UNION)) {
  600.         sd_htype(scope, token);
  601.         dcl_struct();
  602.         RETURN_BOOL(fn_name, is(SEMICOLON_TOK));
  603.     }
  604.     else {
  605.         RETURN_BOOL(fn_name, FALSE);
  606.     }
  607. }
  608.  
  609. /*
  610.     Parse an enum.
  611. */
  612. static void
  613. dcl_enum(void)
  614. {
  615.     SL_NAME(fn_name, "dcl_enum");
  616.     TRACETOK(fn_name);
  617.  
  618.     /* Eat the enum. */
  619.     get_token();
  620.  
  621.     /* get the optional tag. */
  622.     allow_mkeys();
  623.     if (is(ID_TOK)) {
  624.         get_token();
  625.     }
  626.  
  627.     if (is(LCURLY_TOK)) {
  628.  
  629.         get_token();
  630.         for (;;) {
  631.             if (is(ID_TOK)) {
  632.                 get_token();
  633.             }
  634.             else {
  635.                 err3(    "Identifier expected at '",
  636.                     pr_tok(),
  637.                     "' in enum list");
  638.             }
  639.             if (is(ASSN_TOK)) {
  640.                 get_token();
  641.                 expr1(RCURLY_TOK);
  642.             }
  643.             if (is(COMMA_TOK)) {
  644.                 get_token();
  645.             }
  646.             else {
  647.                 break;
  648.             }
  649.         }
  650.         need(RCURLY_TOK);
  651.     }
  652.     RETURN_VOID(fn_name);
  653. }
  654.  
  655. /*
  656.     Parse a struct/union definition.
  657. */
  658. static void
  659. dcl_struct(void)
  660. {
  661.     SL_NAME(fn_name, "dcl_struct");
  662.     TRACETOK(fn_name);
  663.  
  664.     /* Eat the struct or union. */
  665.     get_token();
  666.  
  667.     /* get the optional tag. */
  668.     allow_mkeys();
  669.     if (is(ID_TOK)) {
  670.         get_token();
  671.     }
  672.  
  673.     /* Parse the optional definition. */
  674.     if (is(LCURLY_TOK)) {
  675.  
  676.         get_token();
  677.         allow_mkeys();
  678.         while (is_type() || is(ID_TOK)) {
  679.             dcl(STRUCT_SCOPE);
  680.         }
  681.         need(RCURLY_TOK);
  682.     }
  683.  
  684.     /* Parse a possible initializer. */
  685.     if (is(ASSN_TOK)) {
  686.         get_token();
  687.         initializer();
  688.     }
  689.     RETURN_VOID(fn_name);
  690. }
  691.  
  692. /*
  693.     Parse the part of the declaration after the type specifier.
  694.     Return the type of the tail or NULL_TOK.
  695. */
  696. static en_tokens
  697. type_tail(en_scope scope)
  698. {
  699.     en_tokens final_type = NULL_TOK;
  700.     en_tokens cur_type = NULL_TOK;
  701.  
  702.     SL_NAME(fn_name, "type_tail");
  703.     TRACETOK(fn_name);
  704.     TRACEPN(fn_name, printf("(%s)\n", pr_scope(scope)));
  705.  
  706.     /* Leading stars. */
  707.     allow_mkeys();
  708.     while (is(STAR_TOK)) {
  709.         sd_type(scope, STAR_TOK);
  710.         get_token();
  711.     }
  712.  
  713.     /* Optional const qualifier. */
  714.     allow_mkeys();
  715.     if (is(K_CONST)) {
  716.         get_token();
  717.     }
  718.  
  719.     /* An identifier ALWAYS ends the id part. */
  720.     allow_mkeys();
  721.     if (is(ID_TOK)) {
  722.         sd_id(scope, t_symbol);
  723.         get_token();
  724.     }
  725.     else if (is(LPAREN_TOK)) {
  726.         get_token();
  727.  
  728.         /* The id should be in here. */
  729.         final_type = type_tail(scope);
  730.         need(RPAREN_TOK);
  731.     }
  732.     else if (scope == STRUCT_SCOPE && is(COLON_TOK)) {
  733.  
  734.         /* bit field without id. */
  735.         get_token();
  736.         con_expr(SEMICOLON_TOK);
  737.         goto done;
  738.     }
  739.     /* Bug fix: 6/22/89 */
  740.     else if (scope != NEW_FORMAL_SCOPE && scope != NULL_SCOPE) {
  741.         err3("Id expected in declaration.  '", pr_tok(),
  742.         "' seen instead");
  743.         goto done;
  744.     }
  745.  
  746.     /* The "non-id" part:  the part containing the id has been seen. */
  747.     if (scope == STRUCT_SCOPE && is(COLON_TOK)) {
  748.  
  749.         /* Bit field after id. */
  750.         get_token();
  751.         con_expr(SEMICOLON_TOK);
  752.         goto done;
  753.     }
  754.  
  755.     for (;;) {
  756.         if (is(LPAREN_TOK)) {
  757.             get_token();
  758.  
  759.             /* Parse function declaration or function definition. */
  760.             if (final_type == NULL_TOK) {
  761.                 sd_type(scope, LPAREN_TOK);
  762.             }
  763.             fp_list(scope);
  764.             if (is(LCURLY_TOK) || is_type()) {
  765.                 function(scope);
  766.                 break;
  767.             }
  768.         }
  769.         else if (is(LBRACK_TOK)) {
  770.             /* Parse possible array subscripts. */
  771.             if (final_type == NULL_TOK) {
  772.                 sd_type(scope, LBRACK_TOK);
  773.             }
  774.             array();
  775.         }
  776.         else if (is(ASSN_TOK)) {
  777.             /* Parse possible initializer. */
  778.             get_token();
  779.             initializer();
  780.             break;
  781.         }
  782.         else {
  783.             break;
  784.         }
  785.     }
  786.  
  787. done:
  788.     if (final_type != NULL_TOK) {
  789.         RETURN_INT(fn_name, final_type);
  790.     }
  791.     else {
  792.         RETURN_INT(fn_name, cur_type);
  793.     }
  794. }
  795.