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 / PAR.C < prev    next >
C/C++ Source or Header  |  1991-06-09  |  11KB  |  613 lines

  1. /*
  2.     New Sherlock preprocessor -- Parser Part I  (statements)
  3.  
  4.     source:  par.c
  5.     started: October 22, 1985
  6.     version:
  7.         July 15, 1988
  8.         February 16, 1989 error message start with upper case.
  9.  
  10.  
  11.     PUBLIC DOMAIN SOFTWARE
  12.  
  13.     Sherlock, including the SPP, SDEL and SDIF programs, was placed in
  14.     the public domain on June 15, 1991, by its author,
  15.  
  16.         Edward K. Ream
  17.         166 North Prospect Ave.
  18.         Madison, WI 53705.
  19.         (608) 257-0802
  20.  
  21.     Sherlock may be used for any commercial or non-commercial purpose.
  22.  
  23.  
  24.     DISCLAIMER OF WARRANTIES
  25.  
  26.     Edward K. Ream (Ream) specifically disclaims all warranties,
  27.     expressed or implied, with respect to this computer software,
  28.     including but not limited to implied warranties of merchantability
  29.     and fitness for a particular purpose.  In no event shall Ream be
  30.     liable for any loss of profit or any commercial damage, including
  31.     but not limited to special, incidental consequential or other damages.
  32. */
  33.  
  34. #include "spp.h"
  35.  
  36. /* Declare types of internal parsing routines. */
  37. static void    stat_list    (void);
  38. static bool    stat1        (void);
  39. static void    do_if        (void);
  40. static void    do_do        (void);
  41. static void    do_while    (void);
  42. static void    do_do        (void);
  43. static void    do_while    (void);
  44. static void    do_for        (void);
  45. static void    do_switch    (void);
  46. static void    do_break    (void);
  47. static void    do_continue    (void);
  48. static void    do_case        (void);
  49. static void    do_default    (void);
  50. static void    do_return    (void);
  51. static void    do_goto        (void);
  52. static void    do_label    (void);
  53.  
  54. static void    show_need    (char * s);
  55.  
  56. static void    ll_check    (void);
  57. static void    ll_enter    (char * s);
  58. static bool    ll_lookup    (char * s);
  59.  
  60. /* ========== Local data structures ========== */
  61.  
  62. static bool break_ok  = FALSE;    /* TRUE if break is allowed.    */
  63. static bool cont_ok   = FALSE;    /* TRUE if break is allowed.    */
  64. static bool in_switch = FALSE;    /* TRUE if in a switch.        */
  65.  
  66.  
  67. /* ========== Globally visible routines ========== */
  68.  
  69.  
  70. /*
  71.     Parse a block, including opening and closing braces.
  72.     This is NOT called to parse the block that comprises a function body.
  73. */
  74. void
  75. block(void)
  76. {
  77.     TRACETOK("block");
  78.  
  79.     must(LCURLY_TOK);
  80.     block_dcls();
  81.     stat_list();
  82.     need(RCURLY_TOK);
  83.  
  84.     LEAVE("block");
  85. }
  86.  
  87. /*
  88.     Parse a function body, including opening and closing braces.
  89. */
  90. void
  91. body(void)
  92. {
  93.     TRACETOK("body");
  94.  
  95.     must(LCURLY_TOK);
  96.  
  97.     /* All future definitions are local to the block. */
  98.     st_begin();
  99.  
  100.     /* Parse local declarations. */
  101.     block_dcls();
  102.  
  103.     /* Output the sherlock macro. */
  104.     so_entry();
  105.     
  106.     sf_1body();
  107.     stat_list();
  108.     sf_2body();
  109.  
  110.     /* Output a LEAVE() macro if we have fallen through the end. */
  111.     so_leave();
  112.  
  113.     need(RCURLY_TOK);
  114.  
  115.     /* Go back to global definitions. */
  116.     st_end();
  117.  
  118.     LEAVE("body");
  119. }
  120.  
  121. /*
  122.     Skip the current token if it is what we think it is.
  123. */
  124. void
  125. need(en_tokens tok)
  126. {
  127.     ENTER_TRACE("need", printf("(%d)\n", tok));
  128.  
  129.     if (token == tok) {
  130.         get_token();
  131.     }
  132.     else {
  133.         show_need(pr_op(tok));
  134.     }
  135.  
  136.     LEAVE("need");
  137. }
  138.  
  139. /*
  140.     Internal error if the token is not found.
  141.     Othewise, eat it.
  142. */
  143. void
  144. must(en_tokens expected)
  145. {
  146.     ENTER_TRACE("must", printf("(%d)\n", expected));
  147.  
  148.     if (token != expected) {
  149.         printf("<%s> expected, <%s> found\n",
  150.             pr_op(expected), pr_op(token));
  151.  
  152.         fatal("internal:  must");
  153.     }
  154.     else {
  155.         get_token();
  156.     }
  157.  
  158.     LEAVE("must");
  159. }
  160.  
  161. /*
  162.     error message about needed symbol
  163. */
  164. static void
  165. show_need(char * s)
  166. {
  167.     ENTER_TRACE("show_need", printf("(%s)\n", s));
  168.  
  169.     if (token == ID_TOK) {
  170.         err3(s, " expected at: ", t_symbol);
  171.     }
  172.     else if (pr_op(token)) {
  173.         err3(s, " expected at: ", pr_op(token));
  174.     }
  175.     else {
  176.         err2(s, " expected");
  177.     }
  178.  
  179.     LEAVE("show_need");
  180. }
  181.  
  182. /*
  183.     If the current token is tok, return TRUE and eat it.
  184.  
  185.     Otherwise find the next instance of tok, eat it, and return FALSE.
  186.     -- BUT --
  187.     Stop on and return an intervening semicolon or brace.
  188. */
  189.  
  190. bool
  191. needend(en_tokens tok)
  192. {
  193.     TRACETOK("needend");
  194.  
  195.     if (token == tok) {
  196.         get_token();
  197.         RETURN_INT("needend", TRUE);
  198.     }
  199.     show_need(pr_op(tok));
  200.  
  201.     for(;;) {
  202.         switch(token) {
  203.         case SEMICOLON_TOK:
  204.         case LCURLY_TOK:
  205.         case RCURLY_TOK:
  206.         case EOP_TOK:
  207.             RETURN_INT("needend", FALSE);
  208.         }
  209.         get_token();
  210.         if (token == tok) {
  211.             get_token();
  212.             RETURN_INT("needend", FALSE);
  213.         }
  214.     }
  215. }
  216.  
  217. /* ========== Internal Routines ========== */
  218.  
  219.  
  220. static void
  221. stat_list(void)
  222. {
  223.     TRACETOK("stat_list");
  224.  
  225.     while(stat1()) {
  226.         ;
  227.     }
  228.  
  229.     LEAVE("stat_list");
  230. }
  231.     
  232. /*
  233.     Parse a single statement.
  234.     Return TRUE if a statement was seen.
  235. */
  236. static bool
  237. stat1(void)
  238. {
  239.     TRACETOK("stat1");
  240.  
  241. loop:
  242.  
  243.     switch(token) {
  244.  
  245.     case EOP_TOK:
  246.     case RCURLY_TOK:
  247.         RETURN_INT("stat1", FALSE);
  248.  
  249.     case LCURLY_TOK:
  250.         block();
  251.         RETURN_INT("stat1", TRUE);
  252.  
  253.     case SEMICOLON_TOK:
  254.         get_token();
  255.         goto loop;
  256.  
  257.     case K_BREAK:     do_break();        RETURN_INT("stat1", TRUE);
  258.     case K_CASE:     do_case();        RETURN_INT("stat1", TRUE);
  259.     case K_CONTINUE: do_continue();        RETURN_INT("stat1", TRUE);
  260.     case K_DEFAULT:     do_default();        RETURN_INT("stat1", TRUE);
  261.     case K_DO:     do_do();        RETURN_INT("stat1", TRUE);
  262.     case K_FOR:     do_for();        RETURN_INT("stat1", TRUE);
  263.     case K_GOTO:     do_goto();        RETURN_INT("stat1", TRUE);
  264.     case K_IF:     do_if();        RETURN_INT("stat1", TRUE);
  265.     case K_SWITCH:     do_switch();        RETURN_INT("stat1", TRUE);
  266.     case K_WHILE:     do_while();        RETURN_INT("stat1", TRUE);
  267.     case K_RETURN:     do_return();        RETURN_INT("stat1", TRUE);
  268.  
  269.     case ID_TOK:
  270.         /* Do character-oriented lookahead. */
  271.         skip_bl();
  272.         if (ch == ':') {
  273.             do_label();
  274.             goto loop;
  275.         }
  276.  
  277.     default:
  278.         if (is_type()) {
  279.             error("Declaration in code: check brace structure");
  280.             RETURN_INT("stat1", FALSE);
  281.         }
  282.         else if (is_expr_tok()) {
  283.             sf_expr();
  284.             expr(SEMICOLON_TOK);
  285.             need(SEMICOLON_TOK);
  286.             RETURN_INT("stat1", TRUE);
  287.         }
  288.         else {
  289.             RETURN_INT("stat1", FALSE);
  290.         }
  291.     }
  292. }
  293.  
  294. /*
  295.     Parse complex statements.
  296. */
  297.  
  298. static void
  299. do_do(void)
  300. {
  301.     int oldcont;
  302.     int oldbrk;
  303.  
  304.     TRACETOK("do_do");
  305.  
  306.     oldcont  = cont_ok;    cont_ok  = TRUE;
  307.     oldbrk   = break_ok;    break_ok = TRUE;
  308.  
  309.     must(K_DO);
  310.     sf_1do();
  311.     stat1();
  312.     sf_2do();
  313.     need(K_WHILE);
  314.     need(LPAREN_TOK);
  315.     expr(RPAREN_TOK);
  316.     need(RPAREN_TOK);
  317.  
  318.     cont_ok  = oldcont;
  319.     break_ok = oldbrk;
  320.  
  321.     LEAVE("do_do");
  322. }
  323.  
  324. static void
  325. do_for(void)
  326. {
  327.     int oldcont;
  328.     int oldbrk;
  329.  
  330.     TRACETOK("do_for");
  331.  
  332.     oldcont = cont_ok;    cont_ok  = TRUE;
  333.     oldbrk  = break_ok;    break_ok = TRUE;
  334.  
  335.     must(K_FOR);
  336.     need(LPAREN_TOK);
  337.     expr(SEMICOLON_TOK);    need(SEMICOLON_TOK);
  338.     sf_1for(is(SEMICOLON_TOK));
  339.     expr(SEMICOLON_TOK);    need(SEMICOLON_TOK);
  340.     expr(RPAREN_TOK);    need(RPAREN_TOK);
  341.     stat1();
  342.     sf_2for();
  343.  
  344.     cont_ok  = oldcont;
  345.     break_ok = oldbrk;
  346.  
  347.     LEAVE("do_for");
  348. }
  349.  
  350. static void
  351. do_if(void)
  352. {
  353.     TRACETOK("do_if");
  354.  
  355.     must(K_IF);
  356.     need(LPAREN_TOK);
  357.     expr(RPAREN_TOK);
  358.     need(RPAREN_TOK);
  359.     sf_1if();
  360.     stat1();
  361.     if (token == K_ELSE) {
  362.         must(K_ELSE);
  363.         sf_2if();
  364.         stat1();
  365.     }
  366.     sf_3if();
  367.  
  368.     LEAVE("do_if");
  369. }
  370.  
  371. static void
  372. do_switch(void)
  373. {
  374.     int oldswitch;
  375.     int oldbrk;
  376.  
  377.     TRACETOK("do_switch");
  378.              
  379.     oldswitch = in_switch;    in_switch = TRUE;
  380.     oldbrk    = break_ok;    break_ok  = TRUE;
  381.  
  382.     must(K_SWITCH);
  383.     need(LPAREN_TOK);
  384.     expr(RPAREN_TOK);
  385.     need(RPAREN_TOK);
  386.     need(LCURLY_TOK);
  387.     sf_1switch();
  388.     stat_list();
  389.     sf_2switch();
  390.     need(RCURLY_TOK);
  391.  
  392.     in_switch = oldswitch;
  393.     break_ok  = oldbrk;
  394.  
  395.     LEAVE("do_switch");
  396. }
  397.  
  398. static void
  399. do_while(void)
  400. {
  401.     int oldcont;
  402.     int oldbrk;
  403.  
  404.     TRACETOK("do_while");
  405.  
  406.     oldcont = cont_ok;    cont_ok  = TRUE;
  407.     oldbrk  = break_ok;    break_ok = TRUE;
  408.  
  409.     must(K_WHILE);
  410.     need(LPAREN_TOK);
  411.     expr(RPAREN_TOK);
  412.     need(RPAREN_TOK);
  413.     sf_1while();
  414.     stat1();
  415.     sf_2while();
  416.  
  417.     cont_ok  = oldcont;
  418.     break_ok = oldbrk;
  419.  
  420.     LEAVE("do_while");
  421. }
  422.  
  423. /*
  424.     Parse subordinate statements.
  425. */
  426.  
  427. static void
  428. do_break(void)
  429. {
  430.     TRACETOK("do_break");
  431.  
  432.     if (!break_ok) {
  433.         error("'break' does not match any statement");
  434.     }
  435.  
  436.     sf_break();
  437.     must(K_BREAK);
  438.     need(SEMICOLON_TOK);
  439.  
  440.     LEAVE("do_break");
  441. }
  442.  
  443. static void
  444. do_case(void)
  445. {
  446.     TRACETOK("do_case");
  447.  
  448.     if (!in_switch) {
  449.         error("'case' appears outside of any switch");
  450.     }
  451.  
  452.     must(K_CASE);
  453.     con_expr(COLON_TOK);
  454.     need(COLON_TOK);
  455.  
  456.     LEAVE("do_case");
  457. }
  458.         
  459. static void
  460. do_continue(void)
  461. {
  462.     TRACETOK("do_continue");
  463.  
  464.     if (!cont_ok) {
  465.         error("'continue' appears outside do, while and if");
  466.     }
  467.  
  468.     must(K_CONTINUE);
  469.     need(SEMICOLON_TOK);
  470.  
  471.     LEAVE("do_continue");
  472. }
  473.  
  474. static void
  475. do_default(void)
  476. {
  477.     TRACETOK("do_default");
  478.  
  479.     /* Make sure we are in a switch statement. */
  480.     if (in_switch == NULL) {
  481.         error("'default' appears outside of a switch");
  482.     }
  483.  
  484.     sf_default();
  485.     must(K_DEFAULT);
  486.     need(COLON_TOK);
  487.  
  488.     LEAVE("do_default");
  489. }
  490.  
  491. static void
  492. do_goto(void)
  493. {
  494.     TRACETOK("do_goto");
  495.  
  496.     sf_goto();
  497.     must(K_GOTO);
  498.     need(ID_TOK);
  499.     needend(SEMICOLON_TOK);
  500.  
  501.     LEAVE("do_goto");
  502. }
  503.  
  504. static void
  505. do_label(void)
  506. {
  507.     ENTER("do_label");
  508.  
  509.  
  510.     sf_label();
  511.     must(ID_TOK);
  512.     need(COLON_TOK);
  513.  
  514.     LEAVE("do_label");
  515. }
  516.  
  517. static void
  518. do_return(void)
  519. {
  520.     TRACETOK("do_return");
  521.  
  522.     sf_return();
  523.     so_1exit();
  524.     must(K_RETURN);
  525.     if (token == SEMICOLON_TOK) {
  526.         so_2exit(FALSE);
  527.     }
  528.     else {
  529.         so_2exit(TRUE);
  530.         expr(SEMICOLON_TOK);
  531.     }
  532.     so_3exit();
  533.     need(SEMICOLON_TOK);
  534.  
  535.     LEAVE("do_return");
  536. }
  537.  
  538. /* =============== Label table routines =============== */
  539.  
  540. /* Define label list node. */
  541. static struct label_node {
  542.     struct label_node *    lab_next;
  543.     bool            lab_defined;
  544.     char *            lab_name;
  545. };
  546.  
  547. static struct label_node
  548.     ll_head = {NULL, FALSE, NULL};    /* Header node. */
  549.  
  550. /*
  551.     Check the local label list table to see if any labels
  552.     have been referenced but not defined.
  553.     This should be done at the end of each function.
  554. */
  555. static void
  556. ll_check(void)
  557. {
  558.     register struct label_node * p;
  559.  
  560.     ENTER("ll_check");
  561.  
  562.  
  563.  
  564.     for (p = ll_head.lab_next; p; p = p -> lab_next) {
  565.         if (p -> lab_defined == FALSE) {
  566.             err2("Undefined label: ", p -> lab_name);
  567.         }
  568.     }
  569.  
  570.     LEAVE("ll_check");
  571. }
  572.  
  573. /*
  574.     Enter a symbol in the local label list and mark it undefined.
  575. */
  576. static void
  577. ll_enter(char * symbol)
  578. {
  579.     register struct label_node * p;
  580.  
  581.     ENTER_TRACE("ll_enter", printf("(%s)\n", symbol));
  582.  
  583.     /* Make a new entry entry in the local label list. */
  584.     p = m_alloc(sizeof(struct label_node));
  585.     p -> lab_defined   = FALSE;
  586.     p -> lab_name      = str_alloc(symbol);
  587.  
  588.     /* Link it to the head of the list. */
  589.     p -> lab_next      = ll_head.lab_next;
  590.     ll_head.lab_next   = p;
  591.  
  592.     LEAVE("ll_enter");
  593. }
  594.  
  595. /*
  596.     Look up a symbol in the local label list.
  597. */
  598. static bool
  599. ll_lookup(char * symbol)
  600. {
  601.     register struct label_node * p;
  602.  
  603.     ENTER_TRACE("ll_lookup", printf("(%s)\n", symbol));
  604.     
  605.     for (p = ll_head.lab_next; p != NULL; p = p -> lab_next) {
  606.         if (str_eq(symbol, p -> lab_name)) {
  607.             RETURN_INT("ll_lookup", TRUE);
  608.         }
  609.     }
  610.  
  611.     RETURN_INT("ll_lookup", FALSE);
  612. }
  613.