home *** CD-ROM | disk | FTP | other *** search
/ The C Users' Group Library 1994 August / wc-cdrom-cusersgrouplibrary-1994-08.iso / vol_300 / 357_01 / cstar1.exe / CSTAR.C < prev    next >
C/C++ Source or Header  |  1991-06-18  |  16KB  |  865 lines

  1. /*
  2.     C* Main routine
  3.  
  4.     source:  cstar.c
  5.     started: October 7, 1985
  6.     version: see below
  7.  
  8.     PUBLIC DOMAIN SOFTWARE
  9.  
  10.     The CSTAR program was placed in    the public domain on June 15, 1991,
  11.     by its author and sole owner,
  12.  
  13.         Edward K. Ream
  14.         1617 Monroe Street
  15.         Madison, WI 53711
  16.         (608) 257-0802
  17.  
  18.     CSTAR may be used for any commercial or non-commercial purpose.
  19.  
  20.     DISCLAIMER OF WARRANTIES
  21.  
  22.     Edward K. Ream (Ream) specifically disclaims all warranties,
  23.     expressed or implied, with respect to this computer software,
  24.     including but not limited to implied warranties of merchantability
  25.     and fitness for a particular purpose.  In no event shall Ream be
  26.     liable for any loss of profit or any commercial damage, including
  27.     but not limited to special, incidental consequential or other damages.
  28. */
  29. #include "cstar.h"
  30.  
  31. #define SIGNON "C Star: June 25, 1991\n"
  32.  
  33. #ifdef SHERLOCK
  34. #define USAGE "usage: csdb [++--routine] [options] in out\n"
  35. #else
  36. #define USAGE "usage: cs [options] in out\n"
  37. #endif
  38.  
  39. #define U1 "-d id=value  Define a preprocessor constant\n"
  40. #define U2 "-n           Allow nested C comments\n"
  41. #define U3 "-s path      Look for include files in path\n"
  42. #define U4 "-u id        Undefine a preprocessor constant\n"
  43. #define U5 "-?           Print the version number and exit\n\n"
  44.  
  45. #define U6  "-noparse  Suppress parsing\n"
  46. #define U7  "-nomacro  Suppress macro expansion\n"
  47. #define U8  "-nogen    Suppress code gen\n"
  48. #define U9  "-nopeep   Suppress peephole\n\n"
  49.  
  50. #define U10 "-tokens   Output tokens\n"
  51. #define U11 "-tree     Output parse tree\n"
  52. #define U12 "-code1    Output code list before peephole\n"
  53. #define U13 "-code2    Output code list after peephole\n"
  54.  
  55. static void t_init();
  56.  
  57. main(argc, argv)
  58. int argc;
  59. char **argv;
  60. {
  61.     char *in, *out, *arg;
  62.     char *def;
  63.     char *p1;
  64.     struct u_node *p;
  65.     int out_length;
  66.  
  67.     /* char *mg_alloc(); */
  68.  
  69.     /*
  70.         WARNING!!    Do not change the order of initializing
  71.                 the modules without CAREFUL thought.
  72.     */
  73.     SL_INIT();
  74.     mm_init();
  75.     sysinit();
  76.     SL_PARSE(argc, argv, "++", "--");
  77.  
  78.     /*
  79.         WARNING:  Putting the initializations here means we
  80.         can not trace any of the routines.
  81.  
  82.         On the other hand, mst_init() MUST be placed here
  83.         so we can define macros using the -d option.
  84.  
  85.         The call to mst2_init() must FOLLOW the gathering of
  86.         command line arguments so that the __line__ and __file__
  87.         macros may be disabled using the -u option.
  88.     */
  89.     t_init();
  90.     mst_init();
  91.     st_init();
  92.     pn_init();
  93.     gen_init();
  94.  
  95.     (void) syscsts();
  96.     TICK("main");
  97.  
  98.     /* Always put out the sign on message. */
  99.     printf("%s", SIGNON);
  100.  
  101.     /* Make first test for correct command line. */
  102.     if (argc == 2 && str_eq(argv[1], "-?")) {
  103.         exit(0);
  104.     }
  105.     else if (argc < 3) {
  106.         printf("\n%s\n%s%s%s%s%s%s",
  107.             USAGE, U1, U2, U3, U4, U5, U6);
  108.         printf("%s%s%s%s%s%s%s",
  109.             U7, U8, U9, U10, U11, U12, U13);
  110.         exit(0);
  111.     }
  112.  
  113.     /* No search paths active yet. */
  114.     n_paths = 0;
  115.  
  116.     /* Indicate that no file arguments have been seen yet. */
  117.     in  = NULL;
  118.     out = NULL;
  119.  
  120.     /* Options that don't [yet] have proper option flags */
  121.     TRACE("_noassoc", array_opt = 1;);
  122.     TRACE("local", no_local = 0;);
  123.  
  124.     /* Process all the arguments on the command line. */
  125.     argc--;
  126.     argv++;
  127.     while (argc-- > 0) {
  128.         arg = *argv++;
  129.  
  130.         if (str_eq(arg, "-code1")) {
  131.             code1_flag = TRUE;
  132.         }
  133.         else if (str_eq(arg, "-code2")) {
  134.             code2_flag = TRUE;
  135.         }
  136.         else if(str_eq(arg, "-d")) {
  137.             /* Define a variable. */
  138.             if (argc--) {
  139.                 arg = *argv++;
  140.                 /* Scan for an optional equal sign. */
  141.                 for (def = arg;    *def; def++) {
  142.                     if (*def == '=') {
  143.                         *def = '\0';
  144.                         def++;
  145.                         break;
  146.                     }
  147.                 }
  148.                 (void) mst_enter(arg, def, -1);
  149.             }
  150.             else {
  151.                 printf("Trailing -d\n");
  152.                 exit(0);
  153.             }
  154.         }
  155.         else if (str_eq(arg, "-f")) {
  156.             /* Full C option. */
  157.             full_c = TRUE;
  158.         }
  159.         else if (str_eq(arg, "-n")) {
  160.             /* Allow nested comments. */
  161.             nest_flag = TRUE;
  162.         }
  163.         else if (str_eq(arg, "-nogen")) {
  164.             nogen_flag = TRUE;
  165.         }
  166.         else if (str_eq(arg, "-nomacro")) {
  167.             nomacro_flag = TRUE;
  168.         }
  169.         else if (str_eq(arg, "-noparse")) {
  170.             noparse_flag = TRUE;
  171.         }
  172.         else if (str_eq(arg, "-nopeep")) {
  173.             nopeep_flag = TRUE;
  174.         }
  175.         else if (str_eq(arg, "-s")) {
  176.             /* Define a path. */
  177.             if (argc--) {
  178.                 arg = *argv++;
  179.                 if (n_paths >= MAX_PATHS) {
  180.                     printf("too many path names.\n");
  181.                     exit(0);
  182.                 }
  183.                 else {
  184.                     p1 = mg_alloc(strlen(arg)+2);
  185.                     str_cpy(p1, arg);
  186.                     if (arg[strlen(arg)-1] != '\\') {
  187.                         str_cat(p1, "\\");
  188.                     }
  189.                     paths [n_paths++] = p1;
  190.                 }
  191.             }
  192.             else {
  193.                 printf("Trailing -s.\n");
  194.                 exit(0);
  195.             }
  196.         }
  197.         else if (str_eq(arg, "-tokens")) {
  198.             token_flag = TRUE;
  199.         }
  200.         else if (str_eq(arg, "-tree")) {
  201.             tree_flag = TRUE;
  202.         }
  203.         else if(str_eq(arg, "-u")) {
  204.             /* Suppress the initial definition of a variable. */
  205.             if (argc--) {
  206.                 arg = *argv++;
  207.                 /* Put new u_node on global list. */
  208.  
  209.                 p = CAST(struct u_node *)
  210.                     mg_alloc(sizeof(struct u_node));
  211.                 p -> u_name = arg;
  212.                 p -> u_next = undef_list . u_next;
  213.                 undef_list . u_next = p;
  214.             }
  215.             else {
  216.                 printf("Trailing -u.\n");
  217.                 exit(0);
  218.             }
  219.         }
  220.         else if (str_eq(arg, "-?")) {
  221.             /* Ignore it. */
  222.         }
  223.         else if (in == NULL) {
  224.             in = arg;
  225.         }
  226.         else if (out == NULL) {
  227.             out = arg;
  228.         }
  229.         else {
  230.             printf("Extra file argument: %s\n", arg);
  231.             exit(0);
  232.         }
  233.     }
  234.  
  235.     /* Make sure that both file arguments were provided. */
  236.     if (in == NULL) {
  237.         printf("Missing input, output file arguments.\n");
  238.         exit(0);
  239.     }
  240.     else if (out == NULL) {
  241.         printf("Missing output file argument.\n");
  242.         exit(0);
  243.     }
  244.  
  245.     /* Open the input file. */
  246.     if (sysopen(in) == FALSE) {
  247.         printf("Can not open %s\n", in);
  248.         exit(0);
  249.     }
  250.  
  251.     /* Open the output file. */
  252.     if (syscreat(out) == FALSE) {
  253.         printf("Can not open %s\n", out);
  254.         sysabort();
  255.     }
  256.  
  257.     /*
  258.         Initialize the predefined macros (__line__ and __file__) here
  259.         so that they can be suppressed with the -u command line option.
  260.     */
  261.     mst2_init();
  262.     /*
  263.         Call regs_init() here so tracing +init_1, etc. will work.
  264.     */
  265.     regs_init();
  266.  
  267.     /* Start off at a new line. */
  268.     begin_line(TRUE);
  269.  
  270.     if (noparse_flag) {
  271.         out_length = 0;
  272.         do {
  273.             get_token();
  274.             if (token_flag) {
  275.                 out_length += strlen(ps_tok(t_type))+1;
  276.                 if (out_length >= 70) {
  277.                     sysnlput();
  278.                     out_length = 0;
  279.                 }
  280.                 syssput(ps_tok(t_type));
  281.                 syscput(' ');
  282.             }
  283.         }
  284.         while (t_type != EOP_TOK);
  285.     }
  286.     else {
  287.         /* Parse the program !! */
  288.         program();
  289.     }
  290.  
  291.     /* Close the output file. */
  292.     sysoclose();
  293.  
  294.     TRACE("dump", SL_DUMP());
  295.     TRACE("stat", mm_stat());
  296.  
  297.     sysend();
  298. }
  299.  
  300. /*
  301.     Ready the lex for execution.
  302. */
  303. static void
  304. t_init()
  305. {
  306.     TICK("t_init");
  307.  
  308.     t_iflevel  = 0;
  309.     t_errcount = 0;
  310. }
  311.  
  312. /*
  313.     Return the next token from the input file.  Set global variables
  314.     (see cpp.h for a list) describing the token and the current file.
  315. */
  316.  
  317. #ifdef SHERLOCK
  318. char bug_s1 [] = "get_token";
  319. char bug_s2 [] = "t_type %d, %s\n";
  320. #endif
  321.  
  322. /* CAUTION: evaluate value only once! */
  323. #define T_RETURN(value)\
  324.     t_type = value;\
  325.     TRACEP(bug_s1, printf(bug_s2, t_type, ps_tok(t_type)));\
  326.     return;
  327.  
  328. void
  329. get_token()
  330. {
  331.     unsigned char mesgbuf [40];
  332.     unsigned char cbuf [2];
  333.  
  334.     register struct mst_node * p;
  335.     struct mst_node * mst_lookup();
  336.  
  337.     TICK("get_token");
  338.     *t_symbol = '\0';
  339.  
  340.     /*
  341.         This is one of those situations where a 'goto' statement
  342.         probably makes the structure of a program clearer, not more
  343.         obscure.
  344.  
  345.         We branch to the 'rescan' label whenever a construct is seen
  346.         that does not result directly in a token being returned, i.e.,
  347.         for macros, PP directives and whitespace.
  348.     */
  349.  
  350. rescan:    switch (ch) {
  351.  
  352.     TICK("get_token1");
  353.  
  354.     case '\r':
  355.         sysnext();
  356.         goto rescan;
  357.  
  358.     case ' ':
  359.     case '\t':
  360.         TICK("get_token_ws");
  361.  
  362.         sysnext();
  363.         goto rescan;
  364.  
  365.     case '\n':
  366.         TICK("get_token_nl");
  367.         
  368.                 /* Allow user to abort here. */
  369.         (void) syscsts();
  370.  
  371.         sysnext();
  372.         do_nl();
  373.         begin_line(TRUE);
  374.         goto rescan;
  375.  
  376.     case '#':
  377.         t_error("unexpected # ignored");
  378.         sysnext();
  379.         goto rescan;
  380.  
  381.     case 'a': case 'b': case 'c': case 'd':
  382.     case 'e': case 'f': case 'g': case 'h':
  383.     case 'i': case 'j': case 'k': case 'l':
  384.     case 'm': case 'n': case 'o': case 'p':
  385.     case 'q': case 'r': case 's': case 't':
  386.     case 'u': case 'v': case 'w': case 'x':
  387.     case 'y': case 'z':
  388.     case '_':
  389.     case 'A': case 'B': case 'C': case 'D':
  390.     case 'E': case 'F': case 'G': case 'H':
  391.     case 'I': case 'J': case 'K': case 'L':
  392.     case 'M': case 'N': case 'O': case 'P':
  393.     case 'Q': case 'R': case 'S': case 'T':
  394.     case 'U': case 'V': case 'W': case 'X':
  395.     case 'Y': case 'Z':
  396.  
  397.         TICK("get_token_id");
  398.  
  399.         t_id(t_symbol);
  400.         if(is_reserved(t_symbol, t_length)) {
  401.             TRACE("get_token",
  402.             printf("get_token: reserved: t_type %s, %d, %d\n",
  403.                 t_symbol, t_type, t_subtype));
  404.             return;
  405.         }
  406.  
  407.         if (!nomacro_flag) {
  408.             p = mst_lookup(t_symbol);
  409.         }
  410.         else {
  411.             p = NULL;
  412.         }
  413.  
  414.         if (p == NULL) {
  415.             t_subtype = 0;
  416.             TRACE("get_token",
  417.             printf("get_token: id: t_type %s, %d/%d\n",
  418.                 t_symbol, ID_TOK, t_subtype));
  419.             t_type = ID_TOK;
  420.             return;
  421.         }
  422.         else {
  423.             /* Push back the replacement text. */
  424.             pp_expand(p -> mst_nargs, p -> mst_text);
  425.             goto rescan;
  426.         }
  427.  
  428.  
  429.     case '0': case '1': case '2': case '3': case '4':
  430.     case '5': case '6': case '7': case '8': case '9':
  431.  
  432.         T_RETURN(t_number());
  433.  
  434.  
  435.     case '"':
  436.         t_string(t_symbol);
  437.         T_RETURN(STRING_TOK);
  438.  
  439.     case '\'':
  440.         t_string(t_symbol);
  441.         t_value = (long) char_val(t_symbol);
  442.         T_RETURN(CHAR_TOK);
  443.  
  444.     /*
  445.         We must be VERY careful about exactly when we switch from one
  446.         input file to the next.  This is the place. 
  447.     */
  448.  
  449.     case END_FILE:
  450.  
  451.         /* Switch input streams. */
  452.         sysiclose();
  453.         if (t_inlevel == -1) {
  454.             T_RETURN(EOP_TOK);
  455.         }
  456.         else {
  457.             begin_line(TRUE);
  458.             goto rescan;
  459.         }
  460.  
  461.  
  462.     case '=':    /* = or == */
  463.  
  464.         sysnext();
  465.         if (ch == '=') {
  466.             sysnext();
  467.             T_RETURN(EQUAL_TOK);
  468.         }
  469.         else {
  470.             T_RETURN(ASSN_TOK);
  471.         }
  472.  
  473.  
  474.     case '+':    /* + or ++ or += */
  475.  
  476.         sysnext();
  477.         if (ch == '+') {
  478.             sysnext();
  479.             T_RETURN(INC_TOK);
  480.         }
  481.         else if (ch == '=') {
  482.             sysnext();
  483.             T_RETURN(PLUS_ASSN_TOK);
  484.         }
  485.         else {
  486.             T_RETURN(PLUS_TOK);
  487.         }
  488.  
  489.  
  490.     case '-':    /* - or -- or -> */
  491.  
  492.         sysnext();
  493.         if (ch == '=') {
  494.             sysnext();
  495.             T_RETURN(MINUS_ASSN_TOK);
  496.         }
  497.         else if (ch == '-') {
  498.             sysnext();
  499.             T_RETURN(DEC_TOK);
  500.         }
  501.         else if (ch == '>') {
  502.             sysnext();
  503.             T_RETURN(ARROW_TOK);
  504.         }
  505.         else {
  506.             T_RETURN(MINUS_TOK);
  507.         }
  508.  
  509.  
  510.     case '*':    /* * or *= */
  511.  
  512.         sysnext();
  513.         if (ch == '=') {
  514.             sysnext();
  515.             T_RETURN(STAR_ASSN_TOK);
  516.         }
  517.         else {
  518.             T_RETURN(STAR_TOK);
  519.         }
  520.  
  521.  
  522.     case '/':    /* comment or / or /= */
  523.  
  524.         sysnext();
  525.         if (ch == '*') {
  526.             sysnext();
  527.             t_comment();
  528.             goto rescan;
  529.         }
  530.         else if (ch == '=') {
  531.             sysnext();
  532.             T_RETURN(DIV_ASSN_TOK);
  533.         }
  534.         else {
  535.             T_RETURN(DIV_TOK);
  536.         }
  537.  
  538.  
  539.     case '%':    /* % or %= */
  540.  
  541.         sysnext();
  542.         if (ch == '=') {
  543.             sysnext();
  544.             T_RETURN(MOD_ASSN_TOK);
  545.         }
  546.         else {
  547.             T_RETURN(MOD_TOK);
  548.         }
  549.  
  550.  
  551.     case '>':    /* > or >= or >> or >>= */
  552.  
  553.         sysnext();
  554.         if (ch == '>') {
  555.             sysnext();
  556.             if (ch == '=') {
  557.                 sysnext();
  558.                 T_RETURN(RSHIFT_ASSN_TOK);
  559.             }
  560.             else {
  561.                 T_RETURN(RSHIFT_TOK);
  562.             }
  563.         }
  564.         else if (ch == '=') {
  565.             sysnext();
  566.             T_RETURN(GE_TOK);
  567.         }
  568.         else {
  569.             T_RETURN(GT_TOK);
  570.         }
  571.  
  572.  
  573.     case '<':    /* < or or <= or << or <<= */
  574.  
  575.         sysnext();
  576.         if (ch == '<') {
  577.             sysnext();
  578.             if (ch == '=') {
  579.                 sysnext();
  580.                 T_RETURN(LSHIFT_ASSN_TOK);
  581.             }
  582.             else {
  583.                 T_RETURN(LSHIFT_TOK);
  584.             }
  585.         }
  586.         else if (ch == '=') {
  587.             sysnext();
  588.             T_RETURN(LE_TOK);
  589.         }
  590.         else {
  591.             T_RETURN(LT_TOK);
  592.         }
  593.  
  594.  
  595.     case '!':    /* ! or != */
  596.  
  597.         sysnext();
  598.         if (ch == '=') {
  599.             sysnext();
  600.             T_RETURN(NE_TOK);
  601.         }
  602.         else {
  603.             T_RETURN(NOT_TOK);
  604.         }
  605.             
  606.  
  607.     case '|':    /* | or |= or || */
  608.  
  609.         sysnext();
  610.         if (ch == '=') {
  611.             sysnext();
  612.             T_RETURN(OR_ASSN_TOK);
  613.         }
  614.         else if (ch == '|') {
  615.             sysnext();
  616.             T_RETURN(LOR_TOK);
  617.         }
  618.         else {
  619.             T_RETURN(OR_TOK);
  620.         }
  621.  
  622.  
  623.     case '&':    /* & or &= or && */
  624.  
  625.         sysnext();
  626.         if (ch == '=') {
  627.             sysnext();
  628.             T_RETURN(AND_ASSN_TOK);
  629.         }
  630.         else if (ch == '&') {
  631.             sysnext();
  632.             T_RETURN(LAND_TOK);
  633.         }
  634.         else {
  635.             T_RETURN(AND_TOK);
  636.         }
  637.  
  638.  
  639.     case '^':    /* ^ or ^= */
  640.  
  641.         sysnext();
  642.         if (ch == '=') {
  643.             sysnext();
  644.             T_RETURN(XOR_ASSN_TOK);
  645.         }
  646.         else {
  647.             T_RETURN(XOR_TOK);
  648.         }
  649.  
  650.  
  651.     case '?':    sysnext();    T_RETURN(QUESTION_TOK);
  652.     case ':':    sysnext();    T_RETURN(COLON_TOK);
  653.  
  654.     case '~':    sysnext();    T_RETURN(TILDE_TOK);
  655.     case ',':    sysnext();    T_RETURN(COMMA_TOK);
  656.     case '(':    sysnext();    T_RETURN(LPAREN_TOK);
  657.     case ')':    sysnext();    T_RETURN(RPAREN_TOK);
  658.     case '[':    sysnext();    T_RETURN(LBRACK_TOK);
  659.     case ']':    sysnext();    T_RETURN(RBRACK_TOK);
  660.     case '{':    sysnext();    T_RETURN(LCURLY_TOK);
  661.     case '}':    sysnext();    T_RETURN(RCURLY_TOK);
  662.     case ';':    sysnext();    T_RETURN(SEMICOLON_TOK);
  663.     case '.':    sysnext();    T_RETURN(DOT_TOK);
  664.  
  665.     default:
  666.  
  667.         str_cpy(mesgbuf, "character error: ");
  668.         cbuf [0] = ch;
  669.         cbuf [1] = '\0';
  670.         str_cat(mesgbuf, cbuf);
  671.         t_error(mesgbuf);
  672.         sysnext();
  673.         goto rescan;
  674.     }
  675. }
  676.  
  677. #undef T_RETURN
  678.  
  679.  
  680. /*
  681.     Return the next token in a constant expression.
  682.     Return NULL on end of expression.
  683.     Return ERROR on mal-formed expression.
  684. */
  685.  
  686. int
  687. con_token()
  688. {
  689.     register struct mst_node * p;
  690.     struct mst_node * mst_lookup();
  691.  
  692.     TICK("con_token");
  693.  
  694.     /*
  695.         If you do not wish macros to be legal in #if statements,
  696.         just replace the following with:
  697.  
  698.             if (isid1(ch)) return ERROR;
  699.     */
  700.  
  701. rescan1:
  702.     if (isid1(ch)) {
  703.         t_id(t_symbol);
  704.         p = mst_lookup(t_symbol);
  705.         if (p == NULL) {
  706.             return ID_TOK;
  707.         }
  708.         else {
  709.             pp_expand(p -> mst_nargs, p -> mst_text);
  710.             goto rescan1;
  711.         }
  712.     }
  713.  
  714.     switch(ch) {
  715.  
  716.     case '\n':
  717.     case END_FILE:
  718.     case '#':
  719.  
  720.         /* Terminate the expression immediately. */
  721.         return ZERO;
  722.  
  723.  
  724.     case ' ':
  725.     case '\t':
  726.     case '\r':
  727.  
  728.         /* Ignore white space except for comments. */
  729.         sysnext();
  730.         goto rescan1;
  731.  
  732.  
  733.     case '\\':
  734.  
  735.         /* Allow continuation lines. */
  736.         sysnext();
  737.         if (ch == '\n') {
  738.             sysnext();
  739.             goto rescan1;
  740.         }
  741.         else {
  742.             return ERROR;
  743.         }
  744.  
  745.  
  746.     case '/':
  747.  
  748.         /* Do not allow comments. */
  749.         sysnext();
  750.         return (ch == '*') ? ERROR : DIV_TOK;
  751.  
  752.  
  753.     case '0': case '1': case '2': case '3': case '4':
  754.     case '5': case '6': case '7': case '8': case '9':
  755.  
  756.         (void) t_number();
  757.         return INT_TOK;        /* 1/10/86 */
  758.  
  759.  
  760.     case '\'':
  761.  
  762.         t_string(t_symbol);
  763.         t_value = (long) char_val(t_symbol);
  764.         return CHAR_TOK;
  765.  
  766.  
  767.     case '=':    /* == */
  768.  
  769.         sysnext();
  770.         if (ch == '=') {
  771.             sysnext();
  772.             return EQUAL_TOK;
  773.         }
  774.         else {
  775.             return ERROR;
  776.         }
  777.  
  778.  
  779.     case '!':    /* != */
  780.  
  781.         sysnext();
  782.         if (ch == '=') {
  783.             sysnext();
  784.             return NE_TOK;
  785.         }
  786.         else {
  787.             return ERROR;
  788.         }
  789.  
  790.  
  791.     case '>':    /* > or >= or >> */
  792.  
  793.         sysnext();
  794.         if (ch == '>') {
  795.             sysnext();
  796.             return RSHIFT_TOK;
  797.         }
  798.         else if (ch == '=') {
  799.             sysnext();
  800.             return GE_TOK;
  801.         }
  802.         else {
  803.             return GT_TOK;
  804.         }
  805.  
  806.  
  807.     case '<':    /* < or <= or << */
  808.  
  809.         sysnext();
  810.         if (ch == '<') {
  811.             sysnext();
  812.             return LSHIFT_TOK;
  813.         }
  814.         else if (ch == '=') {
  815.             sysnext();
  816.             return LE_TOK;
  817.         }
  818.         else {
  819.             return LT_TOK;
  820.         }
  821.  
  822.  
  823.     case '+':    sysnext();    return PLUS_TOK;
  824.     case '-':    sysnext();    return MINUS_TOK;
  825.     case '*':    sysnext();    return STAR_TOK;
  826.     case '%':    sysnext();    return MOD_TOK;
  827.     case '|':    sysnext();    return OR_TOK;
  828.     case '&':    sysnext();    return AND_TOK;
  829.     case '~':    sysnext();    return TILDE_TOK;
  830.     case '?':    sysnext();    return QUESTION_TOK;
  831.     case ':':    sysnext();    return COLON_TOK;
  832.     case '^':    sysnext();    return XOR_TOK;
  833.  
  834.     default:    return ERROR;
  835.     }
  836. }
  837.  
  838.  
  839. /*
  840.     Do beginning of line processing.
  841. */
  842. void
  843. begin_line(flag)
  844. int flag;
  845. {
  846.     TICK("begin_line");
  847.  
  848.     skip_bl();
  849.     if (flag && ch == '#') {
  850.         sysnext();
  851.         do_pp();
  852.     }
  853. }
  854.  
  855. /*
  856.     Do end of line processing.
  857. */
  858. void
  859. do_nl()
  860. {
  861.     t_line++;
  862.  
  863.     TRACEP("do_nl", printf("t_line: %d\n", t_line));
  864. }
  865.