home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 2 / Apprentice-Release2.iso / Tools / Languages / Harvest C 1.3 / Source Code / lextoken.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-06-15  |  24.2 KB  |  856 lines  |  [TEXT/ALFA]

  1. /*
  2.     Harvest C
  3.     Copyright 1992 Eric W. Sink.  All rights reserved.
  4.     
  5.     This file is part of Harvest C.
  6.     
  7.     Harvest C is free software; you can redistribute it and/or modify
  8.     it under the terms of the GNU Generic Public License as published by
  9.     the Free Software Foundation; either version 2, or (at your option)
  10.     any later version.
  11.     
  12.     Harvest C is distributed in the hope that it will be useful,
  13.     but WITHOUT ANY WARRANTY; without even the implied warranty of
  14.     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  15.     GNU General Public License for more details.
  16.     
  17.     You should have received a copy of the GNU General Public License
  18.     along with Harvest C; see the file COPYING.  If not, write to
  19.     the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
  20.     
  21.     Harvest C is not in any way a product of the Free Software Foundation.
  22.     Harvest C is not GNU software.
  23.     Harvest C is not public domain.
  24.  
  25.     This file may have other copyrights which are applicable as well.
  26.  
  27. */
  28.  
  29. /*
  30.  * Harvest C
  31.  * 
  32.  * Copyright 1991 Eric W. Sink   All rights reserved.
  33.  * 
  34.  * This file contains the lexical analyzer and preprocessor for Harvest C. The
  35.  * preprocessor is not implemented as a separate stage, but as layers within
  36.  * the lexer.
  37.  * 
  38.  * 
  39.  */
  40.  
  41.  
  42. #include "conditcomp.h"
  43. #include <stdio.h>
  44. #include <ctype.h>
  45. #include <time.h>
  46. #include <string.h>
  47. #include "structs.h"
  48.  
  49. #pragma segment LexToken
  50.  
  51. /*
  52.  * The ParseBuffer facilitates the parser's ability to put a token back if it
  53.  * decides it has read too many.
  54.  */
  55. int                             ParseBufferNdx = 0;
  56. struct PBnodeS                  ParseBuffer[16];
  57.  
  58. Codigo_t
  59. GetaToken()
  60. {                /* QQQQ routine too long ? */
  61.     /*
  62.      * This routine is a relatively high level routine.  It calls
  63.      * GetCharacter to obtain the input from the source file. It reads one
  64.      * token from the source input and return the kind of that token.  It
  65.      * leaves the token string in a global string ThisToken.
  66.      */
  67.     int                             ndx;
  68.     char                            c;
  69.     char                            c2;
  70.     int                             stop;
  71.     Codigo_t                        result;
  72.     ndx = 0;
  73.     stop = 0;
  74.     result = 0;
  75.     /*
  76.      * Note that the use of GetCharacter here for obtaining the first
  77.      * character of the next token implies that preprocessor directives have
  78.      * already been handled and that this character will not be a space.
  79.      */
  80.     c = GetCharacter();
  81.     if (gAllDone || PartDone)    /* This occurs if the SRC stack empties */
  82.     return -1;
  83.     /*
  84.      * First, we check if the character found is a keyword of its own.
  85.      */
  86.     ThisToken[0] = c;
  87.     ThisToken[1] = 0;
  88.     ndx = 1;
  89.     if (isKeyword(ThisToken)) {
  90.     /*
  91.      * If this single character is a keyword, then we keep expanding it
  92.      * by one character, to obtain the longest keyword possible. This is
  93.      * necessary so that != is not parsed as two tokens (for example).
  94.      * Note also, there are NO single character keywords which might also
  95.      * be identifiers.  Also, all operators which are composed of
  96.      * multiple characters have as their first character, a character
  97.      * which is also a keyword in itself. This is important, because this
  98.      * fragment here is the only opportunity for parsing of operator
  99.      * keywords. This list of valid keywords is in isKeyword().  This
  100.      * routine has a special check for the case of a + or - followed by a
  101.      * digit, in which case the prefix sign should NOT be parsed as a
  102.      * keyword, and the routine needs to fall down into the numeric
  103.      * constant part of this function.
  104.      */
  105.     /*
  106.      * This routine handles a unary plus or minus depending on the
  107.      * context, or the last token read.  QQQQ Perhaps, this should be
  108.      * handled by the parser itself, instead of here in the lexer. There
  109.      * IS an entry for unary plus and minus under unary_expr...
  110.      */
  111.     while (!stop) {
  112.         c = TokenCharacter();
  113.         if (!PartDone) {
  114.         ThisToken[ndx++] = c;
  115.         ThisToken[ndx] = 0;
  116.         if (!strcmp(ThisToken, "..")) {
  117.             ThisToken[ndx++] = c = TokenCharacter();
  118.             ThisToken[ndx] = 0;
  119.         }
  120.         stop = !isKeyword(ThisToken);
  121.         } else {
  122.         stop = 1;
  123.         ndx = 2;
  124.         c = 0;
  125.         }
  126.     }
  127.     ThisToken[ndx - 1] = 0;
  128.     PutBackChar(c);
  129.     c = 0;
  130.     result = isKeyword(ThisToken);
  131.     }
  132.     if ((!result) && c) {
  133.     if (isFirstIDChar(c)) {
  134.         ndx = 0;
  135.         ThisToken[ndx++] = c;
  136.         while (isAnyIDChar(c = TokenCharacter())) {
  137.         ThisToken[ndx++] = c;
  138.         }
  139.         ThisToken[ndx] = 0;
  140.         PutBackChar(c);
  141.         result = IDENTIFIER;
  142.         /*
  143.          * Now, we need to handle numeric constants (including floats,
  144.          * octal, hex, exponential, negative, etc...). The lexical
  145.          * parsing of numeric constants is very tricky now because of the
  146.          * expanded rules which ANSI specifies.  Constants may have a
  147.          * prefix sign, a suffix indicating its type, an exponent field
  148.          * (for float and double), and integers may be hex, octal or
  149.          * decimal.
  150.          */
  151. #ifdef OOPECC
  152.     } else if (c == '@') {
  153.         ndx = 0;
  154.         ThisToken[ndx++] = c;
  155.         while (isAnyIDChar(c = TokenCharacter())) {
  156.         ThisToken[ndx++] = c;
  157.         }
  158.         ThisToken[ndx] = 0;
  159.         PutBackChar(c);
  160.         result = isKeyword(ThisToken);    /* We assume that this is an
  161.                          * ObjC keyword, because it
  162.                          * cannot be a typedef name
  163.                          * of identifier (because it
  164.                          * begins with a @) */
  165. #endif
  166.     } else if (isdigit(c)) {
  167.         int                             numdone;
  168.         int                             nonnum;
  169.         int                             exponya;
  170.         int                             isoctal;
  171.         int                             ishex;
  172.         int                             base;
  173.         long                            intresult;
  174.         long double                     floatresult;
  175.         int                             expon;
  176.         int                             exponsign;
  177.         int                             isintresult;
  178.         isintresult = 1;
  179.         exponsign = 0;
  180.         expon = 0;
  181.         intresult = 0;
  182.         floatresult = 0;
  183.         base = 10;
  184.         isoctal = 0;
  185.         ishex = 0;
  186.         exponya = 0;
  187.         numdone = 0;
  188.         nonnum = 0;
  189.         ndx = 0;
  190.  
  191.         ThisToken[ndx++] = c;
  192.         if (isdigit(c)) {
  193.         intresult = (c - '0');
  194.         }
  195.         /* We first check for octal. */
  196.         if (c == '0') {
  197.         c2 = TokenCharacter();
  198.         if (c2 == 'x') {
  199.             ishex = 1;
  200.             base = 16;
  201.             ThisToken[ndx++] = 'x';
  202.             while (ishexdigit(c = TokenCharacter())) {
  203.             ThisToken[ndx++] = c;
  204.             intresult = intresult * base + hexvalue(c);
  205.             }
  206.             PutBackChar(c);
  207.             nonnum = 1;
  208.         } else if (c2 == '.') {
  209.             PutBackChar(c2);
  210.         } else {
  211.             isoctal = 1;
  212.             base = 8;
  213.             PutBackChar(c2);
  214.             while (isoctaldigit(c = TokenCharacter())) {
  215.             ThisToken[ndx++] = c;
  216.             intresult = intresult * base + (c - '0');
  217.             }
  218.             PutBackChar(c);
  219.             nonnum = 1;
  220.         }
  221.         }
  222.         /* Below, deals with floats and type suffices. */
  223.         while (!numdone) {
  224.         c = TokenCharacter();
  225.         if ((!nonnum) && isdigit(c)) {
  226.             ThisToken[ndx++] = c;
  227.             intresult = intresult * base + (c - '0');
  228.         } else {
  229.             nonnum = 1;
  230.             switch (c) {
  231.             case '.':
  232.             case 'e':
  233.             case 'E':
  234.             /* This is now a floating point constant. */
  235.             if (ishex || isoctal) {
  236.                 LexError("No floating hex or octal constants");
  237.                 break;
  238.             }
  239.             floatresult = intresult;
  240.             isintresult = 0;
  241.             if (c != '.') {
  242.                 ThisToken[ndx++] = c;
  243.             } else {
  244.                 double                          digitval;
  245.                 ThisToken[ndx++] = c;
  246.                 digitval = 1;
  247.                 while (isdigit(c = TokenCharacter())) {
  248.                 ThisToken[ndx++] = c;
  249.                 digitval = digitval / base;
  250.                 floatresult = floatresult + (c - '0') * digitval;
  251.                 }
  252.             }
  253.             switch (c) {
  254.                 /* Exponential fields must be handled here. */
  255.             case 'e':
  256.             case 'E':
  257.                 if (exponya) {
  258.                 LexError("FP constants may not have two exp fields");
  259.                 } else {
  260.                 exponya = 1;
  261.                 ThisToken[ndx++] = 'E';
  262.                 c = TokenCharacter();
  263.                 if ((c == '+') || (c == '-')) {
  264.                     ThisToken[ndx++] = c;
  265.                     exponsign = -1;
  266.                 }
  267.                 while (isdigit(c = TokenCharacter())) {
  268.                     ThisToken[ndx++] = c;
  269.                     expon = expon * base + (c - '0');
  270.                 }
  271.                 PutBackChar(c);
  272.                 if (exponsign == -1) {
  273.                     expon = -expon;
  274.                 }
  275.                 floatresult = floatresult * Eintpower(base, expon);
  276.                 }
  277.                 break;
  278.             case 'f':
  279.             case 'F':
  280.                 ThisToken[ndx++] = 'F';
  281.                 numdone = 1;
  282.                 break;
  283.             case 'l':
  284.             case 'L':
  285.                 ThisToken[ndx++] = 'L';
  286.                 numdone = 1;
  287.                 break;
  288.             case '.':
  289.                 if (exponya) {
  290.                 LexError("FP constants may not have decimal pts in exp fields");
  291.                 } else {
  292.                 LexError("FP constants may not have 2 decimal points");
  293.                 }
  294.                 numdone = 1;
  295.                 break;
  296.             default:
  297.                 numdone = 1;
  298.                 PutBackChar(c);
  299.             }
  300.             break;
  301.             case 'u':
  302.             case 'U':
  303.             ThisToken[ndx++] = 'U';
  304.             c = TokenCharacter();
  305.             if ((c == 'l') || (c == 'L')) {
  306.                 ThisToken[ndx++] = 'L';
  307.             } else {
  308.                 PutBackChar(c);
  309.             }
  310.             numdone = 1;
  311.             break;
  312.             case 'l':
  313.             case 'L':
  314.             ThisToken[ndx++] = 'L';
  315.             c = TokenCharacter();
  316.             if ((c == 'u') || (c == 'U')) {
  317.                 ThisToken[ndx++] = 'U';
  318.             } else {
  319.                 PutBackChar(c);
  320.             }
  321.             numdone = 1;
  322.             break;
  323.             default:
  324.             PutBackChar(c);
  325.             numdone = 1;
  326.             }
  327.         }
  328.         }
  329.         ThisToken[ndx] = 0;
  330.         if (isintresult) {
  331.         LastIntegerConstant = intresult;
  332.         result = INTCONSTANT;
  333.         } else {
  334.         LastFloatingConstant = floatresult;
  335.         result = FLOATCONSTANT;
  336.         }
  337.     } else if (c == '\"') {
  338.         int                             ispascalstring = 0;
  339.         int                             skipchar = 0;
  340.         /*
  341.          * This will be a string literal.  Note that the handling of
  342.          * string literals is very tricky because of the special rules
  343.          * for what may appear inside. We used PreProcCharacter() to
  344.          * fetch characters within the string literal because spaces are
  345.          * significant. Also, this fragment handles escape constants.
  346.          */
  347.         ndx = 0;
  348.         while ((c = PreProcCharacter()) != '\"') {
  349.         if (c == '\\') {
  350.             c = PreProcCharacter();
  351.             if ((ndx == 0) && (c == 'p')) {
  352.             ispascalstring = 1;
  353.             skipchar = 1;
  354.             } else
  355.             c = EscapeConvert(c);
  356.         }
  357.         if (!skipchar)
  358.             ThisToken[ndx++] = c;
  359.         skipchar = 0;
  360.         if (ndx >= MAXIDLENGTH) {
  361.             LexError("String Literal too long");
  362.             break;
  363.         }
  364.         }
  365.         ThisToken[ndx] = 0;
  366.         if (ispascalstring)
  367.         result = PASCSTRING_LITERAL;
  368.         else
  369.         result = STRING_LITERAL;
  370.     } else if (c == '\'') {
  371.         /*
  372.          * This is a character constant.  We will allow multi-character
  373.          * constants, for the Macintosh.  The limit will probably be
  374.          * four.  Much of this fragment is identical to that above for
  375.          * string literals.
  376.          */
  377.         long                            intresult;
  378.         int                             countconstant;
  379.         countconstant = 0;
  380.         intresult = 0;
  381.         ndx = 0;
  382.         while ((c = PreProcCharacter()) != '\'') {
  383.         if (c == '\\') {
  384.             c = PreProcCharacter();
  385.             c = EscapeConvert(c);
  386.         }
  387.         intresult = intresult * MAXUNSIGNEDCHAR + c;
  388.         countconstant++;
  389.         ThisToken[ndx++] = c;
  390.         }
  391.         ThisToken[ndx] = 0;
  392.         if (countconstant) {
  393.         if (countconstant != 1) {
  394.             UserWarning(WARN_multicharconstant);
  395.         }
  396.         } else {
  397.         LexError("Empty character constant");
  398.         }
  399.         LastIntegerConstant = intresult;
  400.         result = CHARCONSTANT;
  401.     } else {
  402.         /*
  403.          * Whatever character arrived here should not have done so.
  404.          */
  405.         FatalError("Illegal character for start of token");
  406.     }
  407.     }
  408.     if (PartDone && !result)
  409.     return -1;
  410.     LastTokenKind = result;
  411.     return result;
  412. }
  413.  
  414. Codigo_t
  415. GetToken()
  416. {
  417.     /*
  418.      * This routine is the preprocessor interface to GetaToken. It simply has
  419.      * the function of returning a valid C token to its caller, handling
  420.      * macro expansion at the same time. It is this routine that is called by
  421.      * the Parser.
  422.      */
  423.     register Codigo_t               tok;
  424.     register Codigo_t               result;
  425.     register PPSYMVia_t             def;
  426.     /*
  427.      * First, check the Parse Buffer for any old tokens lying around.
  428.      */
  429.     if (ParseBufferNdx) {
  430.     LastToken = ParseBuffer[--ParseBufferNdx].token;
  431.     LastTokenKind = ParseBuffer[ParseBufferNdx].tokval;
  432.     LastFloatingConstant = ParseBuffer[ParseBufferNdx].floating;
  433.     LastIntegerConstant = ParseBuffer[ParseBufferNdx].integer;
  434.     result = LastTokenKind;
  435.     return result;
  436.     }
  437.     /* QQQQ Is there a valid reason for not checking the PB here ? */
  438.     result = 0;
  439.     while (!result) {
  440.     tok = GetaToken();
  441.     if (gAllDone || (tok == -1))
  442.         return -1;
  443.     /*
  444.      * PPStatus is true when tokens are to be ignored due to conditional
  445.      * compilation directives.
  446.      */
  447.     while (PPStatus && (tok != -1)) {
  448.         tok = GetaToken();
  449.     }
  450.     if (gAllDone || (tok == -1))
  451.         return -1;
  452.     if (tok == IDENTIFIER) {
  453.         /*
  454.          * Check the defined macro list to see if something needs to be
  455.          * expanded or substituted here
  456.          */
  457.         /*
  458.          * The following special macros are defined, according to ANSI:
  459.          * __LINE__ __FILE__ __DATE__ __TIME__ defined
  460.          */
  461.         if ((def = isDefined(ThisToken)) != 0) {
  462.         register SymListVia_t           parmnames;
  463.         char                            TempName[128];    /* MAXIDLENGTH */
  464.         CurrentSRC.PreprocSubsts++;
  465.         if (GetPPSymArgCount(def)) {
  466.             /*
  467.              * First we parse the arguments and place them into
  468.              * parmnames symbol list
  469.              */
  470.  
  471.             int                             PrevCharCount;
  472.             PrevCharCount = CurrentSRC.CharCount;
  473.             tok = GetaToken();
  474.             if (tok != '(') {
  475.             PreprocError2("Macro call without parenthesis ", ThisToken);
  476.             } else {
  477.             int                             doneargs;
  478.             int                             currentarg;
  479.             register int                    charndx;
  480.             char                            c;
  481.             int                             parens;
  482.             doneargs = 0;
  483.             currentarg = 0;
  484.             charndx = 0;
  485.             parmnames = RawTable(11);
  486.             parens = 0;
  487.             while (!doneargs) {
  488.                 c = TokenCharacter();
  489.                 if (c == ',' && !parens) {
  490.                 TempName[charndx] = 0;
  491.                 TableAdd(parmnames, TempName);
  492.                 charndx = 0;
  493.                 currentarg++;
  494.                 } else if (c == ')') {
  495.                 parens--;
  496.                 if (parens == -1) {
  497.                     TempName[charndx] = 0;
  498.                     TableAdd(parmnames, TempName);
  499.                     doneargs = 1;
  500.                 } else {
  501.                     TempName[charndx] = c;
  502.                     charndx++;
  503.                 }
  504.                 } else if (c == '(') {
  505.                 parens++;
  506.                 TempName[charndx] = c;
  507.                 charndx++;
  508.                 } else {
  509.                 TempName[charndx] = c;
  510.                 charndx++;
  511.                 }
  512.             }
  513.             /*
  514.              * Now we have all the arguments inserted into the
  515.              * parmnames symbol table.
  516.              */
  517.             CurrentSRC.PreprocBefore += (CurrentSRC.CharCount - PrevCharCount);
  518.             if (currentarg != (GetPPSymArgCount(def) - 1)) {
  519.                 char                            nm[64];
  520.                 GetPPSymName(def, nm);
  521.                 PreprocError2("Wrong number of arguments to macro func ", nm);
  522.             } else {
  523.                 /*
  524.                  * Now, we must substitute macro parameters in
  525.                  * for the names of the parameters of the macro
  526.                  * function in def. In the previous attmpt, we
  527.                  * simply #defined all the values, in order to
  528.                  * avoid having to parse the macro value field
  529.                  * separately, but that turned out to be a real
  530.                  * mess (NeedtoKill,KillArgs,isParam,infinite
  531.                  * loops,duplicate entries in the macro list,
  532.                  * addmacroparam, etc...) What we will do here is
  533.                  * to create a string to hold this mess, and make
  534.                  * that string the current SRC.  A single new
  535.                  * field in CurrentSRC will allow the memory for
  536.                  * the string to be freed upon completion.
  537.                  */
  538.                 EString_t                       Val;
  539.                 int                             ndx;
  540.                 EString_t                       theval;
  541.                 int                             Valndx;
  542.                 char                            ArgName[128];    /* MAXIDLENGTH */
  543.                 int                             quotenext;
  544.                 int                             eatspace;
  545.                 int                             argndx;
  546.                 int                             paramfound;
  547.                 ndx = 0;
  548.                 Val = Ealloc(MAXMACROLENGTH);
  549.                 /* Build the string into Val here */
  550.                 /*
  551.                  * Begin searching
  552.                  * Via(def)->Definition.PreProcValue for
  553.                  * identifiers which are parameters of the macro
  554.                  * function.  Whenever an identifier is found, if
  555.                  * it is a parameter, replace it with the correct
  556.                  * argument from parmnames.
  557.                  */
  558.                 doneargs = 0;
  559.                 ndx = argndx = Valndx = quotenext = eatspace = 0;
  560.                 theval = GetPPSymValue(def);
  561.                 while (!doneargs) {
  562.                 c = Via(theval)[ndx++];
  563.                 /*
  564.                  * According to ANSI, there are two special
  565.                  * operators used in macro expansion.  The #
  566.                  * operator, when it precedes a parameter,
  567.                  * causes the argument for that parameter to
  568.                  * be surrounded by quotes after expansion.
  569.                  * The ## operator, consumes whitespace
  570.                  * surrounding it, thus allowing the
  571.                  * preprocessor to construct tokens by
  572.                  * concatenation.
  573.                  */
  574.                 if (c == '#') {
  575.                     if (Via(theval)[ndx] != '#')
  576.                     quotenext = 1;
  577.                     else {
  578.                     /*
  579.                      * Here, we must eat white space to
  580.                      * concatenate tokens...
  581.                      */
  582.                     while (isspace(Via(Val)[Valndx - 1])) {
  583.                         Valndx--;
  584.                     }
  585.                     eatspace = 1;
  586.                     ndx++;
  587.                     }
  588.                 } else if (isFirstIDChar(c)) {
  589.                     /*
  590.                      * We have found the beginning of an
  591.                      * identifier.
  592.                      */
  593.                     ArgName[argndx = 0] = c;
  594.                     argndx++;
  595.                     while (isFirstIDChar(Via(theval)[ndx++])) {
  596.                     ArgName[argndx++] = Via(theval)[ndx - 1];
  597.                     }
  598.                     ArgName[argndx] = 0;
  599.                     ndx--;
  600.                     /*
  601.                      * Now, we have an identifier in ArgName,
  602.                      * which may or may not be a parameter of
  603.                      * the macro function.
  604.                      */
  605.                     paramfound = -1;
  606.                     paramfound = PPSymSearchArgNum(def, ArgName);
  607.                     if (!paramfound) {
  608.                     paramfound = -1;
  609.                     }
  610.                     Via(Val)[Valndx] = 0;
  611.                     /*
  612.                      * The parameter list for the macro
  613.                      * function has been searched. paramfound
  614.                      * holds the ndx of the parameter found
  615.                      * or -1 if the search failed.
  616.                      */
  617.                     if (paramfound > -1) {
  618.                     int                             eatspot;
  619.                     /*
  620.                      * Now, we substitute the argument
  621.                      * for the parameter.
  622.                      */
  623.                     char                           *tempptr = NULL;
  624.                     SYMVia_t                        searchres;
  625.                     searchres = TableGetNum(parmnames, paramfound);
  626.                     assert(searchres);
  627.                     tempptr = Via(searchres)->name;
  628.                     if (quotenext) {
  629.                         Via(Val)[Valndx] = '\"';
  630.                         Via(Val)[++Valndx] = 0;
  631.                     }
  632.                     eatspot = 0;
  633.                     if (eatspace) {
  634.                         while (isspace((tempptr)[eatspot]))
  635.                         eatspot++;
  636.                     }
  637.                     strcat(Via(Val), &((tempptr)[eatspot]));
  638.                     Valndx += strlen((tempptr));
  639.                     if (quotenext) {
  640.                         Via(Val)[Valndx] = '\"';
  641.                         Via(Val)[++Valndx] = 0;
  642.                         quotenext = 0;
  643.                     }
  644.                     eatspace = 0;
  645.                     } else {
  646.                     /*
  647.                      * In this case, the identifier we
  648.                      * previously found was NOT a
  649.                      * parameter.  We therefore pass it
  650.                      * into the Val string unchanged.
  651.                      */
  652.                     strcat(Via(Val), ArgName);
  653.                     Valndx += strlen(ArgName);
  654.                     }
  655.                 } else {
  656.                     /*
  657.                      * This means that the character
  658.                      * (obtained from the macro value tmplate
  659.                      * Via(def)->Definition.PreProcValue) was
  660.                      * not a FirstIDChar, nor was it a '#'
  661.                      * (indicating a preprocessor expansion
  662.                      * operator).
  663.                      */
  664.                     if (c) {
  665.                     if (!(eatspace && isspace(c)))
  666.                         Via(Val)[Valndx++] = c;
  667.                     } else {
  668.                     doneargs = 1;
  669.                     Via(Val)[Valndx] = 0;
  670.                     }
  671.                 }
  672.                 }
  673.  
  674.                 /*
  675.                  * Now, the expanded string has been constructed
  676.                  * in Val, and it will become the current SRC.
  677.                  */
  678.                 CurrentSRC.PreprocAfter += strlen(Via(Val));
  679.                 PushSRC();
  680.                 CurrentSRC.NeedtoKill = Val;
  681.                 CurrentSRC.Macro = def;
  682.                 CurrentSRC.isIO = 0;
  683.                 CurrentSRC.where.mem = Val;
  684.  
  685.                 result = GetToken();
  686.             }
  687.             }
  688.         } else {
  689.             /*
  690.              * Substitution for defined symbols is accomplished by
  691.              * pointing the current SRC to a string in memory.
  692.              */
  693.             char                            nm[64];
  694.             GetPPSymName(def, nm);
  695.             CurrentSRC.PreprocBefore += strlen(nm);
  696.             if (GetPPSymValue(def)) {
  697.             CurrentSRC.PreprocAfter += GetPPSymValueLength(def);
  698.             }
  699.             PushSRC();
  700.             CurrentSRC.isIO = 0;
  701.             CurrentSRC.NeedtoKill = NULL;
  702.             CurrentSRC.Macro = def;
  703.             CurrentSRC.where.mem = GetPPSymValue(def);
  704.             CurrentSRC.memindex = 0;
  705.             CurrentSRC.alreadyincluded = NULL;
  706.             CurrentSRC.NumExtras = 0;
  707.  
  708.             result = GetToken();
  709.         }
  710.         } else if (!strcmp(ThisToken, "__LINE__")) {
  711.         sprintf(ThisToken, "%d", CurrentSRC.LineCount);
  712.         result = INTCONSTANT;
  713.         LastIntegerConstant = CurrentSRC.LineCount;
  714.         } else if (!strcmp(ThisToken, "__FILE__")) {
  715.         strcpy(ThisToken, CurrentSRC.fname);
  716.         result = STRING_LITERAL;
  717.         } else if (!strcmp(ThisToken, "__DATE__")) {
  718.         time_t                          thetime;
  719.         thetime = time(NULL);
  720.         strftime(ThisToken,
  721.              MAXIDLENGTH, "%b %d %Y", localtime(&thetime));
  722.         result = STRING_LITERAL;
  723.         } else if (!strcmp(ThisToken, "__TIME__")) {
  724.         time_t                          thetime;
  725.         thetime = time(NULL);
  726.         strftime(ThisToken,
  727.              MAXIDLENGTH, "%H:%M:%S", localtime(&thetime));
  728.         result = STRING_LITERAL;
  729.         } else {
  730.         /*
  731.          * Now, determine if ThisToken contains a keyword,
  732.          * typedefname, or identifier
  733.          */
  734.         result = isKeyword(ThisToken);
  735.         if (result) {
  736.         } else {
  737.             result = (int) isTypedefName(ThisToken) ? TYPEDEF_NAME : 0;
  738.             if (!result) {
  739.             result = IDENTIFIER;
  740.             }
  741.         }
  742.         }
  743.     } else {
  744.         result = tok;
  745.     }
  746.     }
  747.     /*
  748.      * The fragment below handles the concatenation of adjacent string
  749.      * literals by the preprocessor. QQQQ This routine fails to work
  750.      * correctly if the string literal is the very last token in the file. Of
  751.      * course, with legal C code being parsed, this should NEVER happen.
  752.      */
  753.     if ((result == STRING_LITERAL) || (result == PASCSTRING_LITERAL)) {
  754.     int                             wasresult;
  755.     int                             donestrings;
  756.     char                            holdtoken[MAXIDLENGTH];
  757.     wasresult = result;
  758.     donestrings = 0;
  759.     strcpy(holdtoken, ThisToken);
  760.     while (!donestrings) {
  761.         result = GetToken();
  762.         if ((result == STRING_LITERAL) || (result ==
  763.                            PASCSTRING_LITERAL)) {
  764.         if ((strlen(holdtoken) + strlen(LastToken)) >= MAXIDLENGTH) {
  765.             LexError("String literal too long after concatenation");
  766.         }
  767.         strcat(holdtoken, LastToken);
  768.         } else {
  769.         PutBackToken(LastToken, result);
  770.         strcpy(ThisToken, holdtoken);
  771.         result = wasresult;
  772.         donestrings = 1;
  773.         }
  774.     }
  775.     }
  776.     LastTokenKind = result;
  777.     LastToken = ThisToken;
  778.     return result;
  779. }
  780.  
  781. int
  782. NextIs(Codigo_t val)
  783. /*
  784.  * This routine checks the next token to see if it is of kind val, and
  785.  * returns true or false.  If false, the token is put back.  If true, the
  786.  * token is consumed.  NextIs and FetchToken are essentially the only
  787.  * routines used to read tokens by the parser.
  788.  */
  789. {
  790.     register Codigo_t               tmp;
  791.     if (TokenOnDeck) {
  792.     if (LastTokenKind == val) {
  793.         TokenOnDeck = 0;
  794.         return 1;
  795.     } else {
  796.         return 0;
  797.     }
  798.     }
  799.     if ((tmp = GetToken()) == val) {
  800.     return 1;
  801.     } else {
  802.     if (tmp != -1) {
  803.         TokenOnDeck = 1;
  804.     }
  805.     return 0;
  806.     }
  807. }
  808.  
  809. long
  810. FetchToken(void)
  811. /*
  812.  * This routine reads the next token, regardless of what it is.  NextIs and
  813.  * FetchToken are essentially the only routines used to read tokens by the
  814.  * parser.
  815.  */
  816. {
  817.     register Codigo_t               tmp;
  818.     if (TokenOnDeck) {
  819.     TokenOnDeck = 0;
  820.     return LastTokenKind;
  821.     }
  822.     tmp = GetToken();
  823.     if (tmp != -1)
  824.     return LastTokenKind;
  825.     else
  826.     return 0;
  827. }
  828.  
  829. void
  830. PutBackToken(char *name, Codigo_t tokval)
  831. /* Add a token back to the parse buffer. */
  832. {
  833.     /*
  834.      * Note that the values for constants were NOT taken from the function
  835.      * parameters, therefore the following two lines may not be safe.  For
  836.      * now, I'll try them as they are...
  837.      */
  838.     if (TokenOnDeck) {
  839.     ParseBuffer[ParseBufferNdx].tokval = LastTokenKind;
  840.     ParseBuffer[ParseBufferNdx].floating = LastFloatingConstant;
  841.     ParseBuffer[ParseBufferNdx].integer = LastIntegerConstant;
  842.     strcpy(ParseBuffer[ParseBufferNdx++].token, LastToken);
  843.     TokenOnDeck = 0;
  844.     }
  845.     ParseBuffer[ParseBufferNdx].tokval = tokval;
  846.     ParseBuffer[ParseBufferNdx].floating = LastFloatingConstant;
  847.     ParseBuffer[ParseBufferNdx].integer = LastIntegerConstant;
  848.     strcpy(ParseBuffer[ParseBufferNdx++].token, name);
  849. }
  850.  
  851. void
  852. UnFetchToken(void)
  853. {
  854.     PutBackToken(LastToken, LastTokenKind);
  855. }
  856.