home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 2 / Apprentice-Release2.iso / Tools / Languages / Harvest C 1.3 / Source Code / lexer.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-06-15  |  33.5 KB  |  1,387 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 <string.h>
  46. #include "structs.h"
  47. #include "CHarvestApp.h"
  48. #include "CHarvestDoc.h"
  49. #include "CDataFile.h"
  50. #include "CSourceFile.h"
  51. #include "CHarvestOptions.h"
  52. #include "CErrorLog.h"
  53.  
  54. extern CErrorLog *gErrs;
  55.  
  56. extern CHarvestDoc *gProject;
  57. extern CHarvestApp *gApplication;
  58. FILE *fopenMAC(char *name,short vRefNum,long dirID,char *mode);
  59. extern    CSourceFile *gCurSourceFile;
  60.  
  61. #pragma segment Lexer
  62.  
  63. #define isEol(s) (((s) == '\n') || ((s) == '\r'))
  64.  
  65. void
  66. ResetSRC(void)
  67. {
  68.     CurrentSRC.isIO = 0;
  69.     CurrentSRC.where.io = NULL;
  70.     CurrentSRC.PreprocLineDirty = 0;
  71.     CurrentSRC.memindex = 0;
  72.     CurrentSRC.fileKind = SRC_USRFILE;
  73.     CurrentSRC.alreadyincluded = NULL;
  74.     strcpy(CurrentSRC.fname, "");
  75.     CurrentSRC.LineCount = 1;
  76.     CurrentSRC.eol = 0;
  77.     CurrentSRC.NeedtoKill = NULL;
  78.     CurrentSRC.Macro = 0;
  79.     CurrentSRC.ExtraChar[0] = 0;
  80.     CurrentSRC.NumExtras = 0;
  81.     CurrentSRC.CountCasts = 0;
  82.     CurrentSRC.TotalIdentifierLength = 0;
  83.     CurrentSRC.CountIdentifiers = 0;
  84.     CurrentSRC.PreprocSubsts = 0;
  85.     CurrentSRC.PreprocAfter = 0;
  86.     CurrentSRC.PreprocBefore = 0;
  87.     CurrentSRC.CountPreprocCondits = 0;
  88.     CurrentSRC.StmtCount = 0;
  89.     CurrentSRC.CountComments = 0;
  90.     CurrentSRC.CommentBytes = 0;
  91. }
  92.  
  93. void
  94. PopSRC(void)
  95. /*
  96.  * Takes the top SRC off the stack and makes it current. When the stack is
  97.  * empty, the file being parsed is done.
  98.  */
  99. {
  100.     int                             wasio;
  101.     SRCListVia_t                    tmpList;
  102.     SRCKindVia_t                    tmpSRC;
  103.     wasio = 0;
  104.     tmpList = SRCStack;
  105.     if (SRCStack) {
  106.     if (CurrentSRC.isIO) {
  107.         tmpSRC = Via(tmpList)->data;
  108.     }
  109.     }
  110.     if (CurrentSRC.isIO) {
  111.     fclose(CurrentSRC.where.io);
  112.     wasio = 1;
  113.     }
  114.     if (CurrentSRC.Macro) {
  115.     CurrentSRC.Macro = 0;
  116.     }
  117.     if (CurrentSRC.NeedtoKill) {
  118.     Efree(CurrentSRC.NeedtoKill);
  119.     }
  120.     if (tmpList) {
  121.     tmpSRC = Via(tmpList)->data;
  122.     SRCStack = Via(SRCStack)->next;
  123.     CurrentSRC = Via(*tmpSRC);
  124.     Efree(tmpList);
  125.     Efree(tmpSRC);
  126.     if (CurrentSRC.isIO) {
  127.         TakeFileOffHold(CurrentSRC.where.io);
  128.     }
  129.     } else {
  130.     gAllDone = 1;
  131.     }
  132. }
  133.  
  134. void
  135. PushSRC(void)
  136. /*
  137.  * Pushes the current SRC onto the stack.  This occurs when an include file
  138.  * is invoked, or a preprocessor symbol is substituted. There may be other
  139.  * cases where this routine is used in the future.
  140.  */
  141. {
  142.     SRCKindVia_t                    tmpSRC;
  143.     SRCListVia_t                    tmpList;
  144.     tmpSRC = (SRCKindVia_t) Ealloc(sizeof(SRCKind_t));
  145.     Via(*tmpSRC) = CurrentSRC;
  146.     tmpList = (SRCListVia_t) Ealloc(sizeof(SRCList_t));
  147.     Via(tmpList)->data = tmpSRC;
  148.     Via(tmpList)->next = SRCStack;
  149.     SRCStack = tmpList;
  150.     if (CurrentSRC.isIO) {
  151.     PutFileOnHold(CurrentSRC.where.io);
  152.     }
  153.     ResetSRC();
  154. }
  155.  
  156. void
  157. PutBackChar(char c)
  158. /*
  159.  * Puts a character back to the current SRC.  Used when the token parser
  160.  * reads one two many characters.  The character buffer for each SRC has a
  161.  * finite limit on its size.
  162.  */
  163. {
  164.     if (!c)
  165.     return;
  166.     if (CurrentSRC.NumExtras >= MAXEXTRA) {
  167.     VeryBadParseError("Too many characters PUTBACK");
  168.     } else {
  169.     CurrentSRC.ExtraChar[CurrentSRC.NumExtras++] = c;
  170.     CurrentSRC.ExtraChar[CurrentSRC.NumExtras] = 0;
  171.     }
  172. }
  173.  
  174. unsigned char
  175. RawCharacter(void)
  176. {
  177.     /*
  178.      * This routine is lowest level routine for reading the SRC file. I am
  179.      * breaking up the source file reading considerably, for portability and
  180.      * a layered implementation of the preprocessor.
  181.      */
  182.     register int                    c;
  183.   backtotop:
  184.     c = 0;
  185.     /* First, check to see if a character has been "put back" */
  186.     if (CurrentSRC.NumExtras) {
  187.     LastChar = CurrentSRC.ExtraChar[--CurrentSRC.NumExtras];
  188.     return c = LastChar;
  189.     } else {
  190.     /* Now, handle the separate cases of file or string */
  191.     if (CurrentSRC.isIO) {    /* FILE */
  192.         c = fgetc(CurrentSRC.where.io);
  193.         if (!gAllDone)
  194.         CurrentSRC.CharCount++;
  195.         if (c == EOF) {
  196.         PopSRC();
  197.         if (!gAllDone)
  198.             goto backtotop;
  199.         }
  200.     } else {
  201.         if (CurrentSRC.where.mem) {    /* String */
  202.         c = Via(CurrentSRC.where.mem)[CurrentSRC.memindex];
  203.         CurrentSRC.memindex++;
  204.         if (c == 0) {
  205.             if (InPreprocIf) {
  206.             PartDone = 1;
  207.             return LastChar = 0;
  208.             }
  209.             PopSRC();
  210.             if (!gAllDone)
  211.             goto backtotop;
  212.         }
  213.         } else {        /* QQQQ Find out if this fragment is ever
  214.                  * executed */
  215.         if (InPreprocIf) {
  216.             PartDone = 1;
  217.             return LastChar = 0;
  218.         }
  219.         PopSRC();
  220.         if (!gAllDone)
  221.             goto backtotop;
  222.         }
  223.     }
  224.     }
  225.     /*
  226.      * Source file lines are counted individually for each file. QQQQ:
  227.      * Perhaps we should not count source lines for mem SRC's?
  228.      */
  229. #ifdef OLDLINEINC
  230.     if (CurrentSRC.eol) {
  231.     CurrentSRC.eol = 0;
  232.     CurrentSRC.LineCount++;
  233.     TotalLines++;
  234.     }
  235.     if (isEol(c)) {
  236.         CurrentSRC.eol = 1;
  237.     }
  238. #else
  239.     if (isEol(c)) {
  240.         CurrentSRC.PreprocLineDirty = 0;
  241.         TotalLines++;
  242.         CurrentSRC.LineCount++;
  243.     } else {
  244.         if (!(isspace(c) || (c == '#')))
  245.             CurrentSRC.PreprocLineDirty = 1;
  246.     }
  247. #endif
  248.     return (LastChar = c);
  249. }
  250.  
  251. unsigned char
  252. PreProcCharacter(void)
  253. {
  254.     /*
  255.      * This routine handles layers 1 and 2 of the preprocessor, as described
  256.      * in K & R, 2nd Ed., page 229. Trigraph sequences are converted, and all
  257.      * occurences of the backslash followed by a newline are deleted, thus
  258.      * splicing lines.
  259.      */
  260.  
  261.     register unsigned char          c;
  262.     unsigned char                   c2;
  263.     c = RawCharacter();
  264.  
  265.     if (gProject->itsOptions->trigraphs) {
  266.     int                             foundone;
  267.     if (c == '?') {
  268.         c2 = RawCharacter();
  269.         if (c2 == '?') {
  270.         /* trigraph */
  271.         c2 = RawCharacter();
  272.         foundone = 1;
  273.         switch (c2) {
  274.         case '=':
  275.             c = '#';
  276.             break;
  277.         case '/':
  278.             c = '\\';
  279.             break;
  280.         case '\'':
  281.             c = '^';
  282.             break;
  283.         case '(':
  284.             c = '[';
  285.             break;
  286.         case ')':
  287.             c = ']';
  288.             break;
  289.         case '!':
  290.             c = '|';
  291.             break;
  292.         case '<':
  293.             c = '{';
  294.             break;
  295.         case '>':
  296.             c = '}';
  297.             break;
  298.         case '-':
  299.             c = '~';
  300.             break;
  301.         default:
  302.             foundone = 0;
  303.             PutBackChar('?');
  304.             PutBackChar('?');
  305.             break;
  306.         }
  307.         if (foundone) {
  308.             UserWarning(WARN_trigraphs);
  309.         }
  310.         } else {
  311.         PutBackChar(c2);
  312.         }
  313.     }
  314.     }
  315.     /*
  316.      * The fragment below splices lines separated by a backslash
  317.      */
  318.     if (c == '\\') {
  319.     c2 = RawCharacter();
  320.     if (isEol(c2))
  321.         c = RawCharacter();
  322.     else
  323.         PutBackChar(c2);
  324.     }
  325.     return c;
  326. }
  327.  
  328. unsigned char
  329. TokenCharacter(void)
  330. {
  331.     /*
  332.      * This character reading routine handles comments in the source.
  333.      */
  334.  
  335.     register unsigned char          c;
  336.     unsigned char                   c2;
  337.     c = PreProcCharacter();
  338.  
  339.     if (c == '/') {
  340.     c2 = PreProcCharacter();
  341.     if (c2 == '*') {
  342.         int                             doneComment;
  343.         doneComment = 0;
  344.         CurrentSRC.CountComments++;
  345.         CurrentSRC.CommentBytes += 2;
  346.         while (!doneComment) {
  347.         while (c != '*') {
  348.             c = PreProcCharacter();
  349.             CurrentSRC.CommentBytes++;
  350.             if (gAllDone) {
  351.             FatalError("Unterminated comment");
  352.             }
  353.             if (c == '/') {
  354.             c = PreProcCharacter();
  355.             CurrentSRC.CommentBytes++;
  356.             if (c == '*') {
  357.                 UserWarning(WARN_nestedcomment);
  358.             }
  359.             }
  360.         }
  361.         c = PreProcCharacter();
  362.         CurrentSRC.CommentBytes++;
  363.         if (c == '/') {
  364.             doneComment = 1;
  365.         }
  366.         }
  367.         c = ' ';        /* ANSI says comments expand to whitespace */
  368.         /*
  369.          * To expand to nothing, this should read c = TokenCharacter()
  370.          */
  371.     } else if ((c2 == '/')) {
  372.         while (!isEol(c)) {
  373.         c = PreProcCharacter();
  374.         CurrentSRC.CommentBytes++;
  375.         if (gAllDone) {
  376.             FatalError("Unterminated comment");
  377.         }
  378.         }
  379.     } else {
  380.         /*
  381.          * In this case, '/' is the proper character to return, and we
  382.          * have read one character too many. We put it back.
  383.          */
  384.         PutBackChar(c2);
  385.     }
  386.     }
  387.     return c;
  388. }
  389.  
  390. unsigned char
  391. NonSpaceCharacter(void)
  392. /*
  393.  * This routine simply returns a character that is assured not to be a space.
  394.  * In addition, note that is gets its input from TokenCharacter, so comments
  395.  * will never pass through here.
  396.  */
  397. {
  398.     unsigned char                   c;
  399.     c = TokenCharacter();
  400.     while (isspace(c) && (!gAllDone))
  401.     c = TokenCharacter();
  402.     return c;
  403. }
  404.  
  405. short
  406. ParamVal(char *PStr)
  407. {
  408.     if (!strcmp(PStr, "__A0")) {
  409.     return param__A0;
  410.     } else if (!strcmp(PStr, "__A1")) {
  411.     return param__A1;
  412.     } else if (!strcmp(PStr, "__D0")) {
  413.     return param__D0;
  414.     } else if (!strcmp(PStr, "__D1")) {
  415.     return param__D1;
  416.     } else if (!strcmp(PStr, "__D2")) {
  417.     return param__D2;
  418.     }
  419.     return 0;
  420. }
  421.  
  422. void
  423. StoreTillEOL(EString_t buf)
  424. {
  425.     register int                    ndx = 0;
  426.     while (!isEol((Via(buf)[ndx++]) = PreProcCharacter()))    /* empty loop */
  427.     ;
  428.     Via(buf)[ndx] = 0;
  429. }
  430.  
  431. void
  432. SkipTillEOL(void)
  433. /*
  434.  * Used occasionally by the PreProcessor for skipping the rest of a line -
  435.  * use with care !
  436.  */
  437. {
  438.     int c;
  439.     c = PreProcCharacter();
  440.     while (!isEol(c)) {
  441.         c = PreProcCharacter();
  442.     }
  443. }
  444.  
  445. char
  446. GetCharacter(void)
  447. {                /* QQQQ routine too long ? */
  448.     /*
  449.      * A higher level character reading routine  - this one handles all the
  450.      * commands for the PreProcessor.  It is important to keep in mind when
  451.      * reading/writing this routine, that its purpose is to return a
  452.      * character. Hence, even after handling a preproc directive, it is
  453.      * necessary to fetch the next valid character to return.  In addition,
  454.      * it is necessary to make this character fetch recursive, so further
  455.      * preprocessor commands that may follow, will be executed.
  456.      */
  457.     char                            c;
  458.     int                             ndx;
  459.     int                             NumArgs;
  460.     int                             donemacro;
  461.     char                            PStr[128];
  462.     int                             valndx;
  463.     int                             doneargs;
  464.     int                             ndx2;
  465.  
  466.     /* Warning, this routine has goto statements in it !!! */
  467.  
  468.   StartFromTheTop:
  469.  
  470.     ndx = 0;
  471.  
  472.     c = NonSpaceCharacter();    /* This routine skips all the whitespace
  473.                  * before getting its first real character
  474.                  * for processing.  For this reason, it is
  475.                  * ONLY to be called between tokens.  Within
  476.                  * a token, spaces are significant.  More
  477.                  * specifically, spaces delimit tokens,
  478.                  * except for string literals and character
  479.                  * constants */
  480.     if ((c == '#') && !CurrentSRC.PreprocLineDirty) {
  481.     /* This indicates a preprocessor function */
  482.     /*
  483.      * #ifdef #else #endif #elif #if #define #undef #include #ifndef
  484.      * #error #pragma #import
  485.      */
  486.     ndx = 0;
  487.     c = PreProcCharacter();
  488.     /*
  489.      * spaces are allowed between the '#' and the preproc command itself,
  490.      * but they must be on the same line
  491.      */
  492.     while ((!isEol(c)) && (!isFirstIDChar(c)))
  493.         c = PreProcCharacter();
  494.     if (isEol(c)) {
  495.         /*
  496.          * This case means that the '#' was alone on the line. According
  497.          * to ANSI, this line is to be ignored, hence another character
  498.          * is fetched.
  499.          */
  500.         goto StartFromTheTop;
  501.     }
  502.     /*
  503.      * The routine reaches this point iff a non whitespace character was
  504.      * found on the same line as the '#'
  505.      */
  506.     LastPreproc[ndx++] = c;
  507.     while (isFirstIDChar(c = TokenCharacter())) {
  508.         LastPreproc[ndx++] = c;
  509.     }
  510.     LastPreproc[ndx] = 0;
  511.     PutBackChar(c);
  512.     /*
  513.      * LastPreproc is a string which now contains the command being
  514.      * executed.  We will test for each of these cases below and handle
  515.      * them individually.
  516.      */
  517.     if ((!strcmp(LastPreproc, "include"))) {
  518.         char                            EndChar;
  519.         short                           incvol;
  520.         long                            incdir;
  521.         FILE *                newf;
  522.         int                             already;
  523.         FSSpec theHeader;
  524.         already = 0;
  525.         if (!PPStatus) {
  526.         c = NonSpaceCharacter();
  527.         /*
  528.          * We must skip whitespace between the word include and the
  529.          * filename, which may be in either <filename> or "filename"
  530.          * format.
  531.          */
  532.         ndx = 0;
  533.         if (c == '<') {
  534.             /* System Include file */
  535.             EndChar = '>';
  536. #ifdef Undefined
  537.             strcpy(PStr,":Harvest C Headers:");
  538.             ndx = strlen(PStr);
  539. #endif
  540.         } else {
  541.             EndChar = '\"';
  542.         }
  543.         while ((c = PreProcCharacter()) != EndChar) {
  544.             PStr[ndx++] = c;
  545.             if (ndx >= 128) {
  546.             FatalError("Include file name really long !!!!");
  547.             break;
  548.             }
  549.         }
  550.         PStr[ndx] = 0;
  551.         /*
  552.          * Now, PStr is a string containing the filename of the file
  553.          * to be included
  554.          */
  555.         incvol = gCurSourceFile->theFile->volNum;
  556.         incdir = gCurSourceFile->theFile->dirID;
  557.         if (EndChar == '>') {
  558.             incvol = gApplication->StdIncludeVol;
  559.             incdir = gApplication->StdIncludeDir;
  560.         }
  561.         /*
  562.          * Now we have the filename, if this is an import, we need to
  563.          * check the current source to see if this has been included
  564.          * before.
  565.          */
  566.         if (!already) {
  567.             newf = fopenMAC(PStr, incvol, incdir, "r");
  568.             if (!newf)
  569.             newf = fopenMAC(PStr, gProject->StdAppVol, gProject->StdAppDir, "r");
  570.             if (!newf)
  571.             newf = fopenMAC(PStr, gApplication->StdIncludeVol, gApplication->StdIncludeDir, "r");
  572.             if (!newf)
  573.             newf = fopenMAC(PStr, gCurSourceFile->theFile->volNum, gCurSourceFile->theFile->dirID, "r");
  574.             if (newf) {
  575.             CountIncludes++;
  576.             PushSRC();
  577.             CurrentSRC.isIO = 1;
  578.             CurrentSRC.where.io = newf;
  579.             if (EndChar == '>') {
  580.                 CurrentSRC.fileKind = SRC_SYSHEADER;
  581.             }
  582.             else {
  583.                 CurrentSRC.fileKind = SRC_USRHEADER;
  584.             }
  585.             strcpy(CurrentSRC.fname, PStr);
  586.             goto StartFromTheTop;    /* still need to return a
  587.                          * character */
  588.             } else {
  589.             FatalError2("Include file not found ", PStr);
  590.             SkipTillEOL();
  591.             goto StartFromTheTop;    /* still need to return a
  592.                          * character */
  593.             }
  594.         } else {
  595.             SkipTillEOL();
  596.             goto StartFromTheTop;    /* still need to return a
  597.                          * character */
  598.         }
  599.         } else {
  600.         SkipTillEOL();
  601.         goto StartFromTheTop;    /* still need to return a character */
  602.         }
  603.     } else if (!strcmp(LastPreproc, "define")) {
  604.         SymListVia_t                    parmnames;
  605.         char                            TempName[128];
  606.         parmnames = NULL;
  607.         if (!PPStatus) {
  608.         if (isspace(c))
  609.             c = NonSpaceCharacter();
  610.         /*
  611.          * First, we read the identifier for the macro
  612.          */
  613.         ndx = 0;
  614.         PStr[ndx++] = c;
  615.         while (isAnyIDChar(c = TokenCharacter())) {
  616.             PStr[ndx++] = c;
  617.         }
  618.         PStr[ndx] = 0;
  619.         /*
  620.          * The identifier is now in PStr, and the character
  621.          * immediately following the identifier, is in c
  622.          */
  623.  
  624.         /*
  625.          * The character immediately following the identifier must be
  626.          * an open paren for this macro to be a macro function with
  627.          * parameters
  628.          */
  629.  
  630.         if (c == '(') {
  631.             /*
  632.              * This is a macro function.  It is now necessary to
  633.              * parse the parameters and eventually store the
  634.              * definition of the macro in Defines, using the
  635.              * AddMacroFunc routine
  636.              */
  637.             parmnames = RawTable(11);
  638.             NumArgs = 0;
  639.             ndx2 = 0;
  640.             doneargs = 0;
  641.             while (!doneargs) {
  642.             /*
  643.              * Parse args and place into parmnames symbol list
  644.              */
  645.             TempName[ndx2++] = c = NonSpaceCharacter();
  646.             if (c != ')') {
  647.                 while (isAnyIDChar(c = TokenCharacter())) {
  648.                 TempName[ndx2++] = c;
  649.                 }
  650.                 TempName[ndx2] = 0;
  651.                 TableAdd(parmnames, TempName);
  652.                 if (c == ')') {
  653.                 doneargs = 1;
  654.                 }
  655.                 if (c == ',') {
  656.                 NumArgs++;
  657.                 ndx2 = 0;
  658.                 }
  659.             } else {
  660.                 doneargs = 1;
  661.             }
  662.             }
  663.             NumArgs++;
  664.         } else {
  665.             NumArgs = 0;
  666.             PutBackChar(c);
  667.         }
  668.         /*
  669.          * Here, macro functions and defined symbols are handled
  670.          * identically.  Both have a textual "value" which is
  671.          * terminated by a newline. Note that the characters being
  672.          * read are from TokenCharacter() , which means that lines
  673.          * ending in a backslashed have already been spliced by the
  674.          * time they arrive here.  Also, note that spaces are not
  675.          * ignored here, therefore a macro can expand to simply
  676.          * spaces.
  677.          */
  678.         valndx = 0;
  679.         donemacro = 0;
  680.         while (!donemacro) {
  681.             c = TokenCharacter();
  682.             switch (c) {
  683.             case '\n':
  684.             case '\r':
  685.             donemacro = 1;
  686.             break;
  687.             default:
  688.             if (valndx >= MAXMACROLENGTH)
  689.                 FatalError("Macro too long!!!");
  690.             Via(MacroValue)[valndx++] = c;
  691.             break;
  692.             }
  693.         }
  694.         Via(MacroValue)[valndx] = 0;
  695.         /*
  696.          * MacroValue now includes the value of the symbol/macro
  697.          * being defined.
  698.          */
  699.         /*
  700.          * It is possible that valndx is 0, which means that there
  701.          * was no value on the line, and the symbol/macro will expand
  702.          * to nothing.
  703.          */
  704.         /*
  705.          * NumArgs is true if the macro was a macro function.
  706.          */
  707.         if (valndx) {
  708.             if (NumArgs) {
  709.             if (!PPStatus)
  710.                 AddMacroFunc(PStr, NumArgs, MacroValue, parmnames);
  711.             } else {
  712.             if (!PPStatus)
  713.                 AddDefine(PStr, MacroValue);
  714.             }
  715.         } else {
  716.             if (NumArgs) {
  717.             if (!PPStatus)
  718.                 AddMacroFunc(PStr, NumArgs, NULL, parmnames);
  719.             } else {
  720.             if (!PPStatus)
  721.                 AddDefine(PStr, NULL);
  722.             }
  723.         }
  724.         /*
  725.          * No need for SkipTillEOL here because macros terminate at
  726.          * the end of the line.
  727.          */
  728.         goto StartFromTheTop;    /* still need to return a character */
  729.         } else {
  730.         SkipTillEOL();
  731.         goto StartFromTheTop;    /* still need to return a character */
  732.         }
  733.     } else if (!strcmp(LastPreproc, "ifdef")) {
  734.         CurrentSRC.CountPreprocCondits++;
  735.         if (!PPStatus) {
  736.         c = NonSpaceCharacter();
  737.         ndx = 0;
  738.         PStr[ndx++] = c;
  739.         while (isAnyIDChar(c = TokenCharacter())) {
  740.             PStr[ndx++] = c;
  741.         }
  742.         PStr[ndx] = 0;
  743.         /*
  744.          * Now PStr contains the name of the identifer being tested.
  745.          */
  746.         PutBackChar(c);
  747.         /*
  748.          * A PPStatus which is true, indicates that the tokens to
  749.          * follow should be ignored. However, note that the level at
  750.          * which they are ignored is at the level of reading tokens.
  751.          * Therefore, all preprocessor functions are still executed.
  752.          * QQQQ: should this be changed ? At least, all preprocessor
  753.          * functions need to keep in mind that PPStatus may be true.
  754.          */
  755.         if (isDefined(PStr) && !PPStatus) {
  756.             SetPPStatus(0);
  757.         } else {
  758.             SetPPStatus(1);
  759.         }
  760.         SkipTillEOL();
  761.         goto StartFromTheTop;    /* still need to return a character */
  762.         } else {
  763.         SkipTillEOL();
  764.         SetPPStatus(PPStatus);
  765.         goto StartFromTheTop;    /* still need to return a character */
  766.         }
  767.     } else if (!strcmp(LastPreproc, "ifndef")) {
  768.         /*
  769.          * #ifndef is the opposite of #ifdef, see above
  770.          */
  771.         CurrentSRC.CountPreprocCondits++;
  772.         if (!PPStatus) {
  773.         c = NonSpaceCharacter();
  774.         ndx = 0;
  775.         PStr[ndx++] = c;
  776.         while (isAnyIDChar(c = TokenCharacter())) {
  777.             PStr[ndx++] = c;
  778.         }
  779.         PStr[ndx] = 0;
  780.         PutBackChar(c);
  781.         if (!isDefined(PStr) && !PPStatus) {
  782.             SetPPStatus(0);
  783.         } else {
  784.             SetPPStatus(1);
  785.         }
  786.         SkipTillEOL();
  787.         goto StartFromTheTop;    /* still need to return a character */
  788.         } else {
  789.         SkipTillEOL();
  790.         SetPPStatus(1);
  791.         goto StartFromTheTop;    /* still need to return a character */
  792.         }
  793.     } else if (!strcmp(LastPreproc, "else")) {
  794.         /*
  795.          * This simply flips the PPStatus.  QQQQ is it necessary to
  796.          * verify that there has indeed been a conditional compilation
  797.          * test before the #else ?
  798.          */
  799.         int                             oldstat;
  800.         oldstat = PPStatus;
  801.         GetPPStatus();
  802.         if (PPStatus) {
  803.         SetPPStatus(1);
  804.         } else {
  805.         SetPPStatus(!oldstat);
  806.         }
  807.         SkipTillEOL();
  808.         goto StartFromTheTop;    /* still need to return a character */
  809.     } else if (!strcmp(LastPreproc, "elif")) {
  810.         ParseTreeVia_t                  expr;
  811.         int                             flag;
  812.         EString_t                       IfLine;
  813.         SRCListVia_t                    tempstk;
  814.         int                             oldstat;
  815.         oldstat = PPStatus;
  816.         CurrentSRC.CountPreprocCondits++;
  817.         GetPPStatus();
  818.  
  819.         if ((!PPStatus) && oldstat) {
  820.         IfLine = Ealloc(MAXELIFEXPR);
  821.         StoreTillEOL(IfLine);
  822.         PushSRC();
  823.         CurrentSRC.isIO = 0;
  824.         CurrentSRC.where.mem = IfLine;
  825.  
  826.         tempstk = SRCStack;
  827.         SRCStack = NULL;
  828.         InPreprocIf = 1;
  829.         PartDone = 0;
  830.         expr = Do_constant_expr();
  831.         PartDone = 0;
  832.         SRCStack = tempstk;
  833.         InPreprocIf = 0;
  834.         Efree(IfLine);
  835.         PopSRC();
  836.  
  837.         flag = GetIntValue(expr);
  838.         FreeTree(expr);
  839.         if (flag) {
  840.             SetPPStatus(0);
  841.         }
  842.         goto StartFromTheTop;    /* still need to return a character */
  843.         } else {
  844.         SkipTillEOL();
  845.         SetPPStatus(1);
  846.         goto StartFromTheTop;    /* still need to return a character */
  847.         }
  848.     } else if (!strcmp(LastPreproc, "undef")) {
  849.         if (!PPStatus) {
  850.         if (isspace(c))
  851.             c = NonSpaceCharacter();
  852.         ndx = 0;
  853.         PStr[ndx++] = c;
  854.         while (isAnyIDChar(c = TokenCharacter())) {
  855.             PStr[ndx++] = c;
  856.         }
  857.         PStr[ndx] = 0;
  858.         /*
  859.          * PStr now contains the identifer to be undefined
  860.          */
  861.         if (!PPStatus) {
  862.             UnDefine(PStr);
  863.         }
  864.         PutBackChar(c);
  865.         SkipTillEOL();
  866.         goto StartFromTheTop;    /* still need to return a character */
  867.         } else {
  868.         SkipTillEOL();
  869.         goto StartFromTheTop;    /* still need to return a character */
  870.         }
  871.     } else if (!strcmp(LastPreproc, "endif")) {
  872.         GetPPStatus();
  873.         SkipTillEOL();
  874.         goto StartFromTheTop;    /* still need to return a character */
  875.     } else if (!strcmp(LastPreproc, "if")) {
  876.         ParseTreeVia_t                  expr;
  877.         int                             flag;
  878.         EString_t                       IfLine;
  879.         SRCListVia_t                    tempstk;
  880.         CurrentSRC.CountPreprocCondits++;
  881.         if (!PPStatus) {
  882.         IfLine = Ealloc(MAXELIFEXPR);
  883.         StoreTillEOL(IfLine);
  884.         PushSRC();
  885.         CurrentSRC.isIO = 0;
  886.         CurrentSRC.where.mem = IfLine;
  887.  
  888.         tempstk = SRCStack;
  889.         SRCStack = NULL;
  890.         InPreprocIf = 1;
  891.         PartDone = 0;
  892.         expr = Do_constant_expr();
  893.         PartDone = 0;
  894.         SRCStack = tempstk;
  895.         Efree(IfLine);
  896.         PopSRC();
  897.         CurrentSRC.PreprocLineDirty = 0;
  898.         InPreprocIf = 0;
  899.  
  900.         flag = GetIntValue(expr);
  901.         FreeTree(expr);
  902.         if (flag && !PPStatus) {
  903.             SetPPStatus(0);
  904.         } else {
  905.             SetPPStatus(1);
  906.         }
  907.         goto StartFromTheTop;    /* still need to return a character */
  908.         } else {
  909.         SkipTillEOL();
  910.         SetPPStatus(PPStatus);
  911.         goto StartFromTheTop;    /* still need to return a character */
  912.         }
  913.     } else if (!strcmp(LastPreproc, "line")) {
  914.         if (!PPStatus) {
  915.         if (NextIs(INTCONSTANT)) {
  916.             CurrentSRC.LineCount = LastIntegerConstant;
  917.             if (NextIs(STRING_LITERAL)) {
  918.             strcpy(CurrentSRC.fname, LastToken);
  919.             } else {
  920.             PreprocError("Missing file name for #line");
  921.             }
  922.         } else {
  923.             PreprocError("Missing line number for #line");
  924.         }
  925.         SkipTillEOL();
  926.         goto StartFromTheTop;    /* still need to return a character */
  927.         } else {
  928.         SkipTillEOL();
  929.         goto StartFromTheTop;    /* still need to return a character */
  930.         }
  931.     } else if (!strcmp(LastPreproc, "pragma")) {
  932.         if (!PPStatus) {
  933.         /* Read the next name - watch out for end of line */
  934.         int                             cdone = 0;
  935.         do {
  936.             c = TokenCharacter();
  937.             if (isEol(c))
  938.             cdone = 2;
  939.             if (!isspace(c))
  940.             cdone = 1;
  941.         } while (!cdone);
  942.         if (cdone != 2) {
  943.             ndx = 0;
  944.             PStr[ndx++] = c;
  945.             while (isAnyIDChar(c = TokenCharacter())) {
  946.             PStr[ndx++] = c;
  947.             }
  948.             PStr[ndx] = 0;
  949.             PutBackChar(c);
  950.             if (!strcmp(PStr, "segment")) {
  951.             /* Add a segment to the segment list */
  952.             cdone = 0;
  953.             do {
  954.                 c = TokenCharacter();
  955.                 if (isEol(c))
  956.                 cdone = 2;
  957.                 if (!isspace(c))
  958.                 cdone = 1;
  959.             } while (!cdone);
  960.             if (cdone != 2) {
  961.                 SYMVia_t                        seg;
  962.                 ndx = 0;
  963.                 PStr[ndx++] = c;
  964.                 while (isAnyIDChar(c = TokenCharacter())) {
  965.                 PStr[ndx++] = c;
  966.                 }
  967.                 PStr[ndx] = 0;
  968.                 PutBackChar(c);
  969.                 CurrentSegmentLabel = LabTableAdd(SegmentNames, PStr);
  970.             }
  971.             } else if (!strcmp(PStr, "parameter")) {
  972.             int                             gotname = 0;
  973.             int                             argindex = 0;
  974.             int                             argdone = 0;
  975.             ParamRecVia_t                   newparam;
  976.             newparam = Ealloc(sizeof(ParamRec_t));
  977.             Via(newparam)->returnreg = 0;
  978.             Via(newparam)->args[0] = 0;
  979.             Via(newparam)->args[1] = 0;
  980.             Via(newparam)->args[2] = 0;
  981.             Via(newparam)->args[3] = 0;
  982.             Via(newparam)->name[0] = 0;
  983.             Via(newparam)->next = NULL;
  984.  
  985.             cdone = 0;
  986.             do {
  987.                 c = TokenCharacter();
  988.                 if (isEol(c)) {
  989.                 cdone = 2;
  990.                 PutBackChar(c);
  991.                 }
  992.                 if (!isspace(c))
  993.                 cdone = 1;
  994.             } while (!cdone);
  995.             if (cdone != 2) {
  996.                 ndx = 0;
  997.                 PStr[ndx++] = c;
  998.                 while (isAnyIDChar(c = TokenCharacter())) {
  999.                 PStr[ndx++] = c;
  1000.                 }
  1001.                 PStr[ndx] = 0;
  1002.                 PutBackChar(c);
  1003.                 if (!strcmp(PStr, "__A0")) {
  1004.                 Via(newparam)->returnreg = param__A0;
  1005.                 } else if (!strcmp(PStr, "__A1")) {
  1006.                 Via(newparam)->returnreg = param__A1;
  1007.                 } else if (!strcmp(PStr, "__D0")) {
  1008.                 Via(newparam)->returnreg = param__D0;
  1009.                 } else if (!strcmp(PStr, "__D1")) {
  1010.                 Via(newparam)->returnreg = param__D1;
  1011.                 } else if (!strcmp(PStr, "__D2")) {
  1012.                 Via(newparam)->returnreg = param__D2;
  1013.                 } else {
  1014.                 strcpy(Via(newparam)->name, PStr);
  1015.                 gotname = 1;
  1016.                 }
  1017.                 if (!gotname && (cdone != 2)) {
  1018.                 cdone = 0;
  1019.                 do {
  1020.                     c = TokenCharacter();
  1021.                     if (isEol(c)) {
  1022.                     cdone = 2;
  1023.                     PutBackChar(c);
  1024.                     }
  1025.                     if (!isspace(c))
  1026.                     cdone = 1;
  1027.                 } while (!cdone);
  1028.                 if (cdone != 2) {
  1029.                     ndx = 0;
  1030.                     PStr[ndx++] = c;
  1031.                     while (isAnyIDChar(c = TokenCharacter())) {
  1032.                     PStr[ndx++] = c;
  1033.                     }
  1034.                     PStr[ndx] = 0;
  1035.                     PutBackChar(c);
  1036.                 }
  1037.                 strcpy(Via(newparam)->name, PStr);
  1038.                 gotname = 1;
  1039.                 }
  1040.                 if (cdone != 2) {
  1041.                 cdone = 0;
  1042.                 do {
  1043.                     c = TokenCharacter();
  1044.                     if (isEol(c)) {
  1045.                     cdone = 2;
  1046.                     PutBackChar(c);
  1047.                     }
  1048.                     if (!isspace(c))
  1049.                     cdone = 1;
  1050.                 } while (!cdone);
  1051.                 if (cdone != 2) {
  1052.                     /* We have some regs to parse */
  1053.                     /* c must be a left paren */
  1054.                     assert(c == '(');
  1055.                     while (!argdone) {
  1056.                     c = TokenCharacter();
  1057.                     while (isspace(c))
  1058.                         c = TokenCharacter();
  1059.                     ndx = 0;
  1060.                     PStr[ndx++] = c;
  1061.                     while (isAnyIDChar(c = TokenCharacter())) {
  1062.                         PStr[ndx++] = c;
  1063.                     }
  1064.                     PStr[ndx] = 0;
  1065.                     Via(newparam)->args[argindex++] = ParamVal(PStr);
  1066.                     while (isspace(c))
  1067.                         c = TokenCharacter();
  1068.                     if (c == ')')
  1069.                         argdone = 1;
  1070.                     else
  1071.                         assert(c == ',');
  1072.                     }
  1073.                 }
  1074.                 }
  1075.             }
  1076.             Via(newparam)->argcount = argindex;
  1077.             Via(newparam)->next = ParamList;
  1078.             ParamList = newparam;
  1079.             }
  1080.         }
  1081.         SkipTillEOL();
  1082.         goto StartFromTheTop;    /* still need to return a character */
  1083.         } else {
  1084.         SkipTillEOL();
  1085.         goto StartFromTheTop;    /* still need to return a character */
  1086.         }
  1087.     } else if (!strcmp(LastPreproc, "error")) {
  1088.         if (!PPStatus) {
  1089.         strcpy(PStr, "(#error) ");
  1090.         ndx = strlen(PStr);
  1091.         while (!isEol(c = TokenCharacter())) {
  1092.             PStr[ndx++] = c;
  1093.         }
  1094.         PStr[ndx] = 0;
  1095.         UserError(PStr);
  1096.         } else {
  1097.         SkipTillEOL();
  1098.         goto StartFromTheTop;    /* still need to return a character */
  1099.         }
  1100.     } else {
  1101.         PreprocError("Undefined preprocessor directive");
  1102.         SkipTillEOL();
  1103.         goto StartFromTheTop;    /* still need to return a character */
  1104.     }
  1105.     }
  1106.     return c;
  1107. }
  1108.  
  1109. void
  1110. LexerGetLine(char *buf)
  1111. {
  1112.     short                           c;
  1113.     c = GetCharacter();
  1114.     *buf++ = c;
  1115.     while (!isEol(c)) {
  1116.     c = TokenCharacter();
  1117.     if (isEol(c))
  1118.         *buf = 0;
  1119.     else
  1120.         *buf++ = c;
  1121.     }
  1122. }
  1123.  
  1124. char
  1125. EscapeConvert(char c)
  1126. {
  1127.     /*
  1128.      * This routine is used for converting escape characters within string
  1129.      * literals and character constants.
  1130.      */
  1131.     /*
  1132.      * QQQQ Do we need to define the effect of an undefined escape constant ?
  1133.      * ANSI does not.
  1134.      */
  1135.     int                             escapecode;
  1136.     switch (c) {
  1137.     case 'n':
  1138.     c = '\n';
  1139.     break;
  1140.     case 't':
  1141.     c = '\t';
  1142.     break;
  1143.     case 'v':
  1144.     c = '\v';
  1145.     break;
  1146.     case 'b':
  1147.     c = '\b';
  1148.     break;
  1149.     case 'r':
  1150.     c = '\r';
  1151.     break;
  1152.     case 'f':
  1153.     c = '\f';
  1154.     break;
  1155.     case 'a':
  1156.     c = '\a';
  1157.     break;
  1158.     case '\\':
  1159.     c = '\\';
  1160.     break;
  1161.     case '?':
  1162.     c = '\?';
  1163.     break;
  1164.     case '\'':
  1165.     c = '\'';
  1166.     break;
  1167.     case '\"':
  1168.     c = '\"';
  1169.     break;
  1170.     case 'x':
  1171.     escapecode = 0;
  1172.     while (ishexdigit(c = TokenCharacter()))
  1173.         escapecode = escapecode * 16 + hexvalue(c);
  1174.     PutBackChar(c);
  1175.     c = escapecode;
  1176.     break;
  1177.     case '0':
  1178.     case '1':
  1179.     case '2':
  1180.     case '3':
  1181.     case '4':
  1182.     case '5':
  1183.     case '6':
  1184.     case '7':
  1185.     /*
  1186.      * octal character code
  1187.      */
  1188.     escapecode = c - '0';
  1189.     while (isoctaldigit(c = TokenCharacter()))
  1190.         escapecode = escapecode * 8 + (c - '0');
  1191.     PutBackChar(c);
  1192.     c = escapecode;
  1193.     break;
  1194.     }
  1195.     return c;
  1196. }
  1197.  
  1198. double
  1199. Eintpower(int mant, int expon)
  1200. {
  1201.     double                          result;
  1202.     int                             counter;
  1203.     result = 1;
  1204.     counter = 0;
  1205.     if (expon) {
  1206.     if (expon > 0) {
  1207.         while (counter++ < expon) {
  1208.         result = result * mant;
  1209.         }
  1210.     } else {
  1211.         expon = -expon;
  1212.         while (counter++ < expon) {
  1213.         result = result / mant;
  1214.         }
  1215.     }
  1216.     } else {
  1217.     if (mant) {
  1218.         result = 1;
  1219.     } else {
  1220.         VeryBadParseError("0^0 is undefined (float constant)");
  1221.         result = 0;
  1222.     }
  1223.     }
  1224.     return result;
  1225. }
  1226.  
  1227. /*
  1228.  * Reserved words: auto break case char const continue default do double else
  1229.  * enum extern float for goto if INLINE int long PASCAL register return short
  1230.  * signed sizeof static struct switch typedef union unsigned volatile while
  1231.  */
  1232.  
  1233. /*
  1234.  * Operators >>= <<= += -= = /= %= &= ^= |= >> << ++ -- -> && || <= >= == !=
  1235.  * ; { } , : = ( ) [ ] . & ! ~ - +
  1236.  * 
  1237.  * / < > ^ | ?
  1238.  */
  1239.  
  1240. #pragma segment AppInit
  1241.  
  1242. int
  1243. KWHash(char *name)
  1244. /* This is the hash function for the keyword hash table. */
  1245. {
  1246.     register int                    result;
  1247.     result = 0;
  1248.     while (*name) {
  1249.     result += *name;
  1250.     name++;
  1251.     }
  1252.     HashCount++;
  1253.     result = result % KEYWORDTABLESIZE;
  1254.     if (!result)
  1255.     result = 1;
  1256.     return result;
  1257. }
  1258.  
  1259. void
  1260. AddKW(char *name, Codigo_t val)
  1261. /*
  1262.  * Adds a new keyword to the keyword hash table.  Used to build the table
  1263.  * initially, and not used afterwards.
  1264.  */
  1265. {
  1266.     int                             TableNdx;
  1267.     int                             Base;
  1268.     TableNdx = Base = KWHash(name);
  1269.     while (KWTable[TableNdx].val) {
  1270.     HashCollisions++;
  1271.     TableNdx = (TableNdx + Base) % KEYWORDTABLESIZE;
  1272.     }
  1273.     KWTable[TableNdx].val = val;
  1274.     KWTable[TableNdx].name = name;
  1275.     KWTable[TableNdx].uses = 0;
  1276. }
  1277.  
  1278. void
  1279. BuildKWHash(void)
  1280. /* This routine builds the hash table for keywords. */
  1281. {
  1282.     AddKW("auto", AUTO);
  1283.     AddKW("break", BREAK);
  1284.     AddKW("case", CASE);
  1285.     AddKW("char", CHAR);
  1286.     AddKW("const", CONST);
  1287.     AddKW("continue", CONTINUE);
  1288.     AddKW("default", DEFAULT);
  1289.     AddKW("do", DO);
  1290.     AddKW("double", DOUBLE);
  1291.     AddKW("else", ELSE);
  1292.     AddKW("enum", ENUM);
  1293.     AddKW("extern", EXTERN);
  1294.     AddKW("float", FLOAT);
  1295.     AddKW("for", FOR);
  1296.     AddKW("goto", GOTO);
  1297.     AddKW("if", IF);
  1298.     AddKW("int", INT);
  1299.     AddKW("long", LONG);
  1300.     AddKW("pascal", PASCAL);
  1301.     AddKW("asm", ASM);
  1302.     AddKW("register", REGISTER);
  1303.     AddKW("return", RETURN);
  1304.     AddKW("short", SHORT);
  1305.     AddKW("signed", SIGNED);
  1306.     AddKW("sizeof", SIZEOF);
  1307.     AddKW("struct", STRUCT);
  1308.     AddKW("switch", SWITCH);
  1309.     AddKW("typedef", TYPEDEF);
  1310.     AddKW("union", UNION);
  1311.     AddKW("unsigned", UNSIGNED);
  1312.     AddKW("static", STATIC);
  1313.     AddKW("void", VOID);
  1314.     AddKW("volatile", VOLATILE);
  1315.     AddKW("while", WHILE);
  1316.     AddKW("...", ELLIPSIS);
  1317.     AddKW(">>=", RIGHT_ASSIGN);
  1318.     AddKW("<<=", LEFT_ASSIGN);
  1319.     AddKW("+=", ADD_ASSIGN);
  1320.     AddKW("-=", SUB_ASSIGN);
  1321.     AddKW("*=", MUL_ASSIGN);
  1322.     AddKW("/=", DIV_ASSIGN);
  1323.     AddKW("%=", MOD_ASSIGN);
  1324.     AddKW("&=", AND_ASSIGN);
  1325.     AddKW("^=", XOR_ASSIGN);
  1326.     AddKW("|=", OR_ASSIGN);
  1327.     AddKW(">>", RIGHT_OP);
  1328.     AddKW("<<", LEFT_OP);
  1329.     AddKW("++", INC_OP);
  1330.     AddKW("--", DEC_OP);
  1331.     AddKW("->", PTR_OP);
  1332.     AddKW("&&", AND_OP);
  1333.     AddKW("||", OR_OP);
  1334.     AddKW("<=", LE_OP);
  1335.     AddKW(">=", GE_OP);
  1336.     AddKW("==", EQ_OP);
  1337.     AddKW("!=", NE_OP);
  1338.     AddKW(";", ';');
  1339.     AddKW("{", '{');
  1340.     AddKW("}", '}');
  1341.     AddKW(",", ',');
  1342.     AddKW(":", ':');
  1343.     AddKW("=", '=');
  1344.     AddKW("(", '(');
  1345.     AddKW(")", ')');
  1346.     AddKW("[", '[');
  1347.     AddKW("]", ']');
  1348.     AddKW(".", '.');
  1349.     AddKW("&", '&');
  1350.     AddKW("!", '!');
  1351.     AddKW("~", '~');
  1352.     AddKW("-", '-');
  1353.     AddKW("+", '+');
  1354.     AddKW("*", '*');
  1355.     AddKW("/", '/');
  1356.     AddKW("%", '%');
  1357.     AddKW("<", '<');
  1358.     AddKW(">", '>');
  1359.     AddKW("^", '^');
  1360.     AddKW("|", '|');
  1361.     AddKW("?", '?');
  1362.     /*
  1363.      * The defined keyword is a very special keyword.  In reality it is not a
  1364.      * C keyword.  It is implemented as such for simplicity.  It is a
  1365.      * preprocessor feature.  Only during parsing of #if and #elif
  1366.      * expressions is this valid as a keyword.
  1367.      */
  1368.     AddKW("defined", DEFINED);
  1369.     AddKW("#", '#');
  1370.     /*
  1371.      * The crosshatch keyword is defined only for the purpose of the inline
  1372.      * assembler.  Usually, the character reading routines will catch it as a
  1373.      * preproc directive...
  1374.      */
  1375.     AddKW("@interface", atINTERFACE);
  1376.     AddKW("@implementation", atIMPLEMENTATION);
  1377.     AddKW("@end", atEND);
  1378.     AddKW("@selector", atSELECTOR);
  1379.     AddKW("@defs", atDEFS);
  1380.     AddKW("@encode", atENCODE);
  1381.     AddKW("@public", atPUBLIC);
  1382.  
  1383.     AddKW("extended", EXTENDED);
  1384.     AddKW("comp", COMP);
  1385.     AddKW("single", FLOAT);
  1386. }
  1387.