home *** CD-ROM | disk | FTP | other *** search
/ io Programmo 40 / IOPROG_40.ISO / SOFT / NETFrameworkSDK.exe / comsdk.cab / samples1.exe / smc / scan.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  2000-06-23  |  149.7 KB  |  5,783 lines

  1. /*****************************************************************************/
  2.  
  3. #include "smcPCH.h"
  4. #pragma hdrstop
  5.  
  6. #include <sys/types.h>
  7. #include <sys/stat.h>
  8.  
  9. /*****************************************************************************/
  10.  
  11. #include "alloc.h"
  12. #include "scan.h"
  13. #include "error.h"
  14.  
  15. /*****************************************************************************/
  16. #ifdef  DEBUG
  17. #define DISP_TOKEN_STREAMS  0
  18. #else
  19. #define DISP_TOKEN_STREAMS  0
  20. #endif
  21. /*****************************************************************************/
  22.  
  23. #ifndef __SMC__
  24. unsigned            scanner::scanHashValIds[256];
  25. unsigned            scanner::scanHashValAll[256];
  26. #endif
  27.  
  28. /*****************************************************************************
  29.  *
  30.  *  Record the current position as the start of the current token.
  31.  */
  32.  
  33. inline
  34. void                scanner::saveSrcPos()
  35. {
  36.     assert(scanTokReplay == NULL);
  37.  
  38. //  scanTokColumn = scanInputFile.inputStreamCurCol();
  39.     scanTokSrcPos = scanSaveNext;
  40. }
  41.  
  42. /*****************************************************************************
  43.  *
  44.  *  The following functions can be used to construct error string(s).
  45.  */
  46.  
  47. void                scanner::scanErrNameBeg()
  48. {
  49.     scanErrStrNext = scannerBuff;
  50. }
  51.  
  52. char        *       scanner::scanErrNameStrBeg()
  53. {
  54.     return  scanErrStrNext;
  55. }
  56.  
  57. void                scanner::scanErrNameStrAdd(stringBuff str)
  58. {
  59.     if  (scanErrStrNext != str)
  60.         strcpy(scanErrStrNext, str);
  61.  
  62.     scanErrStrNext += strlen(str);
  63. }
  64.  
  65. void                scanner::scanErrNameStrApp(stringBuff str)
  66. {
  67.     scanErrStrNext--;
  68.     scanErrNameStrAdd(str);
  69. }
  70.  
  71. #if MGDDATA
  72. void                scanner::scanErrNameStrAdd(String     str)
  73. {
  74.     UNIMPL(!"managed stradd");
  75. }
  76. void                scanner::scanErrNameStrAdd(String     str)
  77. {
  78.     UNIMPL(!"managed stradd");
  79. }
  80. #endif
  81.  
  82. void                scanner::scanErrNameStrEnd()
  83. {
  84.     *scanErrStrNext++ = 0;
  85. }
  86.  
  87. /*****************************************************************************/
  88.  
  89. bool                infile::inputStreamInit(Compiler        comp,
  90.                                             const char     *filename,
  91.                                             bool            textMode)
  92. {
  93.     _Fstat          fileInfo;
  94.  
  95.     void           *buffAddr;
  96.  
  97.     DWORD           numRead;
  98.  
  99.     bool            result = true;
  100.  
  101.     /* Record the compiler reference for later use */
  102.  
  103.     inputComp     = comp;
  104.  
  105.     /* Remember the file name and mode */
  106.  
  107.     inputFileName = filename;
  108.     inputFileText = textMode;
  109.  
  110.     cycleCounterPause();
  111.  
  112.     /* See if the source file exists */
  113.  
  114.     if  (_stat(filename, &fileInfo))
  115.         goto EXIT;
  116.  
  117.     /* Open the file (we know it exists, but we check for errors anyway) */
  118.  
  119.     inputFile = CreateFileA(filename, GENERIC_READ,
  120.                                       FILE_SHARE_READ,
  121.                                       NULL,
  122.                                       OPEN_EXISTING,
  123.                                       FILE_FLAG_SEQUENTIAL_SCAN,
  124.                                       0);
  125.     if  (!inputFile)
  126.         goto EXIT;
  127.  
  128.     /* Read the file contents into a memory buffer */
  129.  
  130.     buffAddr = malloc(fileInfo.st_size + 1);
  131.     if  (!buffAddr)
  132.         comp->cmpGenFatal(ERRnoMemory);
  133.  
  134.     if  (!ReadFile(inputFile, buffAddr, fileInfo.st_size, &numRead, NULL) ||
  135.          numRead != (DWORD)fileInfo.st_size)
  136.     {
  137.         comp->cmpGenFatal(ERRreadErr, inputFileName);
  138.         free(buffAddr);
  139.         goto EXIT;
  140.     }
  141.  
  142.     /* Append an EOF character so we don't have to check for end of file */
  143.  
  144.     ((BYTE*)buffAddr)[fileInfo.st_size] = 0x1A;
  145.  
  146.     /* Set up the input buffer pointers and such */
  147.  
  148.     inputBuffNext     =
  149.     inputBuffAddr     = (BYTE *)buffAddr;
  150.     inputBuffSize     = fileInfo.st_size;
  151.     inputBuffLast     = inputBuffAddr + inputBuffSize + 1;
  152.  
  153.     inputSrcText      = NULL;
  154.     inputSrcBuff      = NULL;
  155.  
  156.     /* Setup the file and line position logic */
  157.  
  158.     inputFilePos      = 0;
  159.     inputStreamLineNo = 0;
  160.  
  161.     inputFileOver     = false;
  162.  
  163.     /* Everything went fine, return a success code to the caller */
  164.  
  165.     result = false;
  166.  
  167. EXIT:
  168.  
  169.     cycleCounterResume();
  170.  
  171.     return  result;
  172. }
  173.  
  174. void                infile::inputStreamInit(Compiler comp, QueuedFile  buff,
  175.                                                            const char *text)
  176. {
  177.     inputFile          = 0;
  178.  
  179.     inputBuffAddr      = NULL;
  180.  
  181.     inputSrcText       = text;
  182.     inputSrcBuff       = buff;
  183.  
  184. #ifdef  ASYNCH_INPUT_READ
  185.     if  (buff)
  186.     {
  187.         assert(text == NULL);
  188.  
  189.         inputStreamLineBeg =
  190.         inputBuffNext      = (const BYTE *)buff->qfBuff;
  191.         inputBuffLast      = (const BYTE *)buff->qfBuff + buff->qfSize + 1;
  192.  
  193.         inputFileName      = buff->qfName;
  194.     }
  195.     else
  196. #endif
  197.     {
  198.         assert(buff == NULL);
  199.  
  200.         inputStreamLineBeg =
  201.         inputBuffNext      = (const BYTE *)text;
  202.         inputBuffLast      = (const BYTE *)text + strlen(text);
  203.  
  204.         inputFileName      = "<mem>";
  205.     }
  206.  
  207.     assert(inputBuffLast > inputBuffNext && inputBuffLast[-1] == 0x1A);
  208.  
  209.     inputFilePos       = 0;
  210.  
  211.     inputStreamLineNo  = 0;
  212.  
  213.     inputFileOver      = false;
  214. }
  215.  
  216. unsigned            infile::inputStreamMore()
  217. {
  218.     /* Input buffer exhausted */
  219.  
  220.     if  (!inputSrcText)
  221.     {
  222.         if  (!inputFileText)
  223.             inputComp->cmpGenFatal(ERRreadErr, inputFileName);
  224.     }
  225.  
  226.     /* We've reached the end of the input file */
  227.  
  228.     inputFileOver = true;
  229.  
  230.     return  0x1A;
  231. }
  232.  
  233. void                infile::inputStreamDone()
  234. {
  235.     if  (inputBuffAddr)
  236.     {
  237.         free((void *)inputBuffAddr); inputBuffAddr = NULL;
  238.     }
  239.  
  240. #ifdef  ASYNCH_INPUT_READ
  241.     if  (inputSrcBuff)
  242.     {
  243.         // temp hack!!!!
  244.  
  245.         free(inputSrcBuff->qfBuff);
  246.              inputSrcBuff->qfBuff = NULL;
  247.  
  248.         inputSrcBuff = NULL;
  249.     }
  250. #endif
  251.  
  252.     if  (inputFile != 0)
  253.     {
  254.         CloseHandle(inputFile); inputFile = 0;
  255.     }
  256. }
  257.  
  258. /*****************************************************************************
  259.  *
  260.  *  Read the next source character, checking for an "\EOL" sequence.
  261.  */
  262.  
  263. inline
  264. int                 scanner::scanNextChar()
  265. {
  266.     int             ch = readNextChar();
  267.  
  268.     if  (ch == '\\')
  269.     {
  270.         UNIMPL(!"backslash");
  271.     }
  272.  
  273.     return  ch;
  274. }
  275.  
  276. /*****************************************************************************
  277.  *
  278.  *  The following table speeds various tests of characters, such as whether
  279.  *  a given character can be part of an identifier, and so on.
  280.  */
  281.  
  282. enum    CFkinds
  283. {
  284.     _CF_IDENT_OK = 0x01,
  285.     _CF_HEXDIGIT = 0x02,
  286. };
  287.  
  288. static  unsigned char   charFlags[256] =
  289. {
  290.     0,                          /* 0x00   */
  291.     0,                          /* 0x01   */
  292.     0,                          /* 0x02   */
  293.     0,                          /* 0x03   */
  294.     0,                          /* 0x04   */
  295.     0,                          /* 0x05   */
  296.     0,                          /* 0x06   */
  297.     0,                          /* 0x07   */
  298.     0,                          /* 0x08   */
  299.     0,                          /* 0x09   */
  300.     0,                          /* 0x0A   */
  301.     0,                          /* 0x0B   */
  302.     0,                          /* 0x0C   */
  303.     0,                          /* 0x0D   */
  304.     0,                          /* 0x0E   */
  305.     0,                          /* 0x0F   */
  306.     0,                          /* 0x10   */
  307.     0,                          /* 0x11   */
  308.     0,                          /* 0x12   */
  309.     0,                          /* 0x13   */
  310.     0,                          /* 0x14   */
  311.     0,                          /* 0x15   */
  312.     0,                          /* 0x16   */
  313.     0,                          /* 0x17   */
  314.     0,                          /* 0x18   */
  315.     0,                          /* 0x19   */
  316.     0,                          /* 0x1A   */
  317.     0,                          /* 0x1B   */
  318.     0,                          /* 0x1C   */
  319.     0,                          /* 0x1D   */
  320.     0,                          /* 0x1E   */
  321.     0,                          /* 0x1F   */
  322.     0,                          /* 0x20   */
  323.     0,                          /* 0x21 ! */
  324.     0,                          /* 0x22   */
  325.     0,                          /* 0x23 # */
  326.     0,                          /* 0x24 $ */
  327.     0,                          /* 0x25 % */
  328.     0,                          /* 0x26 & */
  329.     0,                          /* 0x27   */
  330.     0,                          /* 0x28   */
  331.     0,                          /* 0x29   */
  332.     0,                          /* 0x2A   */
  333.     0,                          /* 0x2B   */
  334.     0,                          /* 0x2C   */
  335.     0,                          /* 0x2D   */
  336.     0,                          /* 0x2E   */
  337.     0,                          /* 0x2F   */
  338.     0,                          /* 0x30   */
  339.     0,                          /* 0x31   */
  340.     0,                          /* 0x32   */
  341.     0,                          /* 0x33   */
  342.     0,                          /* 0x34   */
  343.     0,                          /* 0x35   */
  344.     0,                          /* 0x36   */
  345.     0,                          /* 0x37   */
  346.     0,                          /* 0x38   */
  347.     0,                          /* 0x39   */
  348.     0,                          /* 0x3A   */
  349.     0,                          /* 0x3B   */
  350.     0,                          /* 0x3C < */
  351.     0,                          /* 0x3D = */
  352.     0,                          /* 0x3E > */
  353.     0,                          /* 0x3F   */
  354.     0,                          /* 0x40 @ */
  355.     _CF_HEXDIGIT,               /* 0x41 A */
  356.     _CF_HEXDIGIT,               /* 0x42 B */
  357.     _CF_HEXDIGIT,               /* 0x43 C */
  358.     _CF_HEXDIGIT,               /* 0x44 D */
  359.     _CF_HEXDIGIT,               /* 0x45 E */
  360.     _CF_HEXDIGIT,               /* 0x46 F */
  361.     0,                          /* 0x47 G */
  362.     0,                          /* 0x48 H */
  363.     0,                          /* 0x49 I */
  364.     0,                          /* 0x4A J */
  365.     0,                          /* 0x4B K */
  366.     0,                          /* 0x4C L */
  367.     0,                          /* 0x4D M */
  368.     0,                          /* 0x4E N */
  369.     0,                          /* 0x4F O */
  370.     0,                          /* 0x50 P */
  371.     0,                          /* 0x51 Q */
  372.     0,                          /* 0x52 R */
  373.     0,                          /* 0x53 S */
  374.     0,                          /* 0x54 T */
  375.     0,                          /* 0x55 U */
  376.     0,                          /* 0x56 V */
  377.     0,                          /* 0x57 W */
  378.     0,                          /* 0x58 X */
  379.     0,                          /* 0x59 Y */
  380.     0,                          /* 0x5A Z */
  381.     0,                          /* 0x5B   */
  382.     0,                          /* 0x5C   */
  383.     0,                          /* 0x5D   */
  384.     0,                          /* 0x5E   */
  385.     0,                          /* 0x5F   */
  386.     0,                          /* 0x60   */
  387.     _CF_HEXDIGIT,               /* 0x61 a */
  388.     _CF_HEXDIGIT,               /* 0x62 b */
  389.     _CF_HEXDIGIT,               /* 0x63 c */
  390.     _CF_HEXDIGIT,               /* 0x64 d */
  391.     _CF_HEXDIGIT,               /* 0x65 e */
  392.     _CF_HEXDIGIT,               /* 0x66 f */
  393.     0,                          /* 0x67 g */
  394.     0,                          /* 0x68 h */
  395.     0,                          /* 0x69 i */
  396.     0,                          /* 0x6A j */
  397.     0,                          /* 0x6B k */
  398.     0,                          /* 0x6C l */
  399.     0,                          /* 0x6D m */
  400.     0,                          /* 0x6E n */
  401.     0,                          /* 0x6F o */
  402.     0,                          /* 0x70 p */
  403.     0,                          /* 0x71 q */
  404.     0,                          /* 0x72 r */
  405.     0,                          /* 0x73 s */
  406.     0,                          /* 0x74 t */
  407.     0,                          /* 0x75 u */
  408.     0,                          /* 0x76 v */
  409.     0,                          /* 0x77 w */
  410.     0,                          /* 0x78 x */
  411.     0,                          /* 0x79 y */
  412.     0,                          /* 0x7A z */
  413.     0,                          /* 0x7B   */
  414.     0,                          /* 0x7C   */
  415.     0,                          /* 0x7D   */
  416.     0,                          /* 0x7E   */
  417.     0                           /* 0x7F   */
  418.  
  419.     // all the remaining values are 0
  420. };
  421.  
  422. /*****************************************************************************
  423.  *
  424.  *  The _C_xxx enum and scanCharType[] table are used to map a character to
  425.  *  simple classification values and flags.
  426.  */
  427.  
  428. enum charTypes
  429. {
  430.         _C_ERR,             // illegal character
  431.         _C_EOF,             // end of file
  432.  
  433. #if FV_DBCS
  434.         _C_XLD,             // first char of a multi-byte sequence
  435.         _C_DB1,             // a SB char that needs to be mapped to a DB char
  436. #endif
  437.  
  438.         _C_LET,             // letter (B-K,M-Z,a-z)
  439.         _C_L_A,             // letter 'A'
  440.         _C_L_L,             // letter 'L'
  441.         _C_L_S,             // letter 'S'
  442.         _C_DIG,             // digit (0-9)
  443.         _C_WSP,             // white space
  444.         _C_NWL,             // new line
  445.  
  446.         _C_DOL,             // $
  447.         _C_BSL,             // \ (backslash)
  448.  
  449.         _C_BNG,             // !
  450.         _C_QUO,             // "
  451.         _C_APO,             // '
  452.         _C_PCT,             // %
  453.         _C_AMP,             // &
  454.         _C_LPR,             // (
  455.         _C_RPR,             // )
  456.         _C_PLS,             // +
  457.         _C_MIN,             // -
  458.         _C_MUL,             // *
  459.         _C_SLH,             // /
  460.         _C_XOR,             // ^
  461.         _C_CMA,             // ,
  462.         _C_DOT,             // .
  463.         _C_LT,              // <
  464.         _C_EQ,              // =
  465.         _C_GT,              // >
  466.         _C_QUE,             // ?
  467.         _C_LBR,             // [
  468.         _C_RBR,             // ]
  469.         _C_USC,             // _
  470.         _C_LC,              // {
  471.         _C_RC,              // }
  472.         _C_BAR,             // |
  473.         _C_TIL,             // ~
  474.         _C_COL,             // :
  475.         _C_SMC,             // ;
  476.         _C_AT,              // @
  477. };
  478.  
  479. const   charTypes   _C_BKQ = _C_ERR;      // `
  480. const   charTypes   _C_SHP = _C_ERR;      // #
  481.  
  482. static
  483. unsigned char       scanCharType[256] =
  484. {
  485.     _C_ERR, _C_ERR, _C_ERR, _C_ERR, _C_ERR, _C_ERR, _C_ERR, _C_ERR, /* 00-07 */
  486.     _C_ERR, _C_WSP, _C_NWL, _C_ERR, _C_WSP, _C_NWL, _C_ERR, _C_ERR, /* 08-0F */
  487.  
  488.     _C_ERR, _C_ERR, _C_ERR, _C_ERR, _C_ERR, _C_ERR, _C_ERR, _C_ERR, /* 10-17 */
  489.     _C_ERR, _C_WSP, _C_EOF, _C_ERR, _C_ERR, _C_ERR, _C_ERR, _C_ERR, /* 18-1F */
  490.  
  491.     _C_WSP, _C_BNG, _C_QUO, _C_SHP, _C_DOL, _C_PCT, _C_AMP, _C_APO, /* 20-27 */
  492.     _C_LPR, _C_RPR, _C_MUL, _C_PLS, _C_CMA, _C_MIN, _C_DOT, _C_SLH, /* 28-2F */
  493.  
  494.     _C_DIG, _C_DIG, _C_DIG, _C_DIG, _C_DIG, _C_DIG, _C_DIG, _C_DIG, /* 30-37 */
  495.     _C_DIG, _C_DIG, _C_COL, _C_SMC, _C_LT , _C_EQ , _C_GT , _C_QUE, /* 38-3F */
  496.  
  497.     _C_AT , _C_L_A, _C_LET, _C_LET, _C_LET, _C_LET, _C_LET, _C_LET, /* 40-47 */
  498.     _C_LET, _C_LET, _C_LET, _C_LET, _C_L_L, _C_LET, _C_LET, _C_LET, /* 48-4F */
  499.  
  500.     _C_LET, _C_LET, _C_LET, _C_L_S, _C_LET, _C_LET, _C_LET, _C_LET, /* 50-57 */
  501.     _C_LET, _C_LET, _C_LET, _C_LBR, _C_BSL, _C_RBR, _C_XOR, _C_USC, /* 58-5F */
  502.  
  503.     _C_BKQ, _C_LET, _C_LET, _C_LET, _C_LET, _C_LET, _C_LET, _C_LET, /* 60-67 */
  504.     _C_LET, _C_LET, _C_LET, _C_LET, _C_LET, _C_LET, _C_LET, _C_LET, /* 68-6F */
  505.  
  506.     _C_LET, _C_LET, _C_LET, _C_LET, _C_LET, _C_LET, _C_LET, _C_LET, /* 70-77 */
  507.     _C_LET, _C_LET, _C_LET, _C_LC , _C_BAR, _C_RC , _C_TIL, _C_ERR, /* 78-7F */
  508.  
  509.     _C_LET, _C_LET, _C_LET, _C_LET, _C_LET, _C_LET, _C_LET, _C_LET, /* 80-87 */
  510.     _C_LET, _C_LET, _C_LET, _C_LET, _C_LET, _C_LET, _C_LET, _C_LET, /* 88-8F */
  511.  
  512.     _C_LET, _C_LET, _C_LET, _C_LET, _C_LET, _C_LET, _C_LET, _C_LET, /* 90-97 */
  513.     _C_LET, _C_LET, _C_LET, _C_LET, _C_LET, _C_LET, _C_LET, _C_LET, /* 98-9F */
  514.  
  515.     _C_LET, _C_LET, _C_LET, _C_LET, _C_LET, _C_LET, _C_LET, _C_LET, /* A0-A7 */
  516.     _C_LET, _C_LET, _C_LET, _C_LET, _C_LET, _C_LET, _C_LET, _C_LET, /* A8-AF */
  517.  
  518.     _C_LET, _C_LET, _C_LET, _C_LET, _C_LET, _C_LET, _C_LET, _C_LET, /* B0-B7 */
  519.     _C_LET, _C_LET, _C_LET, _C_LET, _C_LET, _C_LET, _C_LET, _C_LET, /* B8-BF */
  520.  
  521.     _C_LET, _C_LET, _C_LET, _C_LET, _C_LET, _C_LET, _C_LET, _C_LET, /* C0-C7 */
  522.     _C_LET, _C_LET, _C_LET, _C_LET, _C_LET, _C_LET, _C_LET, _C_LET, /* C8-CF */
  523.  
  524.     _C_LET, _C_LET, _C_LET, _C_LET, _C_LET, _C_LET, _C_LET, _C_LET, /* D0-D7 */
  525.     _C_LET, _C_LET, _C_LET, _C_LET, _C_LET, _C_LET, _C_LET, _C_LET, /* D8-DF */
  526.  
  527.     _C_LET, _C_LET, _C_LET, _C_LET, _C_LET, _C_LET, _C_LET, _C_LET, /* E0-E7 */
  528.     _C_LET, _C_LET, _C_LET, _C_LET, _C_LET, _C_LET, _C_LET, _C_LET, /* E8-EF */
  529.  
  530.     _C_LET, _C_LET, _C_LET, _C_LET, _C_LET, _C_LET, _C_LET, _C_LET, /* F0-F7 */
  531.     _C_LET, _C_LET, _C_LET, _C_LET, _C_LET, _C_LET, _C_LET, _C_LET, /* F8-FF */
  532. };
  533.  
  534. inline
  535. unsigned                charType(unsigned ch)
  536. {
  537.     assert(ch <= 0xFF);
  538.     return  scanCharType[ch];
  539. }
  540.  
  541. inline
  542. unsigned            wideCharType(unsigned ch)
  543. {
  544.     return  (ch <= 0xFF) ? scanCharType[ch]
  545.                          : _C_LET;
  546. }
  547.  
  548. /*****************************************************************************
  549.  *
  550.  *  Fill the hash tables with values. Note that the scanCharType[] table must
  551.  *  be initialized properly before calling this routine.
  552.  */
  553.  
  554. void                hashTab::hashFuncInit(unsigned randSeed)
  555. {
  556.     unsigned        i;
  557.  
  558.     /* Start the random number generator */
  559.  
  560.     srand(randSeed);
  561.  
  562.     /* Fill the 'all' table with random numbers */
  563.  
  564.     for (i = 0; i < 256; i++)
  565.     {
  566.         int     val = rand();
  567.         if  (!val)
  568.             val = 1;
  569.  
  570.         scanner::scanHashValAll[i] = val;
  571.     }
  572.  
  573.     /* Set the appropriate entries in the 'ident-only' array */
  574.  
  575.     memset(&scanner::scanHashValIds, 0, sizeof(scanner::scanHashValIds));
  576.  
  577.     for (i = 0; i < 256; i++)
  578.     {
  579.         switch (scanCharType[i])
  580.         {
  581.         case _C_LET:
  582.         case _C_L_A:
  583.         case _C_L_L:
  584.         case _C_L_S:
  585.         case _C_DIG:
  586.         case _C_USC:
  587.         case _C_DOL:
  588.  
  589.             scanner::scanHashValIds[i] = scanner::scanHashValAll[i];
  590.  
  591.             /* Remember whether this character is OK in an identifier */
  592.  
  593.             charFlags[i] |=  _CF_IDENT_OK;
  594.             break;
  595.  
  596.         default:
  597.  
  598.             charFlags[i] &= ~_CF_IDENT_OK;
  599.             break;
  600.         }
  601.     }
  602. }
  603.  
  604. inline  void        hashFNstart(INOUT unsigned REF hv        ) { hv = 0; }
  605. inline  void        hashFNaddCh(INOUT unsigned REF hv, int ah) { hv = hv * 3 ^ ah; }
  606. inline  unsigned    hashFNvalue(INOUT unsigned REF hv        ) { return hv; }
  607.  
  608. unsigned            hashTab::hashComputeHashVal(const char *name)
  609. {
  610.     unsigned    hash;
  611.     unsigned    hadd;
  612.  
  613.     hashFNstart(hash);
  614.  
  615.     for (;;)
  616.     {
  617.         unsigned    ch = *(BYTE *)name; name++;
  618.  
  619.         if  (!ch)
  620.             return  hashFNvalue(hash);
  621.  
  622.         hadd = scanner::scanHashValAll[ch]; assert(hadd);
  623.  
  624.         hashFNaddCh(hash, hadd);
  625.     }
  626. }
  627.  
  628. unsigned            hashTab::hashComputeHashVal(const char *name, size_t nlen)
  629. {
  630.     unsigned    hash;
  631.     unsigned    hadd;
  632.  
  633.     assert(nlen);
  634.  
  635.     hashFNstart(hash);
  636.  
  637.     do
  638.     {
  639.         unsigned    ch = *(BYTE *)name; name++;
  640.  
  641.         hadd = scanner::scanHashValAll[ch]; assert(hadd);
  642.  
  643.         hashFNaddCh(hash, hadd);
  644.     }
  645.     while (--nlen);
  646.  
  647.     return  hashFNvalue(hash);
  648. }
  649.  
  650. /*****************************************************************************/
  651.  
  652. bool            hashTab::hashStringCompare(const char *s1, const char *s2)
  653. {
  654.     return  (strcmp(s1, s2) == 0);
  655. }
  656.  
  657. /*****************************************************************************/
  658.  
  659. #ifdef DEBUG
  660.  
  661. bool                scanner::scanDispCurToken(bool lastId, bool brief)
  662. {
  663.     bool            prevId = lastId;
  664.                              lastId = false;
  665.  
  666.     if  (brief)
  667.     {
  668.         const char *    name;
  669.  
  670.         switch  (scanTok.tok)
  671.         {
  672.         case tkID:
  673.  
  674.             name = hashTab::identSpelling(scanTok.id.tokIdent);
  675.  
  676.         SHOW_ID:
  677.  
  678.             if  (strlen(name) > 0)
  679.             {
  680.                 printf("[I]");
  681.             }
  682.             else
  683.             {
  684.                 if  (prevId) printf(" ");
  685.                 printf("%s", name);
  686.                 lastId = true;
  687.             }
  688.             break;
  689.  
  690.         case tkIntCon:
  691.             if  (prevId) printf(" ");
  692.             printf("%ld", scanTok.intCon.tokIntVal);
  693.             lastId = true;
  694.             break;
  695.  
  696.         case tkLngCon:
  697.             if  (prevId) printf(" ");
  698.             printf("%Ld", scanTok.lngCon.tokLngVal);
  699.             lastId = true;
  700.             break;
  701.  
  702.         case tkFltCon:
  703.             if  (prevId) printf(" ");
  704.             printf("%f", scanTok.fltCon.tokFltVal);
  705.             lastId = true;
  706.             break;
  707.  
  708.         case tkStrCon:
  709.             if  (prevId) printf(" ");
  710.             printf("\"%s\"", scanTok.strCon.tokStrVal);
  711.             lastId = true;
  712.             break;
  713.  
  714.         case tkEOF:
  715.             printf("\n");
  716.             break;
  717.  
  718.         default:
  719.  
  720.             name = scanHashKwd->tokenName(scanTok.tok);
  721.  
  722.             if (scanTok.tok <= tkKwdLast)
  723.                 goto SHOW_ID;
  724.  
  725.             printf("%s", name);
  726.             break;
  727.         }
  728.     }
  729.     else
  730.     {
  731. //      printf("[line=%4u,col=%03u] ", scanTokLineNo, scanTokColumn);
  732.         printf("[line=%4u] "         , scanTokLineNo);
  733.  
  734.         switch  (scanTok.tok)
  735.         {
  736.         case tkID:
  737.             printf("Ident   '%s' \n", hashTab::identSpelling(scanTok.id.tokIdent));
  738.             break;
  739.  
  740.         case tkIntCon:
  741.             printf("Integer  %ld \n", scanTok.intCon.tokIntVal);
  742.             break;
  743.  
  744.         case tkLngCon:
  745.             printf("Long     %Ld \n", scanTok.lngCon.tokLngVal);
  746.             break;
  747.  
  748.         case tkFltCon:
  749.             printf("Float    %f  \n", scanTok.fltCon.tokFltVal);
  750.             break;
  751.  
  752.         case tkDblCon:
  753.             printf("Double   %f  \n", scanTok.dblCon.tokDblVal);
  754.             break;
  755.  
  756.         case tkStrCon:
  757.             printf("String   '%s'\n", scanTok.strCon.tokStrVal);
  758.             break;
  759.  
  760.         case tkEOF:
  761.             printf("EOF\n");
  762.             break;
  763.  
  764.         default:
  765.  
  766.             /* Must be a keyword token */
  767.  
  768.             assert(tokenToIdent(scanTok.tok));
  769.  
  770. //          printf("Keyword '%s' (#%u)\n", hashTab::identSpelling(tokenToIdent(scanTok.tok)), scanTok.tok);
  771.             printf("Keyword '%s'\n",       hashTab::identSpelling(tokenToIdent(scanTok.tok)));
  772.             break;
  773.         }
  774.     }
  775.  
  776.     return  lastId;
  777. }
  778.  
  779. #endif
  780.  
  781. /*****************************************************************************
  782.  *
  783.  *  Reuse or allocate a preprocessing state entry.
  784.  */
  785.  
  786. inline
  787. PrepList            scanner::scanGetPPdsc()
  788. {
  789.     PrepList        prep;
  790.  
  791.     if  (scanPrepFree)
  792.     {
  793.         prep = scanPrepFree;
  794.                scanPrepFree = prep->pplNext;
  795.     }
  796.     else
  797.     {
  798.         prep = (PrepList)scanAlloc->nraAlloc(sizeof(*prep));
  799.     }
  800.  
  801.     return  prep;
  802. }
  803.  
  804. /*****************************************************************************
  805.  *
  806.  *  Push an entry onto the preprocessing state stack.
  807.  */
  808.  
  809. void                scanner::scanPPdscPush(preprocState state)
  810. {
  811.     PrepList        prep;
  812.  
  813.     prep = scanGetPPdsc();
  814.  
  815.     prep->pplState = state;
  816.     prep->pplLine  = scanTokLineNo;
  817.  
  818.     prep->pplNext  = scanPrepList;
  819.                      scanPrepList = prep;
  820. }
  821.  
  822. /*****************************************************************************
  823.  *
  824.  *  Pop the top entry from the preprocessing state stack.
  825.  */
  826.  
  827. void                scanner::scanPPdscPop()
  828. {
  829.     PrepList        prep;
  830.  
  831.     prep = scanPrepList;
  832.            scanPrepList = prep->pplNext;
  833.  
  834.     prep->pplNext = scanPrepFree;
  835.                     scanPrepFree = prep;
  836. }
  837.  
  838. /*****************************************************************************
  839.  *
  840.  *  We're at the beginning of a new source line, check for a directive. If a
  841.  *  directive is found, its PP_xxx value is returned and 'scanStopAtEOL' will
  842.  *  be set to true;
  843.  */
  844.  
  845. prepDirs            scanner::scanCheckForPrep()
  846. {
  847.     bool            svp;
  848.     tokens          tok;
  849.     unsigned        ch;
  850.  
  851.     do
  852.     {
  853.         ch = readNextChar();
  854.     }
  855.     while (charType(ch) == _C_WSP);
  856.  
  857.     if  (ch != '#')
  858.     {
  859.         undoNextChar();
  860.         return  PP_NONE;
  861.     }
  862.  
  863.     /* We have what looks like a pre-processing directive */
  864.  
  865.     scanStopAtEOL = true;
  866.  
  867.     /* The directive name should come next */
  868.  
  869.     svp = scanSkipToPP; scanSkipToPP = true;
  870.     tok = scan();
  871.     scanSkipToPP = svp;
  872.  
  873.     switch (tok)
  874.     {
  875.         Ident           iden;
  876.         const   char *  name;
  877.         unsigned        nlen;
  878.  
  879.     case tkID:
  880.  
  881.         /* See what directive we have */
  882.  
  883.         iden = scanTok.id.tokIdent;
  884.         if  (iden)
  885.         {
  886.             name = hashTab::identSpelling(iden);
  887.             nlen = hashTab::identSpellLen(iden);
  888.         }
  889.         else
  890.         {
  891.             name = scannerBuff;
  892.             nlen = strlen(name);
  893.         }
  894.  
  895.         /* The following is a bit lame, is there a better way? */
  896.  
  897.         switch (nlen)
  898.         {
  899.         case 5:
  900.  
  901.             if  (!memcmp(name, "endif" , 5)) return PP_ENDIF;
  902.             if  (!memcmp(name, "ifdef" , 5)) return PP_IFDEF;
  903.             if  (!memcmp(name, "error" , 5)) return PP_ERROR;
  904.  
  905.             break;
  906.  
  907.         case 6:
  908.  
  909.             if  (!memcmp(name, "ifndef", 6)) return PP_IFNDEF;
  910.             if  (!memcmp(name, "pragma", 6)) return PP_PRAGMA;
  911.             if  (!memcmp(name, "define", 6)) return PP_DEFINE;
  912.  
  913.             break;
  914.         }
  915.  
  916.         if  (!scanSkipToPP)
  917.             scanComp->cmpGenWarn(WRNbadPrep, name);
  918.  
  919.         goto SKIP;
  920.  
  921.     case tkIF:
  922.         return PP_IF;
  923.  
  924.     case tkELSE:
  925.         return PP_ELSE;
  926.     }
  927.  
  928.     if  (!scanSkipToPP)
  929.        scanComp->cmpGenError(ERRbadPPdir);
  930.  
  931. SKIP:
  932.  
  933.     scanSkipToEOL();
  934.     scanStopAtEOL = false;
  935.  
  936.     return  PP_NONE;
  937. }
  938.  
  939. /*****************************************************************************
  940.  *
  941.  *  Check and make sure we're at the end of the current source line.
  942.  */
  943.  
  944. inline
  945. void                scanner::scanCheckEOL()
  946. {
  947.     scanStopAtEOL = true;
  948.  
  949.     if  (scan() != tkEOL)
  950.     {
  951.         scanComp->cmpError(ERRnoEOL);
  952.         scanSkipToEOL();
  953.     }
  954.  
  955.     scanStopAtEOL = false;
  956. }
  957.  
  958. /*****************************************************************************
  959.  *
  960.  *  Skip to a matching else and/or endif directive.
  961.  */
  962.  
  963. void                scanner::scanSkipToDir(preprocState state)
  964. {
  965.     PrepList        basePrep = scanPrepList;
  966.  
  967.     scanSkipToPP = true;
  968.  
  969.     for (;;)
  970.     {
  971.         /* Skip the current line and check the next one for a directive */
  972.  
  973.         for (;;)
  974.         {
  975.             unsigned        ch = readNextChar();
  976.  
  977.             switch (charType(ch))
  978.             {
  979.             case _C_NWL:
  980.  
  981.                 switch (scanNewLine(ch))
  982.                 {
  983.                 case PP_ELSE:
  984.  
  985.                     /* The top entry better be an "if" */
  986.  
  987.                     if  (scanPrepList == basePrep)
  988.                     {
  989.                         if  (state != PPS_IF)
  990.                             scanComp->cmpError(ERRbadElse);
  991.  
  992.                         scanSkipToPP = false;
  993.  
  994.                         scanPPdscPush(PPS_ELSE);
  995.                         return;
  996.                     }
  997.                     else
  998.                     {
  999.                         if  (scanPrepList->pplState != PPS_IF)
  1000.                             scanComp->cmpError(ERRbadElse);
  1001.  
  1002.                         /* Flip the entry to an "else" */
  1003.  
  1004.                         scanPrepList->pplState = PPS_ELSE;
  1005.                     }
  1006.                     break;
  1007.  
  1008.                 case PP_ENDIF:
  1009.  
  1010.                     /* If there are no nested entries, we're done */
  1011.  
  1012.                     if  (scanPrepList == basePrep)
  1013.                     {
  1014.                         scanSkipToPP = false;
  1015.                         return;
  1016.                     }
  1017.  
  1018.                     /* Pop the most recent entry and keep skipping */
  1019.  
  1020.                     scanPPdscPop();
  1021.                     break;
  1022.  
  1023.                 case PP_IF:
  1024.                 case PP_IFDEF:
  1025.                 case PP_IFNDEF:
  1026.  
  1027.                     /* Push a nested entry */
  1028.  
  1029.                     scanPPdscPush(PPS_IF);
  1030.                     break;
  1031.                 }
  1032.                 break;
  1033.  
  1034.             case _C_SLH:
  1035.  
  1036.                 switch (readNextChar())
  1037.                 {
  1038.                 case '/':
  1039.                     scanSkipLineCmt();
  1040.                     break;
  1041.  
  1042.                 case '*':
  1043.                     scanSkipComment();
  1044.                     break;
  1045.                 }
  1046.                 continue;
  1047.  
  1048.             case _C_EOF:
  1049.  
  1050.                 undoNextChar();
  1051.  
  1052.                 /* Report any open sections as errors */
  1053.  
  1054.                 while (scanPrepList != basePrep)
  1055.                 {
  1056.                     scanComp->cmpGenError(ERRnoEndif, scanPrepList->pplLine);
  1057.  
  1058.                     scanPPdscPop();
  1059.                 }
  1060.  
  1061.                 scanSkipToPP = false;
  1062.                 return;
  1063.  
  1064.             default:
  1065.                 continue;
  1066.             }
  1067.         }
  1068.     }
  1069. }
  1070.  
  1071. /*****************************************************************************
  1072.  *
  1073.  *  Record the beginning of a new source line and check for a pre-processing
  1074.  *  directive.
  1075.  */
  1076.  
  1077. prepDirs            scanner::scanRecordNL(bool noPrep)
  1078. {
  1079.     prepDirs        prep;
  1080.     bool            cond;
  1081.  
  1082.     scanTokLineNo = scanInputFile.inputStreamNxtLine();
  1083. //  scanTokColumn = 0;
  1084.     scanTokSrcPos = scanSaveNext;
  1085.  
  1086.     if  (noPrep)
  1087.         return  PP_NONE;
  1088.  
  1089.     /* Check for a directive in the new source line */
  1090.  
  1091.     prep = scanCheckForPrep();
  1092.     if  (prep == PP_NONE || scanSkipToPP)
  1093.         return  prep;
  1094.  
  1095.     assert(scanTokRecord != false); scanTokRecord = false;
  1096.  
  1097.     /* We have a directive and we're supposed to process it */
  1098.  
  1099.     switch (prep)
  1100.     {
  1101.         Ident           iden;
  1102.         char    *       dest;
  1103.  
  1104.     case PP_IF:
  1105.  
  1106.         assert(scanInPPexpr == false);
  1107.  
  1108.         scanInPPexpr = true;
  1109.         cond = scanComp->cmpEvalPreprocCond();
  1110.         scanInPPexpr = false;
  1111.  
  1112.         goto PREP_COND;
  1113.  
  1114.     case PP_IFDEF:
  1115.     case PP_IFNDEF:
  1116.  
  1117.         scanNoMacExp  = true;
  1118.         scan();
  1119.         scanNoMacExp  = false;
  1120.  
  1121.         if  (scanTok.tok != tkID)
  1122.         {
  1123.             scanComp->cmpGenError(ERRnoIdent);
  1124.  
  1125.             /* To minimize further errors, assume the condition was false */
  1126.  
  1127.             cond = false;
  1128.         }
  1129.         else
  1130.         {
  1131.             if  (hashTab::getIdentFlags(scanTok.id.tokIdent) & IDF_MACRO)
  1132.             {
  1133.                 /* True if the directive was an "#ifdef" */
  1134.  
  1135.                 cond = (prep == PP_IFDEF);
  1136.             }
  1137.             else
  1138.             {
  1139.                 /* True if the directive was an "#ifndef" */
  1140.  
  1141.                 cond = (prep == PP_IFNDEF);
  1142.             }
  1143.         }
  1144.  
  1145.     PREP_COND:
  1146.  
  1147.         /* Come here for "#ifxxx" with 'cond' set to the condition */
  1148.  
  1149.         scanCheckEOL();
  1150.  
  1151.         /* Is the condition satisfied? */
  1152.  
  1153.         if  (cond)
  1154.         {
  1155.             /* Push an "if" record on the PP state stack */
  1156.  
  1157.             scanPPdscPush(PPS_IF);
  1158.         }
  1159.         else
  1160.         {
  1161.             /* Skip to a matching "else" or "endif" */
  1162.  
  1163.             scanSkipToDir(PPS_IF);
  1164.             goto DIR_DONE;
  1165.         }
  1166.  
  1167.         break;
  1168.  
  1169.     case PP_ELSE:
  1170.  
  1171.         /* We better be in an "if" part */
  1172.  
  1173.         if  (scanPrepList == NULL || scanPrepList->pplState != PPS_IF)
  1174.         {
  1175.             scanComp->cmpError(ERRbadElse);
  1176.             goto DIR_SKIP;
  1177.         }
  1178.  
  1179.         /* Skip to the matching "endif" */
  1180.  
  1181.         scanSkipToDir(PPS_ELSE);
  1182.         goto DIR_DONE;
  1183.  
  1184.     case PP_ENDIF:
  1185.  
  1186.         /* We better be in a pre-processing section */
  1187.  
  1188.         if  (scanPrepList == NULL)
  1189.         {
  1190.             scanComp->cmpError(ERRbadEndif);
  1191.             goto DIR_SKIP;
  1192.         }
  1193.  
  1194.         scanPPdscPop();
  1195.         break;
  1196.  
  1197.     case PP_ERROR:
  1198.         scanComp->cmpFatal(ERRerrDir);
  1199.         NO_WAY(!"should never return here");
  1200.  
  1201.     case PP_PRAGMA:
  1202.  
  1203.         if  (scan() != tkID)
  1204.             goto BAD_PRAGMA;
  1205.  
  1206.         /* Check for the pragmas we support */
  1207.  
  1208.         if  (!strcmp(scannerBuff, "pack"))
  1209.             goto PRAGMA_PACK;
  1210.         if  (!strcmp(scannerBuff, "message"))
  1211.             goto PRAGMA_MESSAGE;
  1212.         if  (!strcmp(scannerBuff, "warning"))
  1213.             goto PRAGMA_WARNING;
  1214.         if  (!strcmp(scannerBuff, "option"))
  1215.             goto PRAGMA_OPTION;
  1216.  
  1217.     BAD_PRAGMA:
  1218.  
  1219.         scanComp->cmpGenWarn(WRNbadPragma, scannerBuff);
  1220.         goto DIR_SKIP;
  1221.  
  1222.     PRAGMA_PACK:
  1223.  
  1224.         if  (scan() != tkLParen)
  1225.         {
  1226.             scanComp->cmpError(ERRnoLparen);
  1227.             goto DIR_SKIP;
  1228.         }
  1229.  
  1230.         switch (scan())
  1231.         {
  1232.         case tkIntCon:
  1233.             switch (scanTok.intCon.tokIntVal)
  1234.             {
  1235.             case 1:
  1236.             case 2:
  1237.             case 4:
  1238.             case 8:
  1239.             case 16:
  1240.                 scanParser->parseAlignSet(scanTok.intCon.tokIntVal);
  1241.                 break;
  1242.  
  1243.             default:
  1244.                 goto BAD_PACK;
  1245.             }
  1246.             break;
  1247.  
  1248.         case tkID:
  1249.  
  1250.             if      (!strcmp(scanTok.id.tokIdent->idSpelling(), "push"))
  1251.             {
  1252.                 scanParser->parseAlignPush();
  1253.                 break;
  1254.             }
  1255.             else if (!strcmp(scanTok.id.tokIdent->idSpelling(), "pop" ))
  1256.             {
  1257.                 scanParser->parseAlignPop ();
  1258.                 break;
  1259.             }
  1260.  
  1261.             // Fall through ....
  1262.  
  1263.         default:
  1264.  
  1265.         BAD_PACK:
  1266.  
  1267.             scanComp->cmpError(ERRbadAlign);
  1268.             goto DIR_SKIP;
  1269.         }
  1270.  
  1271.         if  (scan() != tkRParen)
  1272.         {
  1273.             scanComp->cmpError(ERRnoRparen);
  1274.             goto DIR_SKIP;
  1275.         }
  1276.  
  1277.         break;
  1278.  
  1279.     PRAGMA_MESSAGE:
  1280.  
  1281.         if  (scan() != tkLParen)
  1282.         {
  1283.             scanComp->cmpError(ERRnoLparen);
  1284.             goto DIR_SKIP;
  1285.         }
  1286.  
  1287.         if  (scan() != tkStrCon)
  1288.         {
  1289.             scanComp->cmpError(ERRnoString);
  1290.             goto DIR_SKIP;
  1291.         }
  1292.  
  1293.         for (;;)
  1294.         {
  1295.             unsigned        ch = readNextChar();
  1296.  
  1297.             if  (charType(ch) == _C_WSP)
  1298.                 continue;
  1299.  
  1300.             if  (ch != ')')
  1301.             {
  1302.                 scanComp->cmpError(ERRnoLparen);
  1303.                 goto DIR_SKIP;
  1304.             }
  1305.  
  1306.             break;
  1307.         }
  1308.  
  1309.         /* Print the string and make sure no garbage follows */
  1310.  
  1311.         if  ( !scanSkipToPP)
  1312.         {
  1313.             _write(1, scanTok.strCon.tokStrVal,
  1314.                       scanTok.strCon.tokStrLen);
  1315.             _write(1, "\n", 1);
  1316.         }
  1317.  
  1318.         break;
  1319.  
  1320.     PRAGMA_WARNING:
  1321.  
  1322.         if  (scan() != tkLParen)
  1323.         {
  1324.             scanComp->cmpError(ERRnoLparen);
  1325.             goto DIR_SKIP;
  1326.         }
  1327.  
  1328.         do
  1329.         {
  1330.             int             val;
  1331.  
  1332.             if  (scan() != tkID)
  1333.             {
  1334.                 if  (scanTok.tok != tkDEFAULT)
  1335.                 {
  1336.                     scanComp->cmpError(ERRnoIdent);
  1337.                     goto DIR_SKIP;
  1338.                 }
  1339.  
  1340.                 val = -1;
  1341.             }
  1342.             else if (!strcmp(scanTok.id.tokIdent->idSpelling(), "enable"))
  1343.             {
  1344.                 val = 1;
  1345.             }
  1346.             else if (!strcmp(scanTok.id.tokIdent->idSpelling(), "disable"))
  1347.             {
  1348.                 val = 0;
  1349.             }
  1350.             else
  1351.             {
  1352.                 scanComp->cmpGenWarn(WRNbadPragma, "warning");
  1353.                 goto DIR_SKIP;
  1354.             }
  1355.  
  1356.             if  (scan() != tkColon)
  1357.             {
  1358.                 scanComp->cmpError(ERRnoColon);
  1359.                 goto DIR_SKIP;
  1360.             }
  1361.  
  1362.             if  (scan() != tkIntCon)
  1363.             {
  1364.                 scanComp->cmpError(ERRnoIntExpr);
  1365.                 goto DIR_SKIP;
  1366.             }
  1367.  
  1368. //          printf("Warning %u\n", scanTok.intCon.tokIntVal);
  1369.  
  1370.             if  (scanTok.intCon.tokIntVal <  4000 ||
  1371.                  scanTok.intCon.tokIntVal >= 4000 + WRNcountWarn)
  1372.             {
  1373.                 scanComp->cmpGenWarn(WRNbadPragma, "warning");
  1374.                 goto DIR_SKIP;
  1375.             }
  1376.  
  1377.             scanTok.intCon.tokIntVal -= 4000;
  1378.  
  1379.             if  (val == -1)
  1380.                 val = scanComp->cmpInitialWarn[scanTok.intCon.tokIntVal];
  1381.  
  1382.             scanComp->cmpConfig.ccWarning[scanTok.intCon.tokIntVal] = val;
  1383.  
  1384.             /* Make sure we have room to record the pragma */
  1385.  
  1386.             if  (scanSaveNext >= scanSaveEndp)
  1387.                 scanSaveMoreSp();
  1388.  
  1389.             /* Record the pragma */
  1390.  
  1391. #if DISP_TOKEN_STREAMS
  1392.             printf("Save [%08X]: #pragma\n", scanSaveNext);
  1393. #endif
  1394.  
  1395.             *scanSaveNext++ = tkPragma;
  1396.             *scanSaveNext++ = (BYTE)val;
  1397.             *scanSaveNext++ = (BYTE)scanTok.intCon.tokIntVal;
  1398.         }
  1399.         while (scan() == tkComma);
  1400.  
  1401.         if  (scanTok.tok != tkRParen)
  1402.         {
  1403.             scanComp->cmpError(ERRnoRparen);
  1404.             goto DIR_SKIP;
  1405.         }
  1406.  
  1407.         break;
  1408.  
  1409.     case PP_DEFINE:
  1410.  
  1411.         /* Make sure we have an identifier */
  1412.  
  1413.         if  (!scanCollectId())
  1414.         {
  1415.             scanComp->cmpGenError(ERRnoIdent);
  1416.             break;
  1417.         }
  1418.  
  1419.         /* Are there macro arguments ? */
  1420.  
  1421.         if  (peekNextChar() == '(')
  1422.         {
  1423.             scanComp->cmpGenWarn(WRNmacroArgs);
  1424.             goto DIR_SKIP;
  1425.         }
  1426.  
  1427.         /* Stick the identifier in the keyword hash table */
  1428.  
  1429.         iden = scanHashKwd->hashString(scannerBuff); assert(iden);
  1430.  
  1431.         /* The definition should follow, collect it */
  1432.  
  1433.         dest = scannerBuff;
  1434.  
  1435.         while (charType(readNextChar()) == _C_WSP);
  1436.         undoNextChar();
  1437.  
  1438.         for (;;)
  1439.         {
  1440.             unsigned        ch = readNextChar();
  1441.  
  1442.             switch  (charType(ch))
  1443.             {
  1444.             case _C_SLH:
  1445.  
  1446.                 /* Check for start of comment */
  1447.  
  1448.                 switch (charType(readNextChar()))
  1449.                 {
  1450.                 case _C_SLH:
  1451.                     undoNextChar();
  1452.                     goto DONE_DEF;
  1453.  
  1454.                 case _C_MUL:
  1455.                     scanSkipComment();
  1456.                     continue;
  1457.                 }
  1458.                 break;
  1459.  
  1460.             case _C_WSP:
  1461.             case _C_NWL:
  1462.             case _C_EOF:
  1463.                 undoNextChar();
  1464.                 goto DONE_DEF;
  1465.             }
  1466.  
  1467.             *dest++ = ch;
  1468.         }
  1469.  
  1470.     DONE_DEF:
  1471.  
  1472.         /* If there is no value, stick in "1" */
  1473.  
  1474.         if  (dest == scannerBuff)
  1475.             *dest++ = '1';
  1476.  
  1477.         *dest = 0;
  1478.  
  1479.         if  (!scanComp->cmpConfig.ccNoDefines)
  1480.             scanDefMac(iden->idSpelling(), scannerBuff, false, true);
  1481.  
  1482.         break;
  1483.  
  1484.     PRAGMA_OPTION:
  1485.  
  1486.         switch (scanSkipWsp(readNextChar(), true))
  1487.         {
  1488.         case '-':
  1489.         case '/':
  1490.             break;
  1491.  
  1492.         default:
  1493.             scanComp->cmpError(ERRbadPrgOpt);
  1494.             goto DIR_SKIP;
  1495.         }
  1496.  
  1497.         /* Collect the option string */
  1498.  
  1499.         undoNextChar();
  1500.  
  1501.         for (dest = scannerBuff;;)
  1502.         {
  1503.             unsigned        ch = readNextChar();
  1504.  
  1505.             switch  (charType(ch))
  1506.             {
  1507.             case _C_SLH:
  1508.  
  1509.                 /* Check for start of comment */
  1510.  
  1511.                 switch (charType(readNextChar()))
  1512.                 {
  1513.                 case _C_SLH:
  1514.                     undoNextChar();
  1515.                     goto DONE_DEF;
  1516.  
  1517.                 case _C_MUL:
  1518.                     scanSkipComment();
  1519.                     continue;
  1520.                 }
  1521.                 break;
  1522.  
  1523.             case _C_WSP:
  1524.             case _C_NWL:
  1525.             case _C_EOF:
  1526.                 undoNextChar();
  1527.                 goto DONE_OPT;
  1528.             }
  1529.  
  1530.             *dest++ = ch;
  1531.         }
  1532.  
  1533.     DONE_OPT:
  1534.  
  1535.         *dest = 0;
  1536.  
  1537. //      printf("Option string = '%s'\n", scannerBuff);
  1538.  
  1539.         if  (processOption(scannerBuff, scanComp))
  1540.             scanComp->cmpError(ERRbadPrgOpt);
  1541.  
  1542.         break;
  1543.     }
  1544.  
  1545.     /* Here we make sure there is no extra garbage after the directive */
  1546.  
  1547.     scanCheckEOL();
  1548.  
  1549. DIR_DONE:
  1550.  
  1551.     scanStopAtEOL = false;
  1552.     scanTokRecord = true;
  1553.  
  1554.     return  PP_NONE;
  1555.  
  1556. DIR_SKIP:
  1557.  
  1558.     scanSkipToEOL();
  1559.  
  1560.     scanStopAtEOL = false;
  1561.     scanTokRecord = true;
  1562.  
  1563.     return  PP_NONE;
  1564. }
  1565.  
  1566. /*****************************************************************************
  1567.  *
  1568.  *  Initialize the scanner - needs to be called once per lifetime.
  1569.  */
  1570.  
  1571. bool            scanner::scanInit(Compiler comp, HashTab hashKwd)
  1572. {
  1573.     /* Remember the compiler and hash table */
  1574.  
  1575.     scanComp       = comp;
  1576.     scanHashKwd    = hashKwd;
  1577.  
  1578.     /* Initialize any other global state */
  1579.  
  1580.     scanMacros     = NULL;
  1581.     scanPrepFree   = NULL;
  1582.  
  1583.     scanStrLitBuff = NULL;
  1584.  
  1585.     scanSkipInit();
  1586.  
  1587.     /* Prepare to record tokens */
  1588.  
  1589.     scanSaveBase   =
  1590.     scanSaveNext   =
  1591.     scanSaveEndp   = NULL;
  1592.  
  1593.     scanSaveMoreSp();
  1594.  
  1595.     return  false;
  1596. }
  1597.  
  1598. /*****************************************************************************
  1599.  *
  1600.  *  Initializes the scanner to prepare to scan the given source file.
  1601.  */
  1602.  
  1603. void            scanner::scanStart(SymDef               sourceCSym,
  1604.                                    const    char     *  sourceFile,
  1605.                                    QueuedFile           sourceBuff,
  1606.                                    const    char     *  sourceText,
  1607.                                    HashTab              hash,
  1608.                                    norls_allocator   *  alloc)
  1609. {
  1610.     assert(sizeof(scannerBuff) > MAX_IDENT_LEN);
  1611.  
  1612.     /* Remember which compilation unit we're in */
  1613.  
  1614.     scanCompUnit    = sourceCSym;
  1615.  
  1616.     /* Remember which allocator we're supposed to use */
  1617.  
  1618.     scanAlloc       = alloc;
  1619.  
  1620.     /* We're not in skipping mode */
  1621.  
  1622.     scanSkipToPP    = false;
  1623.  
  1624.     /* The initial state is "recording tokens" */
  1625.  
  1626.     scanTokRecord   = true;
  1627.     scanTokReplay   = NULL;
  1628.  
  1629.     /* Prepare to record tokens */
  1630.  
  1631.     scanSaveLastLn  = 1;
  1632.  
  1633.     /* Make the hash table conveniently available */
  1634.  
  1635.     scanHashSrc     = hash;
  1636.  
  1637.     /* We're not in a conditional compilation block */
  1638.  
  1639.     scanPrepList    = NULL;
  1640.  
  1641.     /* Normally we pay no attention to newlines */
  1642.  
  1643.     scanStopAtEOL   = false;
  1644.  
  1645.     /* We're not evaluating a constant expression right now */
  1646.  
  1647.     scanInPPexpr    = false;
  1648.  
  1649.     /* Go ahead and expand macros for now */
  1650.  
  1651.     scanNoMacExp    = false;
  1652.  
  1653.     /* We're not processing a generic instance specification */
  1654.  
  1655.     scanNestedGTcnt = 0;
  1656.  
  1657.     /* We haven't seen any brackets yet */
  1658.  
  1659.     /* Open the input file */
  1660.  
  1661.     if  (sourceBuff || sourceText)
  1662.     {
  1663.         scanInputFile.inputStreamInit(scanComp, sourceBuff, sourceText);
  1664.     }
  1665.     else
  1666.     {
  1667.         char    *   fname;
  1668.  
  1669.         /* Allocate a more permanent copy of the file name */
  1670.  
  1671.         fname = (char *)alloc->nraAlloc(roundUp(strlen(sourceFile)+1));
  1672.         strcpy(fname, sourceFile);
  1673.  
  1674.         if  (scanInputFile.inputStreamInit(scanComp, fname, true))
  1675.             scanComp->cmpGenFatal(ERRopenRdErr, sourceFile);
  1676.     }
  1677.  
  1678.     /* Clear any other state */
  1679.  
  1680.     scanLookAheadCount = 0;
  1681.  
  1682.     /* Initialize the source position tracking logic */
  1683.  
  1684.     scanRecordNL(false);
  1685. }
  1686.  
  1687. /*****************************************************************************
  1688.  *
  1689.  *  We're done parsing the current source -- free up any resources and close
  1690.  *  the file.
  1691.  */
  1692.  
  1693. void                scanner::scanClose()
  1694. {
  1695.     scanInputFile.inputStreamDone();
  1696. }
  1697.  
  1698. /*****************************************************************************
  1699.  *
  1700.  *  Get the scanner initialized and started.
  1701.  */
  1702.  
  1703. void                scanner::scanReset()
  1704. {
  1705.     scanLookAheadCount = 0;
  1706.  
  1707.     scanSkipToPP       = false;
  1708.  
  1709.     scanTokRecord      = false;
  1710.  
  1711.     scanPrepList       = NULL;
  1712.  
  1713.     scanStopAtEOL      = false;
  1714.     scanInPPexpr       = false;
  1715.     scanNoMacExp       = false;
  1716.  
  1717.     /* Get things started */
  1718.  
  1719.     scanTok.tok = tkNone; scan();
  1720. }
  1721.  
  1722. /*****************************************************************************
  1723.  *
  1724.  *  Restart scanning from the specified section of source text (which has
  1725.  *  been previously been scanned and kept open). The line# / columnm info
  1726.  *  is needed for accurate error reporting.
  1727.  */
  1728.  
  1729. void                scanner::scanRestart(SymDef            sourceCSym,
  1730.                                          const char      * sourceFile,
  1731.                                          scanPosTP         begAddr,
  1732. //                                       scanPosTP         endAddr,
  1733.                                          unsigned          begLine,
  1734. //                                       unsigned          begCol,
  1735.                                          norls_allocator * alloc)
  1736. {
  1737.     scanCompUnit       = sourceCSym;
  1738.  
  1739.     scanSaveLastLn     =
  1740.     scanTokLineNo      = begLine;
  1741. //  scanTokColumn      = begCol;
  1742.  
  1743.     scanTokReplay      =
  1744.     scanTokSrcPos      = begAddr;
  1745.  
  1746.     scanAlloc          = alloc;
  1747.  
  1748.     scanReset();
  1749. }
  1750.  
  1751. /*****************************************************************************
  1752.  *
  1753.  *  Scan from the specified string.
  1754.  */
  1755.  
  1756. void                scanner::scanString(const char        * sourceText,
  1757.                                         norls_allocator   * alloc)
  1758. {
  1759.     scanInputFile.inputStreamInit(scanComp, NULL, sourceText);
  1760.  
  1761.     scanTokLineNo      = 1;
  1762. //  scanTokColumn      = 1;
  1763.     scanAlloc          = alloc;
  1764.  
  1765.     scanTokRecord      = false;
  1766.     scanTokReplay      = NULL;
  1767.  
  1768.     scanReset();
  1769. }
  1770.  
  1771. /*****************************************************************************
  1772.  *
  1773.  *  Given the first character (which is known to be a character that can
  1774.  *  start an identifier), parse an identifier.
  1775.  */
  1776.  
  1777. tokens              scanner::scanIdentifier(int ch)
  1778. {
  1779.     unsigned        hashVal;
  1780.     unsigned        hashChv;
  1781.  
  1782.     bool            hadWide = false;
  1783.  
  1784. #if FV_DBCS
  1785.     BOOL            hasDBCS = FALSE;
  1786. #endif
  1787.  
  1788.     Ident           iden;
  1789.  
  1790.     char    *       savePtr = scannerBuff;
  1791.  
  1792.     /* Get the hash function started */
  1793.  
  1794.     hashFNstart(hashVal);
  1795.  
  1796.     /* Accumuluate the identifier string */
  1797.  
  1798.     for (;;)
  1799.     {
  1800.         assert(((charFlags[ch] & _CF_IDENT_OK) != 0) ==
  1801.                ((scanHashValIds[ch]          ) != 0));
  1802.  
  1803.         hashChv = scanHashValIds[ch];
  1804.         if  (!hashChv)
  1805.             break;
  1806.  
  1807.         hashFNaddCh(hashVal, hashChv);
  1808.  
  1809.         *savePtr++ = ch;
  1810.  
  1811.         if  (savePtr >= scannerBuff + sizeof(scannerBuff))
  1812.             goto ID_TOO_LONG;
  1813.  
  1814.         ch = readNextChar();
  1815.     }
  1816.  
  1817.     /* Put back the last character */
  1818.  
  1819.     undoNextChar();
  1820.  
  1821.     /* Make sure the identifier is not too long */
  1822.  
  1823.     if  (savePtr > scannerBuff + MAX_IDENT_LEN)
  1824.         goto ID_TOO_LONG;
  1825.  
  1826.     /* Make sure the name is null-terminated */
  1827.  
  1828.     *savePtr = 0;
  1829.  
  1830.     /* Finish computing the hash value */
  1831.  
  1832.     hashVal = hashFNvalue(hashVal);
  1833.  
  1834. CHK_MAC:
  1835.  
  1836.     /* Hash the identifier into the global/keyword table */
  1837.  
  1838.     iden = scanHashKwd->lookupName(scannerBuff,
  1839.                                    savePtr - scannerBuff,
  1840.                                    hashVal);
  1841.  
  1842.     if  (!iden)
  1843.         goto NOT_KWD2;
  1844.  
  1845.     /* Mark the identifier entry as referenced */
  1846.  
  1847.     hashTab::setIdentFlags(iden, IDF_USED);
  1848.  
  1849.     /* Check for a macro */
  1850.  
  1851.     if  ((hashTab::getIdentFlags(iden) & IDF_MACRO) && (!scanNoMacExp)
  1852.                                                     && (!scanStopAtEOL || scanInPPexpr))
  1853.     {
  1854.         const   char *  str;
  1855.         size_t          len;
  1856.  
  1857.         MacDef          mdef = scanFindMac(iden);
  1858.  
  1859.         if  (!mdef->mdIsId)
  1860.         {
  1861.             // UNDONE: Check type and all that
  1862.  
  1863.             scanTok.tok              = tkIntCon;
  1864.             scanTok.intCon.tokIntTyp = TYP_INT;
  1865.             scanTok.intCon.tokIntVal = mdef->mdDef.mdCons;
  1866.  
  1867.             return  tkIntCon;
  1868.         }
  1869.  
  1870.         /* Get the definition identifier */
  1871.  
  1872.         iden = mdef->mdDef.mdIden;
  1873.  
  1874.         if  (!iden)
  1875.         {
  1876.             if  (scanInPPexpr)
  1877.             {
  1878.                 scanTok.tok              = tkIntCon;
  1879.                 scanTok.intCon.tokIntTyp = TYP_INT;
  1880.                 scanTok.intCon.tokIntVal = 0;
  1881.  
  1882.                 return  tkIntCon;
  1883.             }
  1884.             else
  1885.             {
  1886.                 return  tkNone;
  1887.             }
  1888.         }
  1889.  
  1890.         /* Copy the macro definition string */
  1891.  
  1892.         str = hashTab::identSpelling(iden);
  1893.         len = hashTab::identSpellLen(iden);
  1894.  
  1895.         strcpy(scannerBuff, str); savePtr = scannerBuff + len;
  1896.  
  1897.         /* Compute the hash value */
  1898.  
  1899.         hashVal = hashTab::hashComputeHashVal(str, len);
  1900.  
  1901.         /* Try hashing the name again */
  1902.  
  1903.         iden = scanHashKwd->lookupName(str, len, hashVal);
  1904.         if  (!mdef->mdBuiltin)
  1905.             goto CHK_MAC;
  1906.  
  1907.         /* This should definitely be a keyword (or other token) */
  1908.  
  1909.         assert(hashTab::tokenOfIdent(iden) != tkNone);
  1910.     }
  1911.  
  1912.     /* Is the identifier a keyword? */
  1913.  
  1914.     if  (hashTab::tokenOfIdent(iden) != tkNone)
  1915.     {
  1916.         scanTok.tok = hashTab::tokenOfIdent(iden);
  1917.  
  1918.         if  (scanTok.tok == tkLINE)
  1919.         {
  1920.             scanTok.tok              = tkIntCon;
  1921.             scanTok.intCon.tokIntTyp = TYP_UINT;
  1922.             scanTok.intCon.tokIntVal = scanGetTokenLno();
  1923.  
  1924.             return  (scanTok.tok = tkIntCon);
  1925.         }
  1926.  
  1927.         if  (scanTok.tok == tkFILE)
  1928.         {
  1929.             strcpy(scannerBuff, scanInputFile.inputSrcFileName());
  1930.  
  1931.             scanTok.strCon.tokStrVal  = scannerBuff;
  1932.             scanTok.strCon.tokStrLen  = strlen(scannerBuff);
  1933.             scanTok.strCon.tokStrType = 0;
  1934.             scanTok.strCon.tokStrWide = false;
  1935.  
  1936.             return  (scanTok.tok = tkStrCon);
  1937.         }
  1938.     }
  1939.     else
  1940.     {
  1941.         /* Not a keyword, hash into the source hash */
  1942.  
  1943.     NOT_KWD2:
  1944.  
  1945.         if  (scanInPPexpr)
  1946.         {
  1947.             scanTok.tok              = tkIntCon;
  1948.             scanTok.intCon.tokIntTyp = TYP_INT;
  1949.             scanTok.intCon.tokIntVal = 0;
  1950.         }
  1951.         else
  1952.         {
  1953.             scanTok.id.tokIdent = iden = scanHashSrc->hashName(scannerBuff,
  1954.                                                                hashVal,
  1955.                                                                savePtr - scannerBuff,
  1956.                                                                hadWide);
  1957.  
  1958.             /* Mark the identifier entry as referenced */
  1959.  
  1960.             hashTab::setIdentFlags(iden, IDF_USED);
  1961.  
  1962.             /* The token is an ordinary identifier */
  1963.  
  1964.             scanTok.tok = tkID;
  1965.         }
  1966.     }
  1967.  
  1968.     return scanTok.tok;
  1969.  
  1970.     /* We come here if the identifier turned out to be too long */
  1971.  
  1972. ID_TOO_LONG:
  1973.  
  1974.     scanComp->cmpError(ERRidTooLong);
  1975.     UNIMPL(!"swallow the rest of the long identifier");
  1976.     return tkNone;
  1977. }
  1978.  
  1979. /*****************************************************************************
  1980.  *
  1981.  *  Parses a numeric constant. The current character (passed in as 'ch')
  1982.  *  is either a decimal digit or '.' (which could start a floating point
  1983.  *  number).
  1984.  */
  1985.  
  1986. tokens              scanner::scanNumericConstant(int ch)
  1987. {
  1988.     bool            hadDot  = false;
  1989.     bool            hadExp  = false;
  1990.     bool            hadDigs = false;
  1991.     unsigned        numBase = 0;
  1992.  
  1993.     char *          numPtr  = scannerBuff;
  1994.  
  1995.     /* Assume that this will be an integer */
  1996.  
  1997.     scanTok.tok              = tkIntCon;
  1998.     scanTok.intCon.tokIntTyp = TYP_INT;
  1999.  
  2000.     /* First collect the number string, and then figure out its type */
  2001.  
  2002.     if  (ch == '0')
  2003.     {
  2004.         /* This is most likely an octal or hex integer */
  2005.  
  2006.         switch (peekNextChar())
  2007.         {
  2008.         case 'x':
  2009.         case 'X':
  2010.             numBase = 16;
  2011.             readNextChar();
  2012.             break;
  2013.         }
  2014.     }
  2015.  
  2016.     /* At this point, 'ch' is the next character */
  2017.  
  2018.     for (;;)
  2019.     {
  2020.         /* Save the character we just read, and make sure it's OK */
  2021.  
  2022.         *numPtr++ = ch;
  2023.  
  2024.         /* We're certainly done if the character is non-ASCII */
  2025.  
  2026.         if  (ch > 0xFF)
  2027.             goto ENDNUM;
  2028.  
  2029.         if  (charType(ch) == _C_DIG)
  2030.         {
  2031.             /* It's an ordinary digit */
  2032.  
  2033.             hadDigs = true;
  2034.             goto MORE;
  2035.         }
  2036.  
  2037.         if ((charFlags[ch] & _CF_HEXDIGIT) && numBase == 16)
  2038.         {
  2039.             /* A hex digit */
  2040.  
  2041.             hadDigs = true;
  2042.             goto MORE;
  2043.         }
  2044.  
  2045.         switch (ch)
  2046.         {
  2047.         case '.':
  2048.             if  (!hadDot && !hadExp && !numBase && peekNextChar() != '.')
  2049.             {
  2050.                 hadDot = true;
  2051.  
  2052.                 /* This will be a floating point number */
  2053.  
  2054.                 scanTok.tok = tkDblCon;
  2055.                 goto MORE;
  2056.             }
  2057.             break;
  2058.  
  2059.         case 'e':
  2060.         case 'E':
  2061.             if  (!hadExp && !numBase)
  2062.             {
  2063.                 /* We have an exponent */
  2064.  
  2065.                 hadExp = true;
  2066.  
  2067.                 /* Check for '+' or '-' following the exponent */
  2068.  
  2069.                 ch = readNextChar();
  2070.                 if  (ch == '+' || ch == '-')
  2071.                     *numPtr++ = ch;
  2072.                 else
  2073.                     undoNextChar();
  2074.  
  2075.                 /* This will definitely be a floating point number */
  2076.  
  2077.                 scanTok.tok = tkDblCon;
  2078.                 goto MORE;
  2079.             }
  2080.             break;
  2081.  
  2082.         case 'f':
  2083.         case 'F':
  2084.             if  (!numBase)
  2085.             {
  2086.                 /* This will be a 'float' constant */
  2087.  
  2088.                 scanTok.tok = tkFltCon;
  2089.  
  2090.                 /* Skip the character and stop */
  2091.  
  2092.                 goto ENDN;
  2093.             }
  2094.             break;
  2095.  
  2096.         case 'd':
  2097.         case 'D':
  2098.             if  (!numBase)
  2099.             {
  2100.                 /* This will be a 'double' constant */
  2101.  
  2102.                 scanTok.tok = tkDblCon;
  2103.  
  2104.                 /* Skip the character and stop */
  2105.  
  2106.                 goto ENDN;
  2107.             }
  2108.             break;
  2109.  
  2110.         case 'l':
  2111.         case 'L':
  2112.  
  2113.             if  (scanTok.tok == tkIntCon)
  2114.             {
  2115.                 /* This will be a 'long' integer */
  2116.  
  2117.                 scanTok.intCon.tokIntTyp = TYP_LONG;
  2118.  
  2119.                 /* Skip the character and stop */
  2120.  
  2121.                 goto ENDN;  // UNDONE: check for "LU" suffix on numbers
  2122.             }
  2123.             break;
  2124.  
  2125.         case 'u':
  2126.         case 'U':
  2127.  
  2128.             /* This will be an unsigned integer */
  2129.  
  2130.             if  (scanTok.tok == tkIntCon)
  2131.             {
  2132.                 scanTok.intCon.tokIntTyp = TYP_UINT;
  2133.             }
  2134.             else
  2135.             {
  2136.                 scanTok.intCon.tokIntTyp = TYP_ULONG;
  2137.             }
  2138.  
  2139.             /* Check for 'l' and we're done with the constant */
  2140.  
  2141.             switch (peekNextChar())
  2142.             {
  2143.             case 'l':
  2144.             case 'L':
  2145.                 scanTok.intCon.tokIntTyp = TYP_ULONG;
  2146.                 readNextChar();
  2147.                 break;
  2148.             }
  2149.  
  2150.             goto ENDN;
  2151.         }
  2152.  
  2153.     ENDNUM:
  2154.  
  2155.         /* This character can't be part of the number */
  2156.  
  2157.         undoNextChar();
  2158.         break;
  2159.  
  2160.     MORE:
  2161.  
  2162.         ch = readNextChar();
  2163.     }
  2164.  
  2165. ENDN:
  2166.  
  2167.     /* Null-terminate the number string */
  2168.  
  2169.     numPtr[-1] = 0;
  2170.  
  2171.     /* If there were no digits at all, it's hopeless */
  2172.  
  2173.     if  (!hadDigs)
  2174.         goto NUM_ERR;
  2175.  
  2176.     /* Does the number look like an integer? */
  2177.  
  2178.     if  (scanTok.tok == tkIntCon)
  2179.     {
  2180.         char    *       numPtr = scannerBuff;
  2181.         int             maxDig = '9';
  2182.  
  2183.         var_types       origTp = scanTok.intCon.tokIntTyp;
  2184.  
  2185.         __int64         value  = 0;
  2186.         __int64         maxMask;
  2187.  
  2188.         unsigned        numBasx;
  2189.  
  2190.         /* If the number starts with '0', it will be octal */
  2191.  
  2192.         if (*numPtr == '0' && !numBase)
  2193.             numBase = 8;
  2194.  
  2195.         /*
  2196.             The following table is indexed by the type and the number
  2197.             base (hex = 0, octal = 1), it's not used for decimal nums.
  2198.         */
  2199.  
  2200.         static
  2201.         __int64         maxMasks[][2] =
  2202.         {
  2203.             //-------------------------------------------------------------
  2204.             //                       HEX                  OCT
  2205.             //-------------------------------------------------------------
  2206.             /* TYP_INT     */  { 0xF8000000         , 0xD8000000          },
  2207.             /* TYP_UINT    */  { 0x70000000         , 0x50000000          },
  2208.             /* TYP_NATINT  */  { 0                  , 0                   },
  2209.             /* TYP_NATUINT */  { 0                  , 0                   },
  2210.             /* TYP_LONG    */  { 0xF800000000000000L, 0xD800000000000000L },
  2211.             /* TYP_ULONG   */  { 0x7000000000000000L, 0x5000000000000000L },
  2212.         };
  2213.  
  2214.         /* Convert the number and make sure it fits in an integer */
  2215.  
  2216.         numBasx = 0;
  2217.  
  2218.         if  (numBase == 0)
  2219.         {
  2220.             maxMask = 0;
  2221.         }
  2222.         else
  2223.         {
  2224.             if  (numBase == 8)
  2225.             {
  2226.                 maxDig  = '7';
  2227.                 numBasx = 1;
  2228.             }
  2229.  
  2230.             maxMask = maxMasks[origTp - TYP_INT][numBasx];
  2231.         }
  2232.  
  2233.         do
  2234.         {
  2235.             int     ch = *numPtr++;
  2236.  
  2237.             /* Check the number for overflow */
  2238.  
  2239.             if  (!numBase)
  2240.             {
  2241.                 __int64             newVal;
  2242.  
  2243.                 /* We have a decimal constant */
  2244.  
  2245.                 assert(ch >= '0' && ch <= '9');
  2246.  
  2247.                 newVal = 10 * value + (ch - '0');
  2248.  
  2249.                 if  (newVal < 0)
  2250.                 {
  2251.                     /* This is an implicitly unsigned long constant, right? */
  2252.  
  2253.                     scanTok.intCon.tokIntTyp = TYP_ULONG;
  2254.                 }
  2255.                 else
  2256.                 {
  2257.                     if  ((newVal & 0xFFFFFFFF00000000L) && !numBase
  2258.                                                         && scanTok.intCon.tokIntTyp < TYP_LONG)
  2259.                     {
  2260.                         /* A signed 32-bit decimal constant turning 64-bit */
  2261.  
  2262.                         if  (scanTok.intCon.tokIntTyp == TYP_INT)
  2263.                              scanTok.intCon.tokIntTyp = TYP_LONG;
  2264.                         else
  2265.                              scanTok.intCon.tokIntTyp = TYP_ULONG;
  2266.                     }
  2267.                 }
  2268.  
  2269.                 if  (newVal & maxMask)
  2270.                     goto NUM_ERR;
  2271.  
  2272.                 value = newVal;
  2273.             }
  2274.             else
  2275.             {
  2276.                 /* We have an unsigned octal or hex number */
  2277.  
  2278.                 while (value & maxMask)
  2279.                 {
  2280.                     /* Can we implicitly switch to a larger type? */
  2281.  
  2282.                     switch (scanTok.intCon.tokIntTyp)
  2283.                     {
  2284.                     case TYP_INT:
  2285.                         scanTok.intCon.tokIntTyp = TYP_UINT;
  2286.                         break;
  2287.  
  2288.                     case TYP_UINT:
  2289.                         if  (origTp == TYP_INT)
  2290.                             scanTok.intCon.tokIntTyp = TYP_LONG;
  2291.                         else
  2292.                             scanTok.intCon.tokIntTyp = TYP_ULONG;
  2293.                         break;
  2294.  
  2295.                     case TYP_LONG:
  2296.                         scanTok.intCon.tokIntTyp = TYP_ULONG;
  2297.                         break;
  2298.  
  2299.                     case TYP_ULONG:
  2300.                         goto NUM_ERR;
  2301.  
  2302.                     default:
  2303.                         NO_WAY(!"what?");
  2304.                     }
  2305.  
  2306.                     maxMask = maxMasks[scanTok.intCon.tokIntTyp - TYP_INT][numBasx];
  2307.                 }
  2308.  
  2309.                 value *= numBase;
  2310.  
  2311.                 if  (ch <= '9')
  2312.                 {
  2313.                     if  (ch > maxDig)
  2314.                         goto NUM_ERR;
  2315.  
  2316.                     value |= ch - '0';
  2317.                 }
  2318.                 else
  2319.                 {
  2320.                     value |= toupper(ch) - 'A' + 10;
  2321.                 }
  2322.             }
  2323.         }
  2324.         while   (*numPtr);
  2325.  
  2326.         if  (scanTok.intCon.tokIntTyp >= TYP_LONG)
  2327.         {
  2328.             scanTok.tok              = tkLngCon;
  2329.             scanTok.lngCon.tokLngVal = value;
  2330.         }
  2331.         else
  2332.         {
  2333.             scanTok.intCon.tokIntVal = (__int32)value;
  2334.         }
  2335.  
  2336.         return scanTok.tok;
  2337.     }
  2338.  
  2339.     /* Convert the number (at this point we must have a floating point value) */
  2340.  
  2341.     if  (scanTok.tok == tkFltCon)
  2342.     {
  2343.         // UNDONE: check for illegal float number!
  2344.  
  2345.         scanTok.fltCon.tokFltVal = (float)atof(scannerBuff);
  2346.  
  2347. //      if  (negate)
  2348. //          scanTok.fltCon.tokFltVal = -scanTok.fltCon.tokFltVal;
  2349.     }
  2350.     else
  2351.     {
  2352.         assert(scanTok.tok == tkDblCon);
  2353.  
  2354.         // UNDONE: check for illegal float number!
  2355.  
  2356.         scanTok.dblCon.tokDblVal = atof(scannerBuff);
  2357.  
  2358. //      if  (negate)
  2359. //          scanTok.dblCon.tokDblVal = -scanTok.dblCon.tokDblVal;
  2360.     }
  2361.  
  2362.     return  scanTok.tok;
  2363.  
  2364. NUM_ERR:
  2365.  
  2366.     scanComp->cmpError(ERRbadNumber);
  2367.  
  2368.     scanTok.intCon.tokIntVal = 0;
  2369.     scanTok.intCon.tokIntTyp = TYP_UNDEF;
  2370.  
  2371.     return  scanTok.tok;
  2372. }
  2373.  
  2374. /*****************************************************************************
  2375.  *
  2376.  *  Process a '\' sequence (found within a string/character literal).
  2377.  */
  2378.  
  2379. unsigned            scanner::scanEscapeSeq(bool *newLnFlag)
  2380. {
  2381.     unsigned        ch = readNextChar();
  2382.  
  2383.     if  (newLnFlag) *newLnFlag = false;
  2384.  
  2385.     switch (ch)
  2386.     {
  2387.         unsigned        uc;
  2388.         unsigned        digCnt;
  2389.         bool            isHex;
  2390.  
  2391.     case 'b': ch = '\b'; break;
  2392.     case 'n': ch = '\n'; break;
  2393.     case 't': ch = '\t'; break;
  2394.     case 'r': ch = '\r'; break;
  2395.     case 'a': ch = '\a'; break;
  2396.     case 'f': ch = '\f'; break;
  2397.  
  2398.     case 'u':
  2399.         isHex = false;
  2400.         goto HEXCH;
  2401.  
  2402.     case 'x':
  2403.  
  2404.         isHex = true;
  2405.  
  2406.     HEXCH:
  2407.  
  2408.         for (ch = 0, digCnt = 4; digCnt; digCnt--)
  2409.         {
  2410.             unsigned    uc = readNextChar();
  2411.  
  2412.             if  (charType(uc) == _C_DIG)
  2413.             {
  2414.                 /* It's an ordinary digit */
  2415.  
  2416.                 uc -= '0';
  2417.             }
  2418.             else if (uc >= 'A' && uc <= 'F')
  2419.             {
  2420.                 /* It's an uppercase hex digit */
  2421.  
  2422.                 uc -= 'A' - 10;
  2423.             }
  2424.             else if (uc >= 'a' && uc <= 'f')
  2425.             {
  2426.                 /* It's a  lowercase hex digit */
  2427.  
  2428.                 uc -= 'a' - 10;
  2429.             }
  2430.             else
  2431.             {
  2432.                 undoNextChar();
  2433.                 break;
  2434.             }
  2435.  
  2436.             ch = (ch << 4) | uc;
  2437.         }
  2438.  
  2439.         /* For some reason hex/oct constant may not specify a character > 0xFF */
  2440.  
  2441.         if  (isHex && (ch & 0xFFFFFF00))
  2442.             scanComp->cmpError(ERRbadEscCh);
  2443.  
  2444.         break;
  2445.  
  2446.     case '0':
  2447.     case '1':
  2448.     case '2':
  2449.     case '3':
  2450.     case '4':
  2451.     case '5':
  2452.     case '6':
  2453.     case '7':
  2454.     case '8':
  2455.     case '9':
  2456.  
  2457.         for (uc = ch, ch = 0;;)
  2458.         {
  2459.             if  (ch & 0xFF000000)
  2460.                 scanComp->cmpError(ERRbadEscCh);
  2461.  
  2462.             ch = (ch << 3) | (uc - '0');
  2463.  
  2464.             uc = readNextChar();
  2465.  
  2466.             if  (uc < '0' || uc > '7')
  2467.             {
  2468.                 undoNextChar();
  2469.                 break;
  2470.             }
  2471.         }
  2472.  
  2473.         /* For some reason hex/oct constant may not specify a character > 0xFF */
  2474.  
  2475.         if  (ch & 0xFFFFFF00)
  2476.             scanComp->cmpError(ERRbadEscCh);
  2477.  
  2478.         break;
  2479.  
  2480.     case '\n':
  2481.     case '\r':
  2482.         if  (newLnFlag)
  2483.         {
  2484.             scanNewLine(ch);
  2485.             *newLnFlag = true;
  2486.             return 0;
  2487.         }
  2488.         break;
  2489.  
  2490.     case '"':
  2491.     case '\'':
  2492.     case '\\':
  2493.         break;
  2494.  
  2495.     default:
  2496.         scanComp->cmpGenWarn(WRNbadEsc, ch);
  2497.         break;
  2498.     }
  2499.  
  2500.     return ch;
  2501. }
  2502.  
  2503. /*****************************************************************************
  2504.  *
  2505.  *  Parses a character constant.
  2506.  */
  2507.  
  2508. tokens              scanner::scanCharConstant()
  2509. {
  2510.     unsigned        ch = readNextChar();
  2511.  
  2512.     switch  (charType(ch))
  2513.     {
  2514.     case _C_BSL:
  2515.         ch = scanEscapeSeq(NULL);
  2516.         break;
  2517.  
  2518.     case _C_NWL:
  2519.         undoNextChar();
  2520.         scanComp->cmpError(ERRbadCharCns);
  2521.         goto DONE;
  2522.  
  2523. #if FV_DBCS
  2524.     case _C_XLD:
  2525.         ch = readPrevDBch();
  2526.         break;
  2527. #endif
  2528.  
  2529.     }
  2530.  
  2531.     if  (wideCharType(readNextChar()) != _C_APO)
  2532.         scanComp->cmpError(ERRbadCharCns);
  2533.  
  2534. DONE:
  2535.  
  2536.     scanTok.tok              = tkIntCon;
  2537.     scanTok.intCon.tokIntTyp = scanComp->cmpConfig.ccOldStyle ? TYP_CHAR : TYP_WCHAR;
  2538.     scanTok.intCon.tokIntVal = ch;
  2539.  
  2540.     return  tkIntCon;
  2541. }
  2542.  
  2543. /*****************************************************************************
  2544.  *
  2545.  *  Parses a string constant.
  2546.  */
  2547.  
  2548. tokens              scanner::scanStrgConstant(int prefixChar)
  2549. {
  2550.     char    *       saveAdr = scannerBuff;
  2551.     char    *       savePtr = scannerBuff;
  2552.     char    *       saveMax = scannerBuff + sizeof(scannerBuff) - 7;
  2553.     bool            hasWide = false;
  2554.  
  2555.     /* Use the "big" buffer if we have one */
  2556.  
  2557.     if  (scanStrLitBuff)
  2558.     {
  2559.         saveAdr =
  2560.         savePtr = scanStrLitBuff;
  2561.         saveMax = scanStrLitBuff + scanStrLitBsiz - 7;
  2562.     }
  2563.  
  2564.     for (;;)
  2565.     {
  2566.         unsigned    ch = readNextChar();
  2567.  
  2568.         /* Check for an escape sequence, new-line, and end of string */
  2569.  
  2570.         switch  (charType(ch))
  2571.         {
  2572.         case _C_BSL:
  2573.  
  2574.             {
  2575.                 bool        newLN;
  2576.  
  2577.                 ch = scanEscapeSeq(&newLN);
  2578.                 if  (newLN & 1)     // the "& 1" is a HACK!!!!!!!!!!!!!!!!!!!!!!!!
  2579.                     continue;
  2580.             }
  2581.  
  2582. //          printf("Large char = %04X\n", ch);
  2583.  
  2584.             /* If the character value doesn't fit in a byte, prefix it */
  2585.  
  2586.             if  (ch >= 0xFF)
  2587.             {
  2588.                 /* Write 0xFF followed by the character value */
  2589.  
  2590.                 *(BYTE *)savePtr =            0xFF; savePtr++;
  2591.                 *(BYTE *)savePtr = (BYTE)(ch     ); savePtr++;
  2592.                 *(BYTE *)savePtr = (BYTE)(ch >> 8); savePtr++;
  2593.  
  2594.                 /* Remember that we have some wide characters */
  2595.  
  2596.                 hasWide = true;
  2597.  
  2598.                 /* Make sure there wasn't a bad prefix */
  2599.  
  2600.                 if  (prefixChar == 'A' && ch > 0xFF)
  2601.                     scanComp->cmpError(ERRbadEscCh);
  2602.  
  2603.                 goto SAVED;
  2604.             }
  2605.  
  2606.             break;
  2607.  
  2608.         case _C_NWL:
  2609.             undoNextChar();
  2610.             scanComp->cmpError(ERRnoStrEnd);
  2611.             goto DONE;
  2612.  
  2613.         case _C_QUO:
  2614.             goto DONE;
  2615.  
  2616. #if FV_DBCS
  2617.         case _C_XLD:
  2618.             *savePtr++ = ch;
  2619.             *savePtr++ = readNextChar();
  2620.             goto SAVED;
  2621. #endif
  2622.  
  2623.         }
  2624.  
  2625.         *savePtr++ = ch;
  2626.  
  2627.     SAVED:
  2628.  
  2629.         /* Do we have enough room for the string in our buffer? */
  2630.  
  2631.         if  (savePtr >= saveMax)
  2632.         {
  2633.             size_t          curStrLen;
  2634.             size_t          newStrLen;
  2635.  
  2636.             char    *       newBuffer;
  2637.  
  2638.             /* The constant is *really* long - we'll have to grow the buffer */
  2639.  
  2640.             curStrLen = savePtr - saveAdr;
  2641.  
  2642.             /* Allocate a whole bunch more space */
  2643.  
  2644.             newStrLen = curStrLen * 2;
  2645.             if  (newStrLen < OS_page_size)
  2646.                  newStrLen = OS_page_size;
  2647.  
  2648.             newBuffer = (char *)LowLevelAlloc(newStrLen);
  2649.             if  (!newBuffer)
  2650.                 scanComp->cmpFatal(ERRnoMemory);
  2651.  
  2652.             /* Copy the current string to the new place */
  2653.  
  2654.             memcpy(newBuffer, saveAdr, curStrLen);
  2655.  
  2656.             /* If the old buffer was heap-based, free it now */
  2657.  
  2658.             if  (scanStrLitBuff)
  2659.                 LowLevelFree(scanStrLitBuff);
  2660.  
  2661.             /* Switch over to the new buffer */
  2662.  
  2663.             scanStrLitBuff = newBuffer;
  2664.             scanStrLitBsiz = newStrLen;
  2665.  
  2666.             saveAdr = scanStrLitBuff;
  2667.             savePtr = scanStrLitBuff + curStrLen;
  2668.             saveMax = scanStrLitBuff + scanStrLitBsiz - 7;
  2669.         }
  2670.     }
  2671.  
  2672. DONE:
  2673.  
  2674.     *savePtr = 0;
  2675.  
  2676.     scanTok.strCon.tokStrVal  = saveAdr;
  2677.     scanTok.strCon.tokStrLen  = savePtr - saveAdr;
  2678.     scanTok.strCon.tokStrType = 0;
  2679.     scanTok.strCon.tokStrWide = hasWide;
  2680.  
  2681. //  if  (scanTok.strCon.tokStrLen > 1000) printf("String = '%s'\n", scanTok.strCon.tokStrVal);
  2682.  
  2683.     if  (prefixChar)
  2684.     {
  2685.         switch (prefixChar)
  2686.         {
  2687.         case 'A': scanTok.strCon.tokStrType = 1; break;
  2688.         case 'L': scanTok.strCon.tokStrType = 2; break;
  2689.         case 'S': scanTok.strCon.tokStrType = 3; break;
  2690.         default: NO_WAY(!"funny string");
  2691.         }
  2692.     }
  2693.  
  2694.     return  (scanTok.tok = tkStrCon);
  2695. }
  2696.  
  2697. /*****************************************************************************
  2698.  *
  2699.  *  Skip until the next end-of-line sequence.
  2700.  */
  2701.  
  2702. void                scanner::scanSkipToEOL()
  2703. {
  2704.     for (;;)
  2705.     {
  2706.         switch (charType(readNextChar()))
  2707.         {
  2708.         case _C_NWL:
  2709.         case _C_EOF:
  2710.             undoNextChar();
  2711.             return;
  2712.  
  2713.         case _C_BSL:
  2714.  
  2715.             /* Check for a newline */
  2716.  
  2717.             switch  (readNextChar())
  2718.             {
  2719.             case '\r':
  2720.                 if  (readNextChar() != '\n')
  2721.                     undoNextChar();
  2722.                 break;
  2723.  
  2724.             case '\n':
  2725.                 if  (readNextChar() != '\r')
  2726.                     undoNextChar();
  2727.                 break;
  2728.  
  2729.             case '\\':
  2730.                 continue;
  2731.  
  2732.             default:
  2733.                 scanComp->cmpError(ERRillegalChar);
  2734.                 continue;
  2735.             }
  2736.  
  2737.             /* Swallow the endline and continue */
  2738.  
  2739.             scanRecordNL(true);
  2740.             continue;
  2741.         }
  2742.     }
  2743. }
  2744.  
  2745. /*****************************************************************************
  2746.  *
  2747.  *  Consume an end-of-line sequence.
  2748.  */
  2749.  
  2750. prepDirs            scanner::scanNewLine(unsigned ch, bool noPrep)
  2751. {
  2752.     unsigned        nc;
  2753.  
  2754.     /* Accept both CR/LF and LF/CR as new-lines */
  2755.  
  2756.     nc = readNextChar();
  2757.  
  2758.     switch (nc)
  2759.     {
  2760.     case '\r':
  2761.         if  (ch == '\n')
  2762.             nc = readNextChar();
  2763.         break;
  2764.  
  2765.     case '\n':
  2766.         if  (ch == '\r')
  2767.             nc = readNextChar();
  2768.         break;
  2769.  
  2770.     case 0x1A:
  2771.         undoNextChar();
  2772.         return  PP_NONE;
  2773.     }
  2774.  
  2775.     /* Push back the first character after the newline */
  2776.  
  2777.     undoNextChar();
  2778.  
  2779.     /* Remember that we have a new source line */
  2780.  
  2781.     return  scanRecordNL(noPrep);
  2782. }
  2783.  
  2784. /*****************************************************************************
  2785.  *
  2786.  *  Consume a C++-style comment.
  2787.  */
  2788.  
  2789. void                scanner::scanSkipLineCmt()
  2790. {
  2791.     for (;;)
  2792.     {
  2793.         unsigned        ch = readNextChar();
  2794.  
  2795.         switch  (charType(ch))
  2796.         {
  2797.         case _C_EOF:
  2798.         case _C_NWL:
  2799.             undoNextChar();
  2800.             return;
  2801.  
  2802.         case _C_BSL:
  2803.             if  (peekNextChar() == 'u')
  2804.             {
  2805.                 ch = scanEscapeSeq(NULL);
  2806.                 if  (wideCharType(ch) == _C_NWL)
  2807.                     return;
  2808.             }
  2809.             break;
  2810.         }
  2811.     }
  2812. }
  2813.  
  2814. /*****************************************************************************
  2815.  *
  2816.  *  Consume a C-style comment.
  2817.  */
  2818.  
  2819. void                scanner::scanSkipComment()
  2820. {
  2821.     unsigned        ch;
  2822.  
  2823.     for (;;)
  2824.     {
  2825.         ch = readNextChar();
  2826.  
  2827.     AGAIN:
  2828.  
  2829.         switch (charType(ch))
  2830.         {
  2831.         case _C_MUL:
  2832.             if  (wideCharType(readNextChar()) == _C_SLH)
  2833.                 return;
  2834.             undoNextChar();
  2835.             break;
  2836.  
  2837.         case _C_NWL:
  2838.             scanNewLine(ch, true);
  2839.             break;
  2840.  
  2841.         case _C_EOF:
  2842.             scanComp->cmpError(ERRnoCmtEnd);
  2843.             return;
  2844.  
  2845.         case _C_BSL:
  2846.             if  (peekNextChar() != 'u')
  2847.                 break;
  2848.             ch = scanEscapeSeq(NULL);
  2849.             if  (ch <= 0xFF)
  2850.                 goto AGAIN;
  2851.             break;
  2852.  
  2853.         case _C_AT:
  2854.  
  2855.             if  (!scanSkipToPP)
  2856.             {
  2857.                 /* The following is a truly awful hack */
  2858.  
  2859.                 switch (readNextChar())
  2860.                 {
  2861.                 case 'c':
  2862.  
  2863.                     if  (readNextChar() == 'o' &&
  2864.                          readNextChar() == 'm' &&
  2865.                          readNextChar() == '.')
  2866.                     {
  2867.                         break;
  2868.                     }
  2869.  
  2870.                     continue;
  2871.  
  2872.                 case 'd':
  2873.  
  2874.                     if  (readNextChar() == 'l' &&
  2875.                          readNextChar() == 'l' &&
  2876.                          readNextChar() == '.')
  2877.                     {
  2878.                         break;
  2879.                     }
  2880.  
  2881.                     continue;
  2882.  
  2883.                 default:
  2884.                     undoNextChar();
  2885.                     continue;
  2886.                 }
  2887.  
  2888.                 scanComp->cmpGenWarn(WRNskipAtCm);
  2889.             }
  2890.             break;
  2891.         }
  2892.     }
  2893. }
  2894.  
  2895. /*****************************************************************************
  2896.  *
  2897.  *  Peek ahead at the next token (we can look ahead only one token).
  2898.  */
  2899.  
  2900. tokens              scanner::scanLookAhead()
  2901. {
  2902.     /* Only look ahead if we haven't already */
  2903.  
  2904.     if  (!scanLookAheadCount)
  2905.     {
  2906.         bool        simpleSave;
  2907.         Token       savedToken;
  2908.         unsigned    saveLineNo;
  2909. //      unsigned    saveColumn;
  2910.  
  2911.         /* First we save off the current token along with its position */
  2912.  
  2913.         savedToken = scanTok;
  2914.         simpleSave = false;
  2915.         saveLineNo = scanTokLineNo;
  2916. //      saveColumn = scanTokColumn;
  2917.  
  2918.         /* Record the save position in case the callers tries to back up */
  2919.  
  2920.         scanSaveSN = scanSaveNext;
  2921.  
  2922.         /* Get the next token, and save it */
  2923.  
  2924.         scan();
  2925.  
  2926.         scanLookAheadToken  = scanTok;
  2927.         scanLookAheadLineNo = scanTokLineNo;
  2928. //      scanLookAheadColumn = scanTokColumn;
  2929.  
  2930.         /* Remember that we have now looked ahead */
  2931.  
  2932.         scanLookAheadCount++;
  2933.  
  2934.         /* Now put the old token back */
  2935.  
  2936.         scanTok       = savedToken;
  2937.         scanTokLineNo = saveLineNo;
  2938. //      scanTokColumn = saveColumn;
  2939.     }
  2940.  
  2941.     return  scanLookAheadToken.tok;
  2942. }
  2943.  
  2944. /*****************************************************************************
  2945.  *
  2946.  *  The following is used for token lookahead.
  2947.  */
  2948.  
  2949. DEFMGMT class RecTokDsc
  2950. {
  2951. public:
  2952.  
  2953.     RecTok          rtNext;
  2954.     Token           rtTok;
  2955. };
  2956.  
  2957. /*****************************************************************************
  2958.  *
  2959.  *  Delivers a token stream.
  2960.  *
  2961.  *  Implementation note: for token lookahead and stream recording to work,
  2962.  *  there must be only one return point from this method, down at the "EXIT"
  2963.  *  label. That is, no return statements must be present (other than the one
  2964.  *  at the very end of the function) - to exit, jump to "EXIT" instead.
  2965.  */
  2966.  
  2967. #ifdef  DEBUG
  2968. static  unsigned    scanCount[tkLastValue];
  2969. static  unsigned    tokSaveSize;
  2970. #endif
  2971.  
  2972. tokens              scanner::scan()
  2973. {
  2974.     if  (scanLookAheadCount)
  2975.     {
  2976.         /* Return the looked ahead token */
  2977.  
  2978.         scanLookAheadCount--; assert(scanLookAheadCount == 0);
  2979.  
  2980.         scanTok       = scanLookAheadToken;
  2981.         scanTokLineNo = scanLookAheadLineNo;
  2982. //      scanTokColumn = scanLookAheadColumn;
  2983.  
  2984.         return  scanTok.tok;
  2985.     }
  2986.  
  2987.     if  (scanTokReplay)
  2988.     {
  2989. #if     DISP_TOKEN_STREAMS
  2990.         BYTE    *       start = scanTokReplay;
  2991. #endif
  2992.  
  2993.         scanTokSrcPos = scanTokReplay;
  2994.  
  2995.         scanTok.tok = (tokens)*scanTokReplay++;
  2996.  
  2997.         if  (scanTok.tok >= tkID)
  2998.         {
  2999.             scanTokReplay--;
  3000.  
  3001.             /* Read a complex/fake token */
  3002.  
  3003.             if  (scanReplayTok() == tkNone)
  3004.             {
  3005.                 /* We just peeked ahead a bit, resume scanning */
  3006.  
  3007.                 goto NO_SV;
  3008.             }
  3009.         }
  3010.  
  3011. #if     DISP_TOKEN_STREAMS
  3012.         printf("Read [%08X]:", start);
  3013.         scanDispCurToken(false, false);
  3014. #endif
  3015.  
  3016.         return  scanTok.tok;
  3017.     }
  3018.  
  3019. NO_SV:
  3020.  
  3021.     for (;;)
  3022.     {
  3023.         unsigned    ch;
  3024. #if FV_DBCS
  3025.         unsigned    nc;
  3026. #endif
  3027.  
  3028.         /* Save the starting position of the token for error reporting */
  3029.  
  3030.         saveSrcPos();
  3031.  
  3032.         /* Get the next character and switch on its type value */
  3033.  
  3034.         ch = readNextChar();
  3035.  
  3036.         switch  (charType(ch))
  3037.         {
  3038.         case _C_WSP:
  3039.             break;
  3040.  
  3041.         case _C_LET:
  3042. #if FV_DBCS
  3043.         case _C_DB1:
  3044. #endif
  3045.         case _C_USC:
  3046.         case _C_DOL:
  3047.  
  3048.         IDENT:
  3049.  
  3050.             if  (scanIdentifier(ch) == tkNone)
  3051.                 continue;
  3052.             goto EXIT;
  3053.  
  3054.         case _C_L_A:
  3055.  
  3056.             /* Check for A"string" */
  3057.  
  3058.             if  (peekNextChar() != '"')
  3059.                 goto IDENT;
  3060.  
  3061.             readNextChar();
  3062.             scanStrgConstant('A');
  3063.             goto EXIT;
  3064.  
  3065.         case _C_L_L:
  3066.  
  3067.             /* Check for L"string" */
  3068.  
  3069.             if  (peekNextChar() != '"')
  3070.                 goto IDENT;
  3071.  
  3072.             readNextChar();
  3073.             scanStrgConstant('L');
  3074.             goto EXIT;
  3075.  
  3076.         case _C_L_S:
  3077.  
  3078.             /* Check for S"string" */
  3079.  
  3080.             if  (peekNextChar() != '"')
  3081.                 goto IDENT;
  3082.  
  3083.             readNextChar();
  3084.             scanStrgConstant('S');
  3085.             goto EXIT;
  3086.  
  3087.         case _C_QUO:
  3088.             scanStrgConstant();
  3089.             goto EXIT;
  3090.  
  3091.         case _C_APO:
  3092.             scanCharConstant();
  3093.             goto EXIT;
  3094.  
  3095.         case _C_DOT:
  3096.  
  3097.             /* Is the next character a digit or another dot? */
  3098.  
  3099.             switch (wideCharType(peekNextChar()))
  3100.             {
  3101.             case _C_DIG:
  3102.                 break;
  3103.  
  3104.             case _C_DOT:
  3105.                 ch = readNextChar();
  3106.                 if  (wideCharType(peekNextChar()) == _C_DOT)
  3107.                 {
  3108.                     readNextChar();
  3109.                     scanTok.tok = tkEllipsis;
  3110.                     goto EXIT;
  3111.                 }
  3112.  
  3113.                 scanTok.tok = tkDot2;
  3114.                 goto EXIT;
  3115.  
  3116.             default:
  3117.                 scanTok.tok = tkDot;
  3118.                 goto EXIT;
  3119.             }
  3120.  
  3121.             // Fall through ...
  3122.  
  3123.         case _C_DIG:
  3124.             scanNumericConstant(ch);
  3125.             goto EXIT;
  3126.  
  3127.         case _C_LPR: scanTok.tok = tkLParen; goto EXIT;
  3128.         case _C_RPR: scanTok.tok = tkRParen; goto EXIT;
  3129.         case _C_LC : scanTok.tok = tkLCurly; goto EXIT;
  3130.         case _C_RC : scanTok.tok = tkRCurly; goto EXIT;
  3131.  
  3132.         case _C_LBR: scanTok.tok = tkLBrack; goto EXIT;
  3133.         case _C_RBR: scanTok.tok = tkRBrack; goto EXIT;
  3134.  
  3135.         case _C_CMA: scanTok.tok = tkComma ; goto EXIT;
  3136.         case _C_SMC: scanTok.tok = tkSColon; goto EXIT;
  3137.         case _C_TIL: scanTok.tok = tkTilde ; goto EXIT;
  3138.         case _C_QUE: scanTok.tok = tkQMark ; goto EXIT;
  3139.  
  3140.         case _C_COL:
  3141.             switch  (readNextChar())
  3142.             {
  3143.             case ':':
  3144.                 scanTok.tok = tkColon2;
  3145.                 break;
  3146.             default:
  3147.                 undoNextChar();
  3148.                 scanTok.tok = tkColon;
  3149.                 break;
  3150.             }
  3151.             goto EXIT;
  3152.  
  3153.         case _C_EQ:
  3154.             switch  (readNextChar())
  3155.             {
  3156.             case '=':
  3157.                 scanTok.tok = tkEQ;
  3158.                 break;
  3159.             default:
  3160.                 undoNextChar();
  3161.                 scanTok.tok = tkAsg;
  3162.                 break;
  3163.             }
  3164.             goto EXIT;
  3165.  
  3166.         case _C_BNG:
  3167.             switch  (readNextChar())
  3168.             {
  3169.             case '=':
  3170.                 scanTok.tok = tkNE;
  3171.                 break;
  3172.             default:
  3173.                 undoNextChar();
  3174.                 scanTok.tok = tkBang;
  3175.                 break;
  3176.             }
  3177.             goto EXIT;
  3178.  
  3179.         case _C_PLS:
  3180.             switch  (readNextChar())
  3181.             {
  3182.             case '=':
  3183.                 scanTok.tok = tkAsgAdd;
  3184.                 break;
  3185.             case '+':
  3186.                 scanTok.tok = tkInc;
  3187.                 break;
  3188.             default:
  3189.                 undoNextChar();
  3190.                 scanTok.tok = tkAdd;
  3191.                 break;
  3192.             }
  3193.             goto EXIT;
  3194.  
  3195.         case _C_MIN:
  3196.             switch (readNextChar())
  3197.             {
  3198.             case '=':
  3199.                 scanTok.tok = tkAsgSub;
  3200.                 break;
  3201.             case '-':
  3202.                 scanTok.tok = tkDec;
  3203.                 break;
  3204.             case '>':
  3205.                 scanTok.tok = tkArrow;
  3206.                 break;
  3207.             default:
  3208.                 undoNextChar();
  3209.                 scanTok.tok = tkSub;
  3210.                 break;
  3211.             }
  3212.             goto EXIT;
  3213.  
  3214.         case _C_MUL:
  3215.             switch  (readNextChar())
  3216.             {
  3217.             case '=':
  3218.                 scanTok.tok = tkAsgMul;
  3219.                 break;
  3220.             default:
  3221.                 undoNextChar();
  3222.                 scanTok.tok = tkMul;
  3223.                 break;
  3224.             }
  3225.             goto EXIT;
  3226.  
  3227.         case _C_SLH:
  3228.             switch  (readNextChar())
  3229.             {
  3230.             case '=':
  3231.                 scanTok.tok = tkAsgDiv;
  3232.                 break;
  3233.  
  3234.             case '/':
  3235.                 scanSkipLineCmt();
  3236.                 continue;
  3237.  
  3238.             case '*':
  3239.  
  3240.                 if  (!scanComp->cmpConfig.ccSkipATC)
  3241.                 {
  3242.                     if  (peekNextChar() == '*')
  3243.                     {
  3244.                         if  (readNextChar() == '*' &&
  3245.                              readNextChar() == ' ' &&
  3246.                              readNextChar() == '@')
  3247.                         {
  3248.                             if  (scanDoAtComment())
  3249.                                 goto EXIT;
  3250.                             else
  3251.                                 continue;
  3252.                         }
  3253.                     }
  3254.                 }
  3255.  
  3256.                 scanSkipComment();
  3257.                 continue;
  3258.  
  3259.             default:
  3260.                 undoNextChar();
  3261.                 scanTok.tok = tkDiv;
  3262.                 break;
  3263.             }
  3264.             goto EXIT;
  3265.  
  3266.         case _C_PCT:
  3267.             switch  (readNextChar())
  3268.             {
  3269.             case '=':
  3270.                 scanTok.tok = tkAsgMod;
  3271.                 break;
  3272.             case '%':
  3273.                 switch  (readNextChar())
  3274.                 {
  3275.                 case '=':
  3276.                     scanTok.tok = tkAsgCnc;
  3277.                     break;
  3278.  
  3279.                 default:
  3280.                     undoNextChar();
  3281.                     scanTok.tok = tkConcat;
  3282.                     break;
  3283.                 }
  3284.                 break;
  3285.             default:
  3286.                 undoNextChar();
  3287.                 scanTok.tok = tkPct;
  3288.                 break;
  3289.             }
  3290.             goto EXIT;
  3291.  
  3292.         case _C_LT:
  3293.             switch  (readNextChar())
  3294.             {
  3295.             case '=':
  3296.                 scanTok.tok = tkLE;
  3297.                 break;
  3298.  
  3299.             case '<':
  3300.                 switch  (readNextChar())
  3301.                 {
  3302.                 case '=':
  3303.                     scanTok.tok = tkAsgLsh;
  3304.                     break;
  3305.                 default:
  3306.                     undoNextChar();
  3307.                     scanTok.tok = tkLsh;
  3308.                     break;
  3309.                 }
  3310.                 break;
  3311.             default:
  3312.                 undoNextChar();
  3313.                 scanTok.tok = tkLT;
  3314.                 break;
  3315.             }
  3316.             goto EXIT;
  3317.  
  3318.         case _C_GT:
  3319.  
  3320.             if  (scanNestedGTcnt)
  3321.             {
  3322.                 scanTok.tok = tkGT;
  3323.                 break;
  3324.             }
  3325.  
  3326.             switch  (readNextChar())
  3327.             {
  3328.             case '=':
  3329.                 scanTok.tok = tkGE;
  3330.                 break;
  3331.  
  3332.             case '>':
  3333.                 switch  (readNextChar())
  3334.                 {
  3335.                 case '=':
  3336.                     scanTok.tok = tkAsgRsh;
  3337.                     break;
  3338.  
  3339.                 default:
  3340.                     undoNextChar();
  3341.                     scanTok.tok = tkRsh;
  3342.                     break;
  3343.                 }
  3344.                 break;
  3345.  
  3346.             default:
  3347.                 undoNextChar();
  3348.                 scanTok.tok = tkGT;
  3349.                 break;
  3350.             }
  3351.             goto EXIT;
  3352.  
  3353.         case _C_XOR:
  3354.             switch  (readNextChar())
  3355.             {
  3356.             case '=':
  3357.                 scanTok.tok = tkAsgXor;
  3358.                 break;
  3359.             default:
  3360.                 undoNextChar();
  3361.                 scanTok.tok = tkXor;
  3362.                 break;
  3363.             }
  3364.             goto EXIT;
  3365.  
  3366.         case _C_BAR:
  3367.             switch  (readNextChar())
  3368.             {
  3369.             case '=':
  3370.                 scanTok.tok = tkAsgOr;
  3371.                 break;
  3372.             case '|':
  3373.                 scanTok.tok = tkLogOr;
  3374.                 break;
  3375.             default:
  3376.                 undoNextChar();
  3377.                 scanTok.tok = tkOr;
  3378.                 break;
  3379.             }
  3380.             goto EXIT;
  3381.  
  3382.         case _C_AMP:
  3383.             switch  (readNextChar())
  3384.             {
  3385.             case '=':
  3386.                 scanTok.tok = tkAsgAnd;
  3387.                 break;
  3388.             case '&':
  3389.                 scanTok.tok = tkLogAnd;
  3390.                 break;
  3391.             default:
  3392.                 undoNextChar();
  3393.                 scanTok.tok = tkAnd;
  3394.                 break;
  3395.             }
  3396.             goto EXIT;
  3397.  
  3398.         case _C_EOF:
  3399.             scanTok.tok = tkEOF;
  3400.             goto EXIT;
  3401.  
  3402.         case _C_NWL:
  3403.             if  (scanStopAtEOL)
  3404.             {
  3405.                 scanStopAtEOL = false;
  3406.                 undoNextChar();
  3407.                 scanTok.tok = tkEOL;
  3408.                 goto EXIT;
  3409.             }
  3410.             scanNewLine(ch);
  3411.             break;
  3412.  
  3413.         case _C_BSL:
  3414.  
  3415.             /* Check for a newline */
  3416.  
  3417.             switch  (readNextChar())
  3418.             {
  3419.             case '\r':
  3420.             case '\n':
  3421.  
  3422.                 /* Swallow the endline and continue */
  3423.  
  3424.                 scanRecordNL(true);
  3425.                 continue;
  3426.  
  3427.             default:
  3428.                 goto ERRCH;
  3429.             }
  3430.  
  3431. #if FV_DBCS
  3432.  
  3433.         case _C_XLD:
  3434.  
  3435.             /* Note: we allow wide chars only in idents, comments and strings */
  3436.  
  3437.             nc = peekPrevDBch(); assert(xislead(ch));
  3438.  
  3439.             if  (DBisIdentBeg(nc))
  3440.             {
  3441.                 scanIdentifier(ch);
  3442.                 goto EXIT;
  3443.             }
  3444.  
  3445.             // Fall through to report an error ...
  3446.  
  3447. #endif
  3448.  
  3449.         case _C_AT:
  3450.         case _C_ERR:
  3451.  
  3452.         ERRCH:
  3453.  
  3454.             scanComp->cmpError(ERRillegalChar);
  3455.             break;
  3456.  
  3457.         default:
  3458.             assert(!"missing case for a character kind");
  3459.         }
  3460.     }
  3461.  
  3462. EXIT:
  3463.  
  3464.     if  (!scanTokRecord || scanSkipToPP)
  3465.         return  scanTok.tok;
  3466.  
  3467.     /* Record any line# changes */
  3468.  
  3469.     if  (scanSaveLastLn != scanTokLineNo)
  3470.         scanSaveLinePos();
  3471.  
  3472.     /* Make sure we have room to record the token */
  3473.  
  3474.     if  (scanSaveNext >= scanSaveEndp)
  3475.         scanSaveMoreSp();
  3476.  
  3477.     /* Record the token */
  3478.  
  3479. #if DISP_TOKEN_STREAMS
  3480.     printf("Save [%08X]:", scanSaveNext);
  3481.     scanDispCurToken(false, false);
  3482. #endif
  3483.  
  3484.     *scanSaveNext++ = scanTok.tok;
  3485.  
  3486. #ifdef  DEBUG
  3487.     tokSaveSize++;
  3488. #endif
  3489.  
  3490.     switch (scanTok.tok)
  3491.     {
  3492.     case tkID:
  3493.         *(*(Ident     **)&scanSaveNext)++ = scanTok.id.tokIdent;
  3494. #ifdef  DEBUG
  3495.         tokSaveSize += 4;
  3496. #endif
  3497.         break;
  3498.  
  3499.     case tkAtComment:
  3500.         *(*(AtComment **)&scanSaveNext)++ = scanTok.atComm.tokAtcList;
  3501. #ifdef  DEBUG
  3502.         tokSaveSize += 4;
  3503. #endif
  3504.         break;
  3505.  
  3506.     case tkIntCon:
  3507.  
  3508.         if  (scanTok.intCon.tokIntTyp == TYP_INT &&
  3509.              (signed char)scanTok.intCon.tokIntVal == scanTok.intCon.tokIntVal)
  3510.         {
  3511.             if  (scanTok.intCon.tokIntVal >= -1 &&
  3512.                  scanTok.intCon.tokIntVal <=  2)
  3513.             {
  3514.                 scanSaveNext[-1] = (BYTE)(tkIntConM + 1 + scanTok.intCon.tokIntVal);
  3515. #ifdef  DEBUG
  3516.                 assert(tkIntConM + 1 + scanTok.intCon.tokIntVal < arraylen(scanCount)); scanCount[tkIntConM + 1 + scanTok.intCon.tokIntVal]++;
  3517. #endif
  3518.             }
  3519.            else
  3520.             {
  3521.                  scanSaveNext[-1] = tkIntConB;
  3522.                 *scanSaveNext++   = (signed char)scanTok.intCon.tokIntVal;
  3523.  
  3524. #ifdef  DEBUG
  3525.                 assert(tkIntConB < arraylen(scanCount)); scanCount[tkIntConB]++;
  3526.                 tokSaveSize += 1;
  3527. #endif
  3528.             }
  3529.  
  3530.             return  scanTok.tok;
  3531.         }
  3532.  
  3533.         *(*(BYTE      **)&scanSaveNext)++ = scanTok.intCon.tokIntTyp;
  3534.         *(*(__int32   **)&scanSaveNext)++ = scanTok.intCon.tokIntVal;
  3535. #ifdef  DEBUG
  3536.         tokSaveSize += 5;
  3537. #endif
  3538.         break;
  3539.  
  3540.     case tkLngCon:
  3541.         *(*(BYTE      **)&scanSaveNext)++ = scanTok.lngCon.tokLngTyp;
  3542.         *(*(__int64   **)&scanSaveNext)++ = scanTok.lngCon.tokLngVal;
  3543. #ifdef  DEBUG
  3544.         tokSaveSize += 9;
  3545. #endif
  3546.         break;
  3547.  
  3548.     case tkFltCon:
  3549.         *(*(float     **)&scanSaveNext)++ = scanTok.fltCon.tokFltVal;
  3550. #ifdef  DEBUG
  3551.         tokSaveSize += 4;
  3552. #endif
  3553.         break;
  3554.  
  3555.     case tkDblCon:
  3556.         *(*(double    **)&scanSaveNext)++ = scanTok.dblCon.tokDblVal;
  3557. #ifdef  DEBUG
  3558.         tokSaveSize += 8;
  3559. #endif
  3560.         break;
  3561.  
  3562.     case tkStrCon:
  3563.  
  3564.         /* Make sure we have enough space for the token and its value */
  3565.  
  3566.         if  (scanSaveNext + scanTok.strCon.tokStrLen + 6 >= scanSaveEndp)
  3567.         {
  3568.             /* Unsave the token, grab more space, resave the token */
  3569.  
  3570.             scanSaveNext--;
  3571.             scanSaveMoreSp(scanTok.strCon.tokStrLen + 32);
  3572.            *scanSaveNext++ = scanTok.tok;
  3573.         }
  3574.  
  3575.         /* Save the string type and wideness */
  3576.  
  3577.         *scanSaveNext++ = scanTok.strCon.tokStrType + 8 * scanTok.strCon.tokStrWide;
  3578.  
  3579.         /* Append the string value itself */
  3580.  
  3581.         *(*(unsigned **)&scanSaveNext)++ = scanTok.strCon.tokStrLen;
  3582.  
  3583.         memcpy(scanSaveNext, scanTok.strCon.tokStrVal, scanTok.strCon.tokStrLen+1);
  3584.                scanSaveNext             +=             scanTok.strCon.tokStrLen+1;
  3585.  
  3586. #ifdef  DEBUG
  3587.         tokSaveSize += scanTok.strCon.tokStrLen+1+4;
  3588. #endif
  3589.         break;
  3590.  
  3591.     case tkEOL:
  3592.  
  3593.         /* No point in recording EOL tokens */
  3594.  
  3595.         assert(scanSaveNext[-1] == tkEOL); scanSaveNext--;
  3596.         break;
  3597.     }
  3598.  
  3599. #ifdef  DEBUG
  3600.     assert(scanTok.tok < arraylen(scanCount)); scanCount[scanTok.tok]++;
  3601. #endif
  3602.  
  3603.     return scanTok.tok;
  3604. }
  3605.  
  3606. #ifdef  DEBUG
  3607.  
  3608. #ifndef __SMC__
  3609. extern  const char *tokenNames[];
  3610. #endif
  3611.  
  3612. void                dispScannerStats()
  3613. {
  3614.     unsigned        i;
  3615.  
  3616.     for (i = 0; i < arraylen(scanCount) - 1; i++)
  3617.     {
  3618.         if  (scanCount[i])
  3619.         {
  3620.             unsigned        s = 1;
  3621.             char            b[16];
  3622.             const char  *   n;
  3623.  
  3624.             if  (i < tkCount)
  3625.             {
  3626.                 n = tokenNames[i];
  3627.             }
  3628.             else
  3629.             {
  3630.                 if      (i >= tkLnoAdd1 && i < tkLnoAddB)
  3631.                 {
  3632.                     sprintf(b, "line add %u", i - tkLnoAdd1 + 1); n = b;
  3633.                 }
  3634.                 else if (i >= tkIntConM && i < tkIntConB)
  3635.                 {
  3636.                     sprintf(b, "int const %d", i - tkIntConM - 1); n = b;
  3637.                 }
  3638.                 else
  3639.                 {
  3640.                     switch (i)
  3641.                     {
  3642.                     case tkIntConB:
  3643.                         n = "small int";
  3644.                         break;
  3645.  
  3646.                     case tkBrkSeq:
  3647.                         n = "break seq";
  3648.                         break;
  3649.  
  3650.                     case tkEndSeq:
  3651.                         n = "end seq";
  3652.                         break;
  3653.  
  3654.                     case tkLnoAddB:
  3655.                         n = "line add char";
  3656.                         break;
  3657.  
  3658.                     case tkLnoAddI:
  3659.                         n = "line add int";
  3660.                         break;
  3661.  
  3662.                     default:
  3663.                         UNIMPL(!"unexpected token");
  3664.                     }
  3665.                 }
  3666.             }
  3667.  
  3668.             printf("%6u count of '%s'\n", scanCount[i], n);
  3669.         }
  3670.     }
  3671.  
  3672.     printf("\nTotal saved token size = %u bytes \n", tokSaveSize); _flushall();
  3673. }
  3674.  
  3675. #endif
  3676.  
  3677. /*****************************************************************************
  3678.  *
  3679.  *  The line# has changed, make sure we record this.
  3680.  */
  3681.  
  3682. void                scanner::scanSaveLinePos()
  3683. {
  3684.     unsigned        dif;
  3685.  
  3686.     assert(scanSkipToPP == false);
  3687.  
  3688.     if  (scanTokRecord == false)
  3689.         return;
  3690.     if  (scanTokReplay != NULL)
  3691.         return;
  3692.  
  3693.     assert(scanTokSrcPos == scanSaveNext);
  3694.  
  3695.     /* Compute the difference from the last recorded line# */
  3696.  
  3697.     dif = scanTokLineNo - scanSaveLastLn; assert((int)dif > 0);
  3698.  
  3699.     /* Update the last recorded line# */
  3700.  
  3701.     scanSaveLastLn = scanTokLineNo;
  3702.  
  3703.     /* Make sure we have room to record the line# change */
  3704.  
  3705.     if  (scanSaveNext >= scanSaveEndp)
  3706.         scanSaveMoreSp();
  3707.  
  3708. #if DISP_TOKEN_STREAMS
  3709.     printf("Save [%08X]:line dif %u\n", scanSaveNext, dif);
  3710. #endif
  3711.  
  3712.     if  (dif < 10)
  3713.     {
  3714.         *scanSaveNext++ = tkLnoAdd1 - 1 + dif;
  3715. #ifdef  DEBUG
  3716.         scanCount[tkLnoAdd1 - 1 + dif]++;
  3717.         tokSaveSize += 1;
  3718. #endif
  3719.     }
  3720.     else if (dif < 256)
  3721.     {
  3722.         *(*(BYTE     **)&scanSaveNext)++ = tkLnoAddB;
  3723.         *(*(BYTE     **)&scanSaveNext)++ = dif;
  3724. #ifdef  DEBUG
  3725.         scanCount[tkLnoAddB]++;
  3726.         tokSaveSize += 2;
  3727. #endif
  3728.     }
  3729.     else
  3730.     {
  3731.         *(*(BYTE     **)&scanSaveNext)++ = tkLnoAddI;
  3732.         *(*(unsigned **)&scanSaveNext)++ = dif;
  3733. #ifdef  DEBUG
  3734.         scanCount[tkLnoAddI]++;
  3735.         tokSaveSize += 5;
  3736. #endif
  3737.     }
  3738.  
  3739.     scanTokSrcPos = scanSaveNext;
  3740. }
  3741.  
  3742. /*****************************************************************************
  3743.  *
  3744.  *  Define a macro; return NULL in case of an error, otherwise returns a macro
  3745.  *  descriptor.
  3746.  */
  3747.  
  3748. MacDef              scanner::scanDefMac(const char *name,
  3749.                                         const char *def, bool builtIn,
  3750.                                                          bool chkOnly)
  3751. {
  3752. #if MGDDATA
  3753.     MacDef          mdef = new MacDef;
  3754. #else
  3755.     MacDef          mdef = &scanDefDsc;
  3756. #endif
  3757.  
  3758.     Ident           mid;
  3759.  
  3760.     assert(name);
  3761.     assert(def);
  3762.  
  3763.     /* Hash the macro name into the main hash table */
  3764.  
  3765.     mdef->mdName = mid = scanHashKwd->hashString(name); assert(mid);
  3766.  
  3767.     /* Remember whether this is a "built-in" macro */
  3768.  
  3769.     mdef->mdBuiltin = builtIn;
  3770.  
  3771.     /* See if the value is an identifier or number */
  3772.  
  3773.     if  (*def && isdigit(*def))
  3774.     {
  3775.         unsigned        val = 0;
  3776.  
  3777.         do
  3778.         {
  3779.             if  (!isdigit(*def))
  3780.                 return  NULL;
  3781.  
  3782.             val = val * 10 + *def - '0';
  3783.         }
  3784.         while (*++def);
  3785.  
  3786.         mdef->mdIsId       = false;
  3787.         mdef->mdDef.mdCons = val;
  3788.     }
  3789.     else
  3790.     {
  3791.         Ident           name = NULL;
  3792.  
  3793.         /* Is there an identifier? */
  3794.  
  3795.         if  (*def)
  3796.         {
  3797.             const   char *  ptr;
  3798.  
  3799.             /* Make sure the identifier is well-formed */
  3800.  
  3801.             if  (!isalpha(*def) && *def != '_' && !builtIn)
  3802.             {
  3803.                 /* Last chance - non-identifier token */
  3804.  
  3805.                 name = scanHashKwd->lookupString(def);
  3806.                 if  (!name)
  3807.                     return  NULL;
  3808.             }
  3809.             else
  3810.             {
  3811.  
  3812.                 ptr = def + 1;
  3813.  
  3814.                 while (*ptr)
  3815.                 {
  3816.                     if  (!isalnum(*ptr) && *ptr != '_' && !builtIn)
  3817.                         return  NULL;
  3818.  
  3819.                     ptr++;
  3820.                 }
  3821.  
  3822.                 /* Hash the identifier into the main hash table */
  3823.  
  3824.                 name = scanHashKwd->hashString(def);
  3825.  
  3826.                 /* Ignore endless recursion */
  3827.  
  3828.                 if  (name == mid)
  3829.                     return  NULL;
  3830.  
  3831.                 // UNDONE: Need to detect indirect recursion as well!!!!!!!
  3832.             }
  3833.         }
  3834.  
  3835.         /* Store the identifier in the macro descriptor */
  3836.  
  3837.         mdef->mdIsId       = true;
  3838.         mdef->mdDef.mdIden = name;
  3839.     }
  3840.  
  3841.     /* Is the name already defined as a macro? */
  3842.  
  3843.     if  (hashTab::getIdentFlags(mid) & IDF_MACRO)
  3844.     {
  3845.         MacDef          odef;
  3846.  
  3847.         /* See if the old definition is identical to the current one */
  3848.  
  3849.         odef = scanFindMac(mid); assert(odef);
  3850.  
  3851.         if  (odef->mdIsId)
  3852.         {
  3853.             if  (mdef->mdDef.mdIden == odef->mdDef.mdIden)
  3854.                 return  odef;
  3855.         }
  3856.         else
  3857.         {
  3858.             if  (mdef->mdDef.mdCons == odef->mdDef.mdCons)
  3859.                 return  odef;
  3860.         }
  3861.  
  3862.         /* Report a redefinition of the macro and bail */
  3863.  
  3864.         scanComp->cmpError(ERRmacRedef, mid);
  3865.         return  mdef;
  3866.     }
  3867.     else
  3868.     {
  3869.         /* Make sure the macro name hasn't been referenced */
  3870.  
  3871.         if  (hashTab::getIdentFlags(mid) & IDF_USED)
  3872.             scanComp->cmpError(ERRmacPlace, mid);
  3873.  
  3874.         /* Make sure we have a permanent copy of the descriptor */
  3875.  
  3876. #if!MGDDATA
  3877.         mdef = (MacDef)scanComp->cmpAllocPerm.nraAlloc(sizeof(*mdef)); *mdef = scanDefDsc;
  3878. #endif
  3879.  
  3880.         /* Add the macro to the list of defined macros */
  3881.  
  3882.         mdef->mdNext = scanMacros;
  3883.                        scanMacros = mdef;
  3884.     }
  3885.  
  3886.     /* Mark the identifier as having a macro definition */
  3887.  
  3888.     hashTab::setIdentFlags(mid, IDF_MACRO);
  3889.  
  3890.     return  mdef;
  3891. }
  3892.  
  3893. /*****************************************************************************
  3894.  *
  3895.  *  Undefine a macro; return non-zero in case of an error.
  3896.  */
  3897.  
  3898. bool                scanner::scanUndMac(const char *name)
  3899. {
  3900.     printf("UNDONE: Undef  macro '%s'\n", name);
  3901.     return  false;
  3902. }
  3903.  
  3904. /*****************************************************************************
  3905.  *
  3906.  *  Given a global hash table entry that is known to be a macro, return
  3907.  *  its macro definition record.
  3908.  */
  3909.  
  3910. MacDef              scanner::scanFindMac(Ident name)
  3911. {
  3912.     MacDef          mdef;
  3913.  
  3914.     for (mdef = scanMacros; mdef; mdef = mdef->mdNext)
  3915.     {
  3916.         if  (mdef->mdName == name)
  3917.             return  mdef;
  3918.     }
  3919.  
  3920.     return  mdef;
  3921. }
  3922.  
  3923. /*****************************************************************************
  3924.  *
  3925.  *  Return true if what follows is a defined macro name.
  3926.  */
  3927.  
  3928. bool                scanner::scanChkDefined()
  3929. {
  3930.     switch  (charType(peekNextChar()))
  3931.     {
  3932.         bool            save;
  3933.         Ident           iden;
  3934.  
  3935.     case _C_LET:
  3936.     case _C_L_A:
  3937.     case _C_L_L:
  3938.     case _C_L_S:
  3939. #if FV_DBCS
  3940.     case _C_DB1:
  3941. #endif
  3942.     case _C_USC:
  3943.     case _C_DOL:
  3944.  
  3945.         save = scanInPPexpr;
  3946.         assert(scanNoMacExp == false);
  3947.  
  3948.         scanNoMacExp = true;
  3949.         scanInPPexpr = false;
  3950.         scanIdentifier(readNextChar());
  3951.         scanNoMacExp = false;
  3952.         scanInPPexpr = save;
  3953.  
  3954.         iden = (scanTok.tok == tkID) ? scanTok.id.tokIdent
  3955.                                      : scanHashKwd->tokenToIdent(scanTok.tok);
  3956.  
  3957.         return  (hashTab::getIdentFlags(iden) & IDF_MACRO) != 0;
  3958.  
  3959.     default:
  3960.         scanComp->cmpError(ERRnoIdent);
  3961.         return  false;
  3962.     }
  3963. }
  3964.  
  3965. /*****************************************************************************
  3966.  *
  3967.  *  Return true if the given string denotes a defined macro name.
  3968.  */
  3969.  
  3970. bool                scanner::scanIsMacro(const char *name)
  3971. {
  3972.     Ident           iden = scanHashKwd->lookupString(name);
  3973.  
  3974.     if  (iden)
  3975.     {
  3976.         /* Mark the identifier entry as referenced */
  3977.  
  3978.         hashTab::setIdentFlags(iden, IDF_USED);
  3979.  
  3980.         /* Return true if the identifier is a macro */
  3981.  
  3982.         if  (hashTab::getIdentFlags(iden) & IDF_MACRO)
  3983.             return  true;
  3984.     }
  3985.  
  3986.     return  false;
  3987. }
  3988.  
  3989. /*****************************************************************************
  3990.  *
  3991.  *  Record the current state of the scanner so that we can restart where we
  3992.  *  are later (after doing some "nested" scanning).
  3993.  */
  3994.  
  3995. void                scanner::scanSuspend(OUT scannerState REF state)
  3996. {
  3997.     assert(scanLookAheadCount == 0);
  3998.  
  3999.     assert(scanStopAtEOL      == false);
  4000.     assert(scanInPPexpr       == false);
  4001.     assert(scanNoMacExp       == false);
  4002.     assert(scanSkipToPP       == false);
  4003.  
  4004.     state.scsvCompUnit    = scanCompUnit;
  4005.     state.scsvTok         = scanTok;
  4006.     state.scsvTokLineNo   = scanTokLineNo;
  4007. //  state.scsvTokColumn   = scanTokColumn;
  4008.     state.scsvTokSrcPos   = scanTokSrcPos;
  4009.     state.scsvTokReplay   = scanTokReplay;
  4010.     state.scsvTokRecord   = scanTokRecord;   scanTokRecord   = false;
  4011.     state.scsvNestedGTcnt = scanNestedGTcnt; scanNestedGTcnt = 0;
  4012. }
  4013.  
  4014. /*****************************************************************************
  4015.  *
  4016.  *  Restore the state of the scanner from an earlier suspend call.
  4017.  */
  4018.  
  4019. void                scanner::scanResume(IN scannerState REF state)
  4020. {
  4021.     scanCompUnit    = state.scsvCompUnit;
  4022.     scanTok         = state.scsvTok;
  4023.     scanTokLineNo   = state.scsvTokLineNo;
  4024. //  scanTokColumn   = state.scsvTokColumn;
  4025.     scanTokSrcPos   = state.scsvTokSrcPos;
  4026.     scanTokReplay   = state.scsvTokReplay;
  4027.     scanTokRecord   = state.scsvTokRecord;
  4028.     scanNestedGTcnt = state.scsvNestedGTcnt;
  4029. }
  4030.  
  4031. /*****************************************************************************
  4032.  *
  4033.  *  Mark the current spot in the token stream, we'll return to it later.
  4034.  */
  4035.  
  4036. scanPosTP           scanner::scanTokMarkPos(OUT Token    REF saveTok,
  4037.                                             OUT unsigned REF saveLno)
  4038. {
  4039.     saveTok = scanTok;
  4040.     saveLno = scanTokLineNo;
  4041.  
  4042.     return  scanTokReplay ? scanTokReplay
  4043.                           : scanSaveNext;
  4044. }
  4045.  
  4046. scanPosTP           scanner::scanTokMarkPLA(OUT Token    REF saveTok,
  4047.                                             OUT unsigned REF saveLno)
  4048. {
  4049.     saveTok = scanTok;
  4050.     saveLno = scanTokLineNo;
  4051.  
  4052.     assert(scanTokReplay == NULL);
  4053.  
  4054.     return  scanSaveSN;
  4055. }
  4056.  
  4057. /*****************************************************************************
  4058.  *
  4059.  *  Rewind back to a previously marked position in the token stream.
  4060.  */
  4061.  
  4062. void                scanner::scanTokRewind(scanPosTP pos, unsigned lineNum,
  4063.                                                           Token  * pushTok)
  4064. {
  4065.     /* Are we currently recording? */
  4066.  
  4067.     if  (scanSaveNext)
  4068.         *scanSaveNext  = tkEndSeq;
  4069.  
  4070.     /* Start reading at the desired input position */
  4071.  
  4072.     scanTokReplay      = (BYTE *)pos;
  4073.  
  4074.     /* Reset the current line # */
  4075.  
  4076.     scanTokLineNo      = lineNum;
  4077.  
  4078.     /* Clear any lookaheads, just in case */
  4079.  
  4080.     scanLookAheadCount = 0;
  4081.  
  4082.     /* Make sure we get started out right */
  4083.  
  4084.     if  (pushTok)
  4085.         scanTok = *pushTok;
  4086.     else
  4087.         scan();
  4088. }
  4089.  
  4090. /*****************************************************************************
  4091.  *
  4092.  *  Make room for more recorded tokens.
  4093.  */
  4094.  
  4095. void                scanner::scanSaveMoreSp(size_t need)
  4096. {
  4097.     BYTE    *       nextBuff;
  4098.  
  4099.     /* Figure out how much more space we should grab */
  4100.  
  4101.     if  (need < scanSaveBuffSize)
  4102.          need = scanSaveBuffSize;
  4103.  
  4104.     /* Need to get some more space */
  4105.  
  4106.     nextBuff = (BYTE *)LowLevelAlloc(need);
  4107.  
  4108.     /* Are we finishing a section? */
  4109.  
  4110.     if  (scanSaveNext)
  4111.     {
  4112.         /* Link from end of old section to the new one */
  4113.  
  4114.         *(*(BYTE  **)&scanSaveNext)++ = tkBrkSeq;
  4115.         *(*(BYTE ***)&scanSaveNext)++ = nextBuff;
  4116.     }
  4117.  
  4118. //  static unsigned totSiz; totSiz += scanSaveBuffSize; printf("Alloc token buffer: total size = %u\n", totSiz);
  4119.  
  4120.     /* Switch to the new buffer */
  4121.  
  4122.     scanSaveBase =
  4123.     scanSaveNext = nextBuff;
  4124.     scanSaveEndp = nextBuff + need - 16;
  4125. }
  4126.  
  4127. /*****************************************************************************
  4128.  *
  4129.  *  Replay the next recorded token.
  4130.  */
  4131.  
  4132. tokens              scanner::scanReplayTok()
  4133. {
  4134.     tokens          tok;
  4135.  
  4136.     for (;;)
  4137.     {
  4138.         /* Get hold of the next saved token */
  4139.  
  4140.         scanTok.tok = tok = (tokens)*scanTokReplay++;
  4141.  
  4142.         /* We're done if it's a "simple" token */
  4143.  
  4144.         if  (tok < tkID)
  4145.             return  tok;
  4146.  
  4147.         /* See if any special handling is required for this token */
  4148.  
  4149.         switch (tok)
  4150.         {
  4151.             unsigned        strTmp;
  4152.             size_t          strLen;
  4153.             char    *       strAdr;
  4154.  
  4155.         case tkID:
  4156.             scanTok.id.tokIdent = *(*(Ident **)&scanTokReplay)++;
  4157.             return  tok;
  4158.  
  4159.         case tkLnoAdd1:
  4160.         case tkLnoAdd2:
  4161.         case tkLnoAdd3:
  4162.         case tkLnoAdd4:
  4163.         case tkLnoAdd5:
  4164.         case tkLnoAdd6:
  4165.         case tkLnoAdd7:
  4166.         case tkLnoAdd8:
  4167.         case tkLnoAdd9:
  4168. #if DISP_TOKEN_STREAMS
  4169. //          printf("Read [%08X]:line dif %u\n", scanTokReplay-1, tok - tkLnoAdd1 + 1);
  4170. #endif
  4171.             scanTokLineNo += (tok - tkLnoAdd1 + 1);
  4172.             scanSaveLastLn = scanTokLineNo;
  4173.             break;
  4174.  
  4175.         case tkLnoAddB:
  4176. #if DISP_TOKEN_STREAMS
  4177. //          printf("Read [%08X]:line dif %u\n", scanTokReplay-1, *(BYTE    *)scanTokReplay);
  4178. #endif
  4179.             scanTokLineNo += *(*(BYTE     **)&scanTokReplay)++;
  4180.             scanSaveLastLn = scanTokLineNo;
  4181.             break;
  4182.  
  4183.         case tkLnoAddI:
  4184. #if DISP_TOKEN_STREAMS
  4185. //          printf("Read [%08X]:line dif %u\n", scanTokReplay-1, *(unsigned*)scanTokReplay);
  4186. #endif
  4187.             scanTokLineNo += *(*(unsigned **)&scanTokReplay)++;
  4188.             scanSaveLastLn = scanTokLineNo;
  4189.             break;
  4190.  
  4191.         case tkIntConM:
  4192.         case tkIntCon0:
  4193.         case tkIntCon1:
  4194.         case tkIntCon2:
  4195.             scanTok.tok               = tkIntCon;
  4196.             scanTok.intCon.tokIntTyp  = TYP_INT;
  4197.             scanTok.intCon.tokIntVal  = tok - tkIntConM - 1;
  4198.             return  tkIntCon;
  4199.  
  4200.         case tkIntConB:
  4201.             scanTok.tok               = tkIntCon;
  4202.             scanTok.intCon.tokIntTyp  = TYP_INT;
  4203.             scanTok.intCon.tokIntVal  = *(*(signed char **)&scanTokReplay)++;
  4204.             return  tkIntCon;
  4205.  
  4206.         case tkIntCon:
  4207.             scanTok.intCon.tokIntTyp  = (var_types)*(*(BYTE **)&scanTokReplay)++;
  4208.             scanTok.intCon.tokIntVal  = *(*(__int32   **)&scanTokReplay)++;
  4209.             return  tok;
  4210.  
  4211.         case tkLngCon:
  4212.             scanTok.lngCon.tokLngTyp  = (var_types)*(*(BYTE **)&scanTokReplay)++;;
  4213.             scanTok.lngCon.tokLngVal  = *(*(__int64   **)&scanTokReplay)++;;
  4214.             return  tok;
  4215.  
  4216.         case tkFltCon:
  4217.             scanTok.fltCon.tokFltVal  = *(*(float     **)&scanTokReplay)++;;
  4218.             return  tok;
  4219.  
  4220.         case tkDblCon:
  4221.             scanTok.dblCon.tokDblVal  = *(*(double    **)&scanTokReplay)++;;
  4222.             return  tok;
  4223.  
  4224.         case tkStrCon:
  4225.  
  4226.             strTmp = *scanTokReplay++;
  4227.  
  4228.             scanTok.strCon.tokStrType = strTmp & 7;
  4229.             scanTok.strCon.tokStrWide = strTmp / 8;
  4230.  
  4231.             strLen = scanTok.strCon.tokStrLen = *(*(size_t **)&scanTokReplay)++;
  4232.  
  4233.             /* Does the string fit in our convenient buffer? */
  4234.  
  4235.             if  (strLen < sizeof(scannerBuff) - 1)
  4236.             {
  4237.                 strAdr = scannerBuff;
  4238.             }
  4239.             else
  4240.             {
  4241.                 assert(scanStrLitBuff);
  4242.                 assert(scanStrLitBsiz > strLen);
  4243.  
  4244.                 strAdr = scanStrLitBuff;
  4245.             }
  4246.  
  4247.             memcpy(strAdr, scanTokReplay,   strLen+1);
  4248.                            scanTokReplay += strLen+1;
  4249.  
  4250.             scanTok.strCon.tokStrVal  = strAdr;
  4251.  
  4252. //          if  (scanTok.strCon.tokStrLen > 1000) printf("String = '%s'\n", scanTok.strCon.tokStrVal);
  4253.  
  4254.             return  tok;
  4255.  
  4256.         case tkBrkSeq:
  4257.             scanTokReplay = *(BYTE**)scanTokReplay;
  4258.             break;
  4259.  
  4260.         case tkEndSeq:
  4261.             scanTokReplay = NULL;
  4262.             return  tkNone;
  4263.  
  4264.         case tkEOF:
  4265.             return  tok;
  4266.  
  4267.         case tkAtComment:
  4268.             scanTok.atComm.tokAtcList = *(*(AtComment **)&scanTokReplay)++;;
  4269.             return  tok;
  4270.  
  4271.         case tkPragma:
  4272.             switch (*scanTokReplay++)
  4273.             {
  4274.             case 0:
  4275.                 scanComp->cmpConfig.ccWarning[*scanTokReplay++] = 0;
  4276.                 break;
  4277.  
  4278.             case 1:
  4279.                 scanComp->cmpConfig.ccWarning[*scanTokReplay++] = 1;
  4280.                 break;
  4281.  
  4282.             default:
  4283.                 NO_WAY(!"unexpected pragma");
  4284.             }
  4285.             continue;
  4286.  
  4287.         default:
  4288.             UNIMPL(!"unexpected token");
  4289.         }
  4290.     }
  4291. }
  4292.  
  4293. /*****************************************************************************
  4294.  *
  4295.  *  Change the current token into a qualified name token.
  4296.  */
  4297.  
  4298. void                scanner::scanSetQualID(QualName qual, SymDef sym,
  4299.                                                           SymDef scp)
  4300. {
  4301.     scanTok.tok                = tkQUALID;
  4302.     scanTok.qualid.tokQualName = qual;
  4303.     scanTok.qualid.tokQualSym  = sym;
  4304.     scanTok.qualid.tokQualScp  = scp;
  4305. }
  4306.  
  4307. /*****************************************************************************
  4308.  *
  4309.  *  Set the entries for all interesting characters to 1 in this table.
  4310.  */
  4311.  
  4312. static  BYTE        scanSkipFlags[256];
  4313.  
  4314. void                scanner::scanSkipInit()
  4315. {
  4316.     scanSkipFlags['(' ] = 1;
  4317.     scanSkipFlags[')' ] = 1;
  4318.     scanSkipFlags['[' ] = 1;
  4319.     scanSkipFlags[']' ] = 1;
  4320.     scanSkipFlags['{' ] = 1;
  4321.     scanSkipFlags['}' ] = 1;
  4322.     scanSkipFlags[';' ] = 1;
  4323.     scanSkipFlags[',' ] = 1;
  4324.  
  4325.     scanSkipFlags['\r'] = 1;
  4326.     scanSkipFlags['\n'] = 1;
  4327.     scanSkipFlags[0x1A] = 1;
  4328.  
  4329.     scanSkipFlags['/' ] = 1;
  4330.     scanSkipFlags['\''] = 1;
  4331.     scanSkipFlags['"' ] = 1;
  4332. }
  4333.  
  4334. /*****************************************************************************
  4335.  *
  4336.  *  Skip over a block of text bracketed by the given delimiters.
  4337.  */
  4338.  
  4339. void                scanner::scanSkipText(tokens LT, tokens RT, tokens ET)
  4340. {
  4341.     unsigned        delimLevel = 0;
  4342.     unsigned        braceLevel = 0;
  4343.  
  4344.     assert(scanTok.tok == LT || LT == tkNone || LT == tkLParen);
  4345.  
  4346.     assert(LT == tkNone || LT == tkLCurly || LT == tkLBrack || LT == tkLParen || LT == tkLT);
  4347.     assert(RT == tkNone || RT == tkRCurly || RT == tkRBrack || RT == tkRParen || RT == tkGT);
  4348.     assert(ET == tkNone || ET == tkRCurly || ET == tkLCurly || ET == tkComma);
  4349.  
  4350.     for (;;)
  4351.     {
  4352.         if      (scanTok.tok == LT)
  4353.         {
  4354.             delimLevel++;
  4355.             if  (scanTok.tok == tkLCurly)
  4356.                 braceLevel++;
  4357.             goto NEXT;
  4358.         }
  4359.         else if (scanTok.tok == RT)
  4360.         {
  4361.             delimLevel--;
  4362.             if  (scanTok.tok == tkRCurly)
  4363.                 braceLevel--;
  4364.  
  4365.             if  (delimLevel == 0)
  4366.             {
  4367.                 if  (RT != tkRParen || ET != tkComma)
  4368.                     goto EXIT;
  4369.             }
  4370.  
  4371.             goto NEXT;
  4372.         }
  4373.         else if (scanTok.tok == ET)
  4374.         {
  4375.             if  (delimLevel == 0 && braceLevel == 0)
  4376.                 goto EXIT;
  4377.         }
  4378.  
  4379.         switch (scanTok.tok)
  4380.         {
  4381.         case tkLCurly:
  4382.             braceLevel++;
  4383.             break;
  4384.  
  4385.         case tkRCurly:
  4386.             if  (braceLevel == 0)
  4387.                 goto EXIT;
  4388.  
  4389.             braceLevel--;
  4390.             break;
  4391.  
  4392.         case tkSColon:
  4393.             if  (!delimLevel || LT != tkLCurly)
  4394.                 goto EXIT;
  4395.             break;
  4396.  
  4397.         case tkEOF:
  4398.             goto EXIT;
  4399.         }
  4400.  
  4401.     NEXT:
  4402.  
  4403.         scan();
  4404.     }
  4405.  
  4406. EXIT:
  4407.  
  4408.     return;
  4409. }
  4410.  
  4411. /*****************************************************************************
  4412.  *
  4413.  *  A little helper to collect an identifier (used when processing directives
  4414.  *  and other things that aren't "truly" part of the source text). On success
  4415.  *  returns true.
  4416.  */
  4417.  
  4418. bool                scanner::scanCollectId(bool dotOK)
  4419. {
  4420.     unsigned        ch;
  4421.     char    *       temp;
  4422.  
  4423. SKIP:
  4424.  
  4425.     switch  (charType(peekNextChar()))
  4426.     {
  4427.     case _C_LET:
  4428.     case _C_L_A:
  4429.     case _C_L_L:
  4430.     case _C_L_S:
  4431.     case _C_USC:
  4432.     case _C_DOL:
  4433.         break;
  4434.  
  4435.     case _C_WSP:
  4436.         readNextChar();
  4437.         goto SKIP;
  4438.  
  4439.     default:
  4440.         return  false;
  4441.     }
  4442.  
  4443.     temp = scannerBuff;
  4444.     for (;;)
  4445.     {
  4446.         ch = readNextChar();
  4447.  
  4448.         switch  (charType(ch))
  4449.         {
  4450.         case _C_DOT:
  4451.             if  (!dotOK)
  4452.                 break;
  4453.  
  4454.             // Fall through ....
  4455.  
  4456.         case _C_LET:
  4457.         case _C_L_A:
  4458.         case _C_L_L:
  4459.         case _C_L_S:
  4460.         case _C_DIG:
  4461.         case _C_USC:
  4462.         case _C_DOL:
  4463.             if  (temp < scannerBuff + sizeof(scannerBuff) - 1)
  4464.                 *temp++ = ch;
  4465.             continue;
  4466.         }
  4467.         break;
  4468.     }
  4469.  
  4470.     *temp = 0;
  4471.  
  4472.     undoNextChar();
  4473.  
  4474.     return  true;
  4475. }
  4476.  
  4477. /*****************************************************************************
  4478.  *
  4479.  *  A little helper to consume and convert a decimal number (this is used for
  4480.  *  processing directives and other things that aren't "truly" part of the
  4481.  *  source text). On success returns the value, otherwise returns -1.
  4482.  */
  4483.  
  4484. int                 scanner::scanCollectNum()
  4485. {
  4486.     unsigned        ch;
  4487.  
  4488.     int             sign = 1;
  4489.     bool            hex  = false;
  4490.     unsigned        val  = 0;
  4491.  
  4492.     scanSkipWsp(readNextChar()); undoNextChar();
  4493.  
  4494.     switch (charType(peekNextChar()))
  4495.     {
  4496.     case _C_DIG:
  4497.         break;
  4498.  
  4499.     case _C_MIN:
  4500.         sign = -1;
  4501.         readNextChar();
  4502.         if  (charType(peekNextChar()) == _C_DIG)
  4503.             break;
  4504.  
  4505.     default:
  4506.         return  -1;
  4507.     }
  4508.  
  4509.     if  (peekNextChar() == '0')
  4510.     {
  4511.         readNextChar();
  4512.  
  4513.         switch (peekNextChar())
  4514.         {
  4515.         case 'x':
  4516.         case 'X':
  4517.             readNextChar();
  4518.             hex = true;
  4519.             break;
  4520.         }
  4521.     }
  4522.  
  4523.     for (;;)
  4524.     {
  4525.         ch = readNextChar();
  4526.  
  4527.         switch (charType(ch))
  4528.         {
  4529.         case _C_DIG:
  4530.             val = val * (hex ? 16 : 10) + (ch - '0');
  4531.             continue;
  4532.  
  4533.         default:
  4534.  
  4535.             if (hex)
  4536.             {
  4537.                 unsigned        add;
  4538.  
  4539.                 if      (ch >= 'a' && ch <= 'f')
  4540.                     add = 10 + (ch - 'a');
  4541.                 else if (ch >= 'A' && ch <= 'F')
  4542.                     add = 10 + (ch - 'A');
  4543.                 else
  4544.                     break;
  4545.  
  4546.                 val = val * 16 + add;
  4547.                 continue;
  4548.             }
  4549.  
  4550.             break;
  4551.         }
  4552.  
  4553.         break;
  4554.     }
  4555.  
  4556.     undoNextChar();
  4557.     return  val * sign;
  4558. }
  4559.  
  4560. /*****************************************************************************
  4561.  *
  4562.  *  Skip any whitespace, including newlines.
  4563.  */
  4564.  
  4565. unsigned            scanner::scanSkipWsp(unsigned ch, bool stopAtEOL)
  4566. {
  4567.     for (;;)
  4568.     {
  4569.         switch (charType(ch))
  4570.         {
  4571.         case _C_NWL:
  4572.             if  (stopAtEOL)
  4573.                 return  ch;
  4574.             scanNewLine(ch);
  4575.             break;
  4576.  
  4577.         case _C_WSP:
  4578.             break;
  4579.  
  4580.         default:
  4581.             return  ch;
  4582.         }
  4583.  
  4584.         ch = readNextChar();
  4585.     }
  4586. }
  4587.  
  4588. /*****************************************************************************
  4589.  *
  4590.  *  The following is used to map types in @structmap directives.
  4591.  */
  4592.  
  4593. struct  COMtypeMapDsc
  4594. {
  4595.     const   char *  ctmName;
  4596.     CorNativeType   ctmType;
  4597. };
  4598.  
  4599. static
  4600. COMtypeMapDsc       COMtypeMap[] =
  4601. {
  4602.     { "BOOLEAN"     , NATIVE_TYPE_BOOLEAN    },
  4603.     { "TCHAR"       , NATIVE_TYPE_SYSCHAR    },
  4604.     { "I1"          , NATIVE_TYPE_I1         },
  4605.     { "U1"          , NATIVE_TYPE_U1         },
  4606.     { "I2"          , NATIVE_TYPE_I2         },
  4607.     { "U2"          , NATIVE_TYPE_U2         },
  4608.     { "I4"          , NATIVE_TYPE_I4         },
  4609.     { "U4"          , NATIVE_TYPE_U4         },
  4610.     { "I8"          , NATIVE_TYPE_I8         },
  4611.     { "U8"          , NATIVE_TYPE_U8         },
  4612.     { "R4"          , NATIVE_TYPE_R4         },
  4613.     { "R8"          , NATIVE_TYPE_R8         },
  4614.  
  4615.     { "PTR"         , NATIVE_TYPE_PTR        },
  4616.     { "DATE"        , NATIVE_TYPE_DATE       },
  4617.     { "STRING"      , NATIVE_TYPE_BSTR       },
  4618.     { "STRUCT"      , NATIVE_TYPE_STRUCT     },     // ????
  4619.     { "OBJECT"      , NATIVE_TYPE_OBJECTREF  },
  4620.     { "VARIANT"     , NATIVE_TYPE_VARIANT    },
  4621.     { "DISPATCH"    , NATIVE_TYPE_IDISPATCH  },
  4622.     { "CURRENCY"    , NATIVE_TYPE_CURRENCY   },
  4623.     { "SAFEARRAY"   , NATIVE_TYPE_SAFEARRAY  },
  4624.     { "ARRAY"       , NATIVE_TYPE_FIXEDARRAY },
  4625.  
  4626.     { "CUSTOM"      , NATIVE_TYPE_MAX        },     // ????
  4627.     { "CUSTOMBYREF" , NATIVE_TYPE_VOID       },     // ????
  4628.     { "BSTR"        , NATIVE_TYPE_BSTR       },
  4629.     { "LPSTR"       , NATIVE_TYPE_LPSTR      },
  4630.     { "LPWSTR"      , NATIVE_TYPE_LPWSTR     },
  4631.     { "LPTSTR"      , NATIVE_TYPE_LPTSTR     },
  4632.     { "STRUCT"      , NATIVE_TYPE_STRUCT     },
  4633.     { "INTF"        , NATIVE_TYPE_INTF       },
  4634.     { "VARIANTBOOL" , NATIVE_TYPE_VARIANTBOOL},
  4635.     { "FUNC"        , NATIVE_TYPE_FUNC       },
  4636.     { "LPVOID"      , NATIVE_TYPE_LPVOID     },
  4637.     { "ASANY"       , NATIVE_TYPE_ASANY      },
  4638.     { "LPARRAY"     , NATIVE_TYPE_ARRAY      },   //ugh - "ARRAY" already used
  4639.     { "LPSTRUCT"    , NATIVE_TYPE_LPSTRUCT   },
  4640. };
  4641.  
  4642. bool                scanner::scanNativeType(CorNativeType *typePtr,
  4643.                                             size_t        *sizePtr)
  4644. {
  4645.     CorNativeType   type;
  4646.     unsigned        size;
  4647.  
  4648.     if  (!scanCollectId())
  4649.         return  true;
  4650.  
  4651.     if      (!strcmp(scannerBuff, "FIXEDARRAY"))
  4652.     {
  4653.         if  (readNextChar() != ',')
  4654.             return  true;
  4655.         scanSkipWsp(readNextChar()); undoNextChar();
  4656.         if  (!scanCollectId() || strcmp(scannerBuff, "size"))
  4657.             return  true;
  4658.         if  (scanSkipWsp(readNextChar()) != '=')
  4659.             return  true;
  4660.         type = NATIVE_TYPE_FIXEDARRAY;
  4661.         size = scanCollectNum();
  4662.         if  ((int)size == -1)
  4663.             return  true;
  4664.     }
  4665.     else
  4666.     {
  4667.         COMtypeMapDsc * typePtr;
  4668.         unsigned        typeNum;
  4669.  
  4670.         for (typeNum = 0, typePtr = COMtypeMap;
  4671.              typeNum < arraylen(COMtypeMap);
  4672.              typeNum++  , typePtr++)
  4673.         {
  4674.             if  (!strcmp(scannerBuff, typePtr->ctmName))
  4675.             {
  4676.                 type = typePtr->ctmType;
  4677.                 goto GOT_STP;
  4678.             }
  4679.         }
  4680.  
  4681.         printf("ERROR: unrecognized @dll.structmap type '%s'\n", scannerBuff);
  4682.         forceDebugBreak();
  4683.         return  true;
  4684.  
  4685. GOT_STP:
  4686.  
  4687.         if  (peekNextChar() == '[')
  4688.         {
  4689.             readNextChar();
  4690.             size = scanCollectNum();
  4691.             if  ((int)size == -1)
  4692.                 return  true;
  4693.             if  (readNextChar() != ']')
  4694.                 return  true;
  4695.  
  4696.             switch (type)
  4697.             {
  4698.             case NATIVE_TYPE_SYSCHAR:
  4699.                 type = NATIVE_TYPE_FIXEDSYSSTRING;
  4700.                 break;
  4701.  
  4702.             default:
  4703. //              assert(!"unexpected fixed array type in @dll/@com directive");
  4704.                 break;
  4705.             }
  4706.         }
  4707.         else
  4708.             size = 0;
  4709.     }
  4710.  
  4711.     if  (type != NATIVE_TYPE_MAX || *typePtr == NATIVE_TYPE_END)
  4712.         *typePtr = type;
  4713.  
  4714.     *sizePtr = size;
  4715.  
  4716.     return  false;
  4717. }
  4718.  
  4719. ConstStr            scanner::scanCollectGUID()
  4720. {
  4721.     char    *       dest = scannerBuff;
  4722.  
  4723.     /* Save everything up to the next "," or ")" in a buffer */
  4724.  
  4725.     for (;;)
  4726.     {
  4727.         unsigned        ch = readNextChar();
  4728.  
  4729.         switch (ch)
  4730.         {
  4731.         case '0':
  4732.         case '1':
  4733.         case '2':
  4734.         case '3':
  4735.         case '4':
  4736.         case '5':
  4737.         case '6':
  4738.         case '7':
  4739.         case '8':
  4740.         case '9':
  4741.  
  4742.         case 'a':
  4743.         case 'A':
  4744.         case 'b':
  4745.         case 'B':
  4746.         case 'c':
  4747.         case 'C':
  4748.         case 'd':
  4749.         case 'D':
  4750.         case 'e':
  4751.         case 'E':
  4752.         case 'f':
  4753.         case 'F':
  4754.  
  4755.         case '-':
  4756.  
  4757.             if  (dest >= scannerBuff + sizeof(scannerBuff))
  4758.                 return  NULL;
  4759.  
  4760.             *dest++ = ch;
  4761.             continue;
  4762.  
  4763.         case ',':
  4764.         case ')':
  4765.             undoNextChar();
  4766.             break;
  4767.  
  4768.         default:
  4769.             return  NULL;
  4770.         }
  4771.         break;
  4772.     }
  4773.  
  4774.     *dest = 0;
  4775.  
  4776.     /* Save the GUID string */
  4777.  
  4778.     return  scanComp->cmpSaveStringCns(scannerBuff, dest - scannerBuff);
  4779. }
  4780.  
  4781. /*****************************************************************************
  4782.  *
  4783.  *  We've encountered "/** @", process whatever follows. If we find a correct
  4784.  *  recognized comment directive we set the current token to tkAtComment, in
  4785.  *  case of an error (such as an unrecognized directive) we set it to tkNone.
  4786.  */
  4787.  
  4788. #ifdef  __SMC__
  4789. void                ATCerror(){}
  4790. #else
  4791. #define             ATCerror() forceDebugBreak()
  4792. #endif
  4793.  
  4794. bool                scanner::scanDoAtComment()
  4795. {
  4796.     unsigned        ch;
  4797.  
  4798.     bool            isCom;
  4799.     char            name[16];
  4800.     char *          temp;
  4801.  
  4802.     AtComment       atcList = NULL;
  4803.     AtComment       atcLast = NULL;
  4804.  
  4805.     unsigned        saveTokLineNo = scanTokLineNo;
  4806. //  unsigned        saveTokColumn = scanTokColumn;
  4807.     scanPosTP       saveTokSrcPos = scanTokSrcPos;
  4808.  
  4809. #ifdef  DEBUG
  4810.     char *          begAddr;
  4811.     bool            ignored;
  4812. #endif
  4813.  
  4814.     for (;;)
  4815.     {
  4816.         atCommDsc       atcDesc;
  4817.         AtComment       atcThis;
  4818.  
  4819.         bool            skipRest;
  4820.  
  4821.         const   char *  atcName;
  4822.  
  4823.     AGAIN:
  4824.  
  4825. #ifdef  DEBUG
  4826.         begAddr = (char *)scanInputFile.inputBuffNext - 1;
  4827.         ignored = false;
  4828. #endif
  4829.  
  4830.         /* The first thing we expect is a simple identifier */
  4831.  
  4832.         if  (!scanCollectId())
  4833.         {
  4834.  
  4835.         ERR_RET:
  4836.  
  4837.             // UNDONE: Free up any allocated memory
  4838.  
  4839.             scanSkipComment();
  4840.             scanTok.tok = tkNone;
  4841.             return  false;
  4842.         }
  4843.  
  4844.         /* Get the directive name (and save it in case we issue diagnostics later) */
  4845.  
  4846.         if  (strlen(scannerBuff) >= arraylen(name))
  4847.         {
  4848.         WRN1:
  4849.  
  4850.             saveSrcPos();
  4851.             scanComp->cmpGenWarn(WRNbadAtCm, scannerBuff);
  4852.  
  4853.             goto ERR_RET;
  4854.         }
  4855.  
  4856.         strcpy(name, scannerBuff);
  4857.  
  4858.         /* Look for a recognizable directive */
  4859.  
  4860.         skipRest = false;
  4861.  
  4862.         if      (!strcmp(name, "deprecated"))
  4863.         {
  4864.             atcDesc.atcFlavor = AC_DEPRECATED;
  4865.  
  4866. //          scanComp->cmpGenWarn(WRNobsolete, "@deprecated");
  4867.  
  4868.             /* There is often garbage after this directive */
  4869.  
  4870.             skipRest = true;
  4871.             goto NEXT;
  4872.         }
  4873.         else if (!strcmp(name, "conditional"))
  4874.         {
  4875.             goto CONDITIONAL;
  4876.         }
  4877.         else if (!strcmp(name, "dll"))
  4878.         {
  4879.             isCom = false;
  4880.         }
  4881.         else if (!strcmp(name, "com"))
  4882.         {
  4883.             isCom = true;
  4884.         }
  4885.         else if (!strcmp(name, "param")  ||
  4886.                  !strcmp(name, "return") ||
  4887.                  !strcmp(name, "exception"))
  4888.         {
  4889.             skipRest = true;
  4890.             goto SKIP;
  4891.         }
  4892.         else
  4893.             goto WRN1;
  4894.  
  4895.         /* Here we expect too see a subdirective, i.e. ".subdir" */
  4896.  
  4897.         if  (readNextChar() != '.')
  4898.         {
  4899.         ERR1:
  4900.  
  4901.             saveSrcPos();
  4902. //          scanComp->cmpGenWarn(WRNbadAtCm, name);
  4903.             scanComp->cmpGenError(ERRbadAtCmForm, name);
  4904.  
  4905.             goto ERR_RET;
  4906.         }
  4907.  
  4908.         if  (!scanCollectId())
  4909.             { ATCerror(); goto ERR1; }
  4910.  
  4911.         /* Now check the directive/subdirective combination */
  4912.  
  4913.         temp = scannerBuff;
  4914.  
  4915.         if  (isCom)
  4916.         {
  4917.             if  (!strcmp(temp, "class"     )) goto AT_COM_CLASS;
  4918.             if  (!strcmp(temp, "interface" )) goto AT_COM_INTERF;
  4919.             if  (!strcmp(temp, "method"    )) goto AT_COM_METHOD;
  4920.             if  (!strcmp(temp, "parameters")) goto AT_COM_PARAMS;
  4921.             if  (!strcmp(temp, "register"  )) goto AT_COM_REGSTR;
  4922.             if  (!strcmp(temp, "struct"    )) goto AT_DLL_STRUCT;
  4923.             if  (!strcmp(temp, "structmap" )) goto AT_DLL_STRMAP;
  4924.         }
  4925.         else
  4926.         {
  4927.             if  (!strcmp(temp, "import"    )) goto AT_DLL_IMPORT;
  4928.             if  (!strcmp(temp, "struct"    )) goto AT_DLL_STRUCT;
  4929.             if  (!strcmp(temp, "structmap" )) goto AT_DLL_STRMAP;
  4930.         }
  4931.  
  4932.         scanComp->cmpGenError(ERRbadAtCmSubd, name, temp);
  4933.         goto ERR_RET;
  4934.  
  4935.     AT_DLL_IMPORT:
  4936.     {
  4937.         Linkage         linkInfo;
  4938.  
  4939.         char    *       DLLname = NULL;
  4940.         char    *       SYMname = NULL;
  4941.  
  4942.         unsigned        strings = 0;
  4943.  
  4944.         bool            lasterr = false;
  4945.  
  4946.         /* We should have a set of things within "()" here */
  4947.  
  4948.         if  (readNextChar() != '(')
  4949.             { ATCerror(); goto ERR1; }
  4950.  
  4951.         for (;;)
  4952.         {
  4953.             switch  (charType(scanSkipWsp(readNextChar())))
  4954.             {
  4955.             case _C_QUO:
  4956.  
  4957.                 /* Presumably we have a DLL name */
  4958.  
  4959.                 scanStrgConstant();
  4960.  
  4961.                 /* Save a permanent copy of the string */
  4962.  
  4963.                 DLLname = (char*)scanComp->cmpAllocPerm.nraAlloc(roundUp(scanTok.strCon.tokStrLen+1));
  4964.                 memcpy(DLLname, scanTok.strCon.tokStrVal,
  4965.                                 scanTok.strCon.tokStrLen+1);
  4966.  
  4967.                 break;
  4968.  
  4969.             default:
  4970.  
  4971.                 /* This better be one of the identifier things */
  4972.  
  4973.                 undoNextChar();
  4974.  
  4975.                 if  (!scanCollectId())
  4976.                     { ATCerror(); goto ERR1; }
  4977.  
  4978.                 if      (!strcmp(scannerBuff, "auto"))
  4979.                 {
  4980.                     if  (strings)
  4981.                         { ATCerror(); goto ERR1; }
  4982.                     strings = 1;
  4983.                 }
  4984.                 else if (!strcmp(scannerBuff, "ansi"))
  4985.                 {
  4986.                     if  (strings)
  4987.                         { ATCerror(); goto ERR1; }
  4988.                     strings = 2;
  4989.                 }
  4990.                 else if (!strcmp(scannerBuff, "unicode"))
  4991.                 {
  4992.                     if  (strings)
  4993.                         { ATCerror(); goto ERR1; }
  4994.                     strings = 3;
  4995.                 }
  4996.                 else if (!strcmp(scannerBuff, "ole"))
  4997.                 {
  4998.                     if  (strings)
  4999.                         { ATCerror(); goto ERR1; }
  5000.                     strings = 4;
  5001.                 }
  5002.                 else if (!strcmp(scannerBuff, "setLastError"))
  5003.                 {
  5004.                     if  (lasterr)
  5005.                         { ATCerror(); goto ERR1; }
  5006.                     lasterr = true;
  5007.                 }
  5008.                 else if (!strcmp(scannerBuff, "entrypoint"))
  5009.                 {
  5010.                     if  (SYMname)
  5011.                         { ATCerror(); goto ERR1; }
  5012.  
  5013.                     ch = scanSkipWsp(readNextChar());
  5014.                     if  (ch != '=')
  5015.                         { ATCerror(); goto ERR1; }
  5016.  
  5017.                     ch = scanSkipWsp(readNextChar());
  5018.                     if  (ch != '"')
  5019.                         { ATCerror(); goto ERR1; }
  5020.  
  5021.                     scanStrgConstant();
  5022.  
  5023.                     /* Save a permanent copy of the string */
  5024.  
  5025.                     SYMname = (char*)scanComp->cmpAllocPerm.nraAlloc(roundUp(scanTok.strCon.tokStrLen+1));
  5026.                     memcpy(SYMname, scanTok.strCon.tokStrVal,
  5027.                                     scanTok.strCon.tokStrLen+1);
  5028.  
  5029.                     break;
  5030.                 }
  5031.                 else
  5032.                     { ATCerror(); goto ERR1; }
  5033.  
  5034.                 break;
  5035.             }
  5036.  
  5037.             switch  (scanSkipWsp(readNextChar()))
  5038.             {
  5039.             case ')':
  5040.                 goto DONE_IMP;
  5041.  
  5042.             case ',':
  5043.                 break;
  5044.  
  5045.             default:
  5046.                 { ATCerror(); goto ERR1; }
  5047.             }
  5048.         }
  5049.  
  5050.     DONE_IMP:
  5051.  
  5052.         /* Allocate a linkage descriptor and fill it in */
  5053.  
  5054.         linkInfo  = (Linkage)scanComp->cmpAllocPerm.nraAlloc(sizeof(*linkInfo));
  5055.  
  5056.         linkInfo->ldDLLname = DLLname;
  5057.         linkInfo->ldSYMname = SYMname;
  5058.  
  5059.         linkInfo->ldStrings = strings;
  5060.         linkInfo->ldLastErr = lasterr;
  5061.  
  5062.         /* Store the info in the current descriptor */
  5063.  
  5064.         atcDesc.atcFlavor          = AC_DLL_IMPORT;
  5065.         atcDesc.atcInfo.atcImpLink = linkInfo;
  5066.         }
  5067.         goto NEXT;
  5068.  
  5069.     AT_COM_METHOD:
  5070.  
  5071.         /* Format: @com.method(vtoffset=13, addFlagsVtable=4) */
  5072.  
  5073.         {
  5074.             int             temp;
  5075.             int             offs = -1;
  5076.             int             disp = -1;
  5077.  
  5078.             if  (readNextChar() != '(')
  5079.                 { ATCerror(); goto ERR1; }
  5080.  
  5081.             if  (peekNextChar() == ')')
  5082.             {
  5083.                 readNextChar();
  5084.                 offs = disp = 0;
  5085.                 goto DONE_METH;
  5086.             }
  5087.  
  5088.             for (;;)
  5089.             {
  5090.                 if  (!scanCollectId())
  5091.                     { ATCerror(); goto ERR1; }
  5092.                 if  (readNextChar() != '=')
  5093.                     { ATCerror(); goto ERR1; }
  5094.  
  5095.                 if  (!_stricmp(scannerBuff, "type"))
  5096.                 {
  5097.                     if  (!scanCollectId())
  5098.                         { ATCerror(); goto ERR1; }
  5099.  
  5100.                     if      (!_stricmp(scannerBuff, "method"))
  5101.                     {
  5102.                     }
  5103.                     else if (!_stricmp(scannerBuff, "PROPPUT"))
  5104.                     {
  5105.                     }
  5106.                     else if (!_stricmp(scannerBuff, "PROPPUTREF"))
  5107.                     {
  5108.                     }
  5109.                     else if (!_stricmp(scannerBuff, "PROPGET"))
  5110.                     {
  5111.                     }
  5112.                     else
  5113.                         { ATCerror(); goto ERR1; }
  5114.  
  5115.                     goto NXT_METH;
  5116.                 }
  5117.  
  5118.                 if  (!_stricmp(scannerBuff, "name"))
  5119.                 {
  5120.                     if  (readNextChar() != '"')
  5121.                         { ATCerror(); goto ERR1; }
  5122.                     if  (!scanCollectId())
  5123.                         { ATCerror(); goto ERR1; }
  5124.                     if  (readNextChar() != '"')
  5125.                         { ATCerror(); goto ERR1; }
  5126.  
  5127. //                  scanComp->cmpGenWarn(WRNignAtCm, "method/name");
  5128.                     goto NXT_METH;
  5129.                 }
  5130.  
  5131.                 if  (!_stricmp(scannerBuff, "name2"))
  5132.                 {
  5133.                     if  (readNextChar() != '"')
  5134.                         { ATCerror(); goto ERR1; }
  5135.                     if  (!scanCollectId())
  5136.                         { ATCerror(); goto ERR1; }
  5137.                     if  (readNextChar() != '"')
  5138.                         { ATCerror(); goto ERR1; }
  5139.  
  5140. //                  scanComp->cmpGenWarn(WRNignAtCm, "method/name2");
  5141.                     goto NXT_METH;
  5142.                 }
  5143.  
  5144.                 if  (!strcmp(scannerBuff, "returntype"))
  5145.                 {
  5146.                     if  (!scanCollectId(true))
  5147.                         { ATCerror(); goto ERR1; }
  5148.  
  5149.                     goto NXT_METH;
  5150.                 }
  5151.  
  5152.                 temp = scanCollectNum();
  5153.                 if  (temp == -1)
  5154.                     { ATCerror(); goto ERR1; }
  5155.  
  5156.                 if      (!_stricmp(scannerBuff, "vtoffset"))
  5157.                 {
  5158.                     offs = temp;
  5159.                 }
  5160.                 else if (!_stricmp(scannerBuff, "addflagsvtable"))
  5161.                 {
  5162.                     if  (temp != 4)
  5163.                         { ATCerror(); goto ERR1; }
  5164.                 }
  5165.                 else if (!_stricmp(scannerBuff, "dispid"))
  5166.                 {
  5167.                     disp = temp;
  5168.                 }
  5169.                 else
  5170.                     { ATCerror(); goto ERR1; }
  5171.  
  5172.             NXT_METH:
  5173.  
  5174.                 ch = readNextChar();
  5175.                 if  (ch != ',')
  5176.                     break;
  5177.             }
  5178.  
  5179.             if  (ch != ')')
  5180.                 { ATCerror(); goto ERR1; }
  5181.  
  5182.         DONE_METH:
  5183.  
  5184.             atcDesc.atcFlavor                   = AC_COM_METHOD;
  5185.             atcDesc.atcInfo.atcMethod.atcVToffs = offs;
  5186.             atcDesc.atcInfo.atcMethod.atcDispid = disp;
  5187.         }
  5188.         goto NEXT;
  5189.  
  5190.     AT_COM_PARAMS:
  5191.  
  5192.         /* Format: @com.parameters([out] arg, [vt=9,type=SAFEARRAY] return) */
  5193.  
  5194.         if  (readNextChar() != '(')
  5195.             { ATCerror(); goto ERR1; }
  5196.  
  5197.         atcDesc.atcFlavor         = AC_COM_PARAMS;
  5198.         atcDesc.atcInfo.atcParams = NULL;
  5199.  
  5200.         if  (peekNextChar() != ')')
  5201.         {
  5202.             MethArgInfo         list = NULL;
  5203.             MethArgInfo         last = NULL;
  5204.             MethArgInfo         desc;
  5205.  
  5206.             do
  5207.             {
  5208.                 Ident           name;
  5209.  
  5210.                 unsigned        vt      = 0;
  5211.                 CorNativeType   type    = NATIVE_TYPE_END;
  5212.                 bool            marsh   = false;
  5213.                 unsigned        size    = 0;
  5214.  
  5215.                 bool            modeIn  = false;
  5216.                 bool            modeOut = false;
  5217.  
  5218.                 if  (scanSkipWsp(readNextChar()) != '[')
  5219.                     { ATCerror(); goto ERR1; }
  5220.  
  5221.                 do
  5222.                 {
  5223.                     if  (!scanCollectId())
  5224.                         { ATCerror(); goto ERR1; }
  5225.  
  5226.                     if      (!_stricmp(scannerBuff, "in"))
  5227.                     {
  5228.                         modeIn  = true;
  5229.                     }
  5230.                     else if (!_stricmp(scannerBuff, "out"))
  5231.                     {
  5232.                         modeOut = true;
  5233.                     }
  5234.                     else if (!_stricmp(scannerBuff, "byref"))
  5235.                     {
  5236.                         modeIn  = true;
  5237.                         modeOut = true;
  5238.                     }
  5239.                     else if (!_stricmp(scannerBuff, "vt"))
  5240.                     {
  5241.                         if  (readNextChar() != '=')
  5242.                             { ATCerror(); goto ERR1; }
  5243.                         vt = scanCollectNum();
  5244.                         if  ((int)vt == -1)
  5245.                             { ATCerror(); goto ERR1; }
  5246.                     }
  5247.                     else if (!_stricmp(scannerBuff, "type"))
  5248.                     {
  5249.                         size_t          temp;
  5250.  
  5251.                         if  (readNextChar() != '=')
  5252.                             { ATCerror(); goto ERR1; }
  5253.  
  5254.                         if  (marsh)
  5255.                         {
  5256.                             if  (!scanCollectId())
  5257.                                 { ATCerror(); goto ERR1; }
  5258.  
  5259.                             if      (!_stricmp(scannerBuff, "custom"))
  5260.                             {
  5261.                             }
  5262.                             else if (!_stricmp(scannerBuff, "custombyref"))
  5263.                             {
  5264.                             }
  5265.                             else
  5266.                                 { ATCerror(); goto ERR1; }
  5267.                         }
  5268.                         else
  5269.                         {
  5270.                             if  (scanNativeType(&type, &temp))
  5271.                                 { ATCerror(); goto ERR1; }
  5272.                             if  (temp)
  5273.                                 size = temp;
  5274.                         }
  5275.                     }
  5276.                     else if (!_stricmp(scannerBuff, "size"))
  5277.                     {
  5278.                         if  (readNextChar() != '=')
  5279.                             { ATCerror(); goto ERR1; }
  5280.                         size = scanCollectNum();
  5281.                         if  ((int)size == -1)
  5282.                             { ATCerror(); goto ERR1; }
  5283.                     }
  5284.                     else if (!_stricmp(scannerBuff, "iid"))
  5285.                     {
  5286.                         if  (readNextChar() != '=')
  5287.                             { ATCerror(); goto ERR1; }
  5288.                         if  (!scanCollectGUID())
  5289.                             { ATCerror(); goto ERR1; }
  5290.  
  5291. //                      scanComp->cmpGenWarn(WRNignAtCm, "params/iid");
  5292.                     }
  5293.                     else if (!strcmp(scannerBuff, "thread"))
  5294.                     {
  5295.                         if  (readNextChar() != '=')
  5296.                             { ATCerror(); goto ERR1; }
  5297.                         if  (!scanCollectId())
  5298.                             { ATCerror(); goto ERR1; }
  5299.                         if  (_stricmp(scannerBuff, "auto"))
  5300.                             { ATCerror(); goto ERR1; }
  5301.                     }
  5302.                     else if (!strcmp(scannerBuff, "customMarshal"))
  5303.                     {
  5304.                         if  (readNextChar() != '=')
  5305.                             { ATCerror(); goto ERR1; }
  5306.                         if  (readNextChar() != '"')
  5307.                             { ATCerror(); goto ERR1; }
  5308.                         if  (!scanCollectId(true))
  5309.                             { ATCerror(); goto ERR1; }
  5310.  
  5311.                         if      (!_stricmp(scannerBuff, "com.ms.com.AnsiStringMarshaller"))
  5312.                         {
  5313.                             type = NATIVE_TYPE_LPSTR;
  5314.                         }
  5315.                         else if (!_stricmp(scannerBuff, "com.ms.com.UniStringMarshaller"))
  5316.                         {
  5317.                             type = NATIVE_TYPE_LPWSTR;
  5318.                         }
  5319.                         else if (!_stricmp(scannerBuff, "com.ms.dll.StringMarshaler"))
  5320.                         {
  5321.                             type = NATIVE_TYPE_LPTSTR;
  5322.                         }
  5323.                         else if (!_stricmp(scannerBuff, "UniStringMarshaller"))
  5324.                         {
  5325.                             type = NATIVE_TYPE_LPTSTR;
  5326.                         }
  5327.                         else
  5328.                         {
  5329.                             { ATCerror(); goto ERR1; }
  5330.                         }
  5331.  
  5332.                         if  (readNextChar() != '"')
  5333.                             { ATCerror(); goto ERR1; }
  5334.  
  5335. //                      marsh = true;
  5336.                     }
  5337.                     else if (!strcmp(scannerBuff, "elementType"))
  5338.                     {
  5339.                         if  (readNextChar() != '=')
  5340.                             { ATCerror(); goto ERR1; }
  5341.                         if  (!scanCollectId(true))
  5342.                             { ATCerror(); goto ERR1; }
  5343.                     }
  5344.                     else
  5345.                         { ATCerror(); goto ERR1; }
  5346.  
  5347.                     ch = readNextChar();
  5348.                 }
  5349.                 while (ch == ',');
  5350.  
  5351.                 if  (ch != ']')
  5352.                     { ATCerror(); goto ERR1; }
  5353.                 if  (!scanCollectId())
  5354.                 {
  5355.                     switch (scanSkipWsp(readNextChar()))
  5356.                     {
  5357.                     case ',':
  5358.                     case ')':
  5359.                         break;
  5360.  
  5361.                     default:
  5362.                         { ATCerror(); goto ERR1; }
  5363.                     }
  5364.                     undoNextChar();
  5365.                     name = NULL;
  5366.                 }
  5367.                 else
  5368.                 {
  5369.                     name = scanHashKwd->lookupString(scannerBuff);
  5370.                     if  (!name)
  5371.                         name = scanHashSrc->hashString(scannerBuff);
  5372.                 }
  5373.  
  5374.                 desc = (MethArgInfo)scanComp->cmpAllocPerm.nraAlloc(sizeof(*desc));
  5375.  
  5376.                 desc->methArgDesc.marshType    = type;
  5377.                 desc->methArgDesc.marshSubTp   = 0;
  5378.                 desc->methArgDesc.marshSize    = size;
  5379.  
  5380.                 desc->methArgDesc.marshModeIn  = modeIn;
  5381.                 desc->methArgDesc.marshModeOut = modeOut;
  5382.  
  5383.                 desc->methArgName              = name;
  5384.                 desc->methArgNext              = NULL;
  5385.  
  5386.                 if  (last)
  5387.                     last->methArgNext = desc;
  5388.                 else
  5389.                     list              = desc;
  5390.  
  5391.                 last = desc;
  5392.             }
  5393.             while (readNextChar() == ',');
  5394.  
  5395.             undoNextChar();
  5396.  
  5397.             atcDesc.atcInfo.atcParams = list;
  5398.         }
  5399.  
  5400.         if  (readNextChar() != ')')
  5401.             { ATCerror(); goto ERR1; }
  5402.  
  5403.         goto NEXT;
  5404.  
  5405.     AT_COM_INTERF:
  5406.  
  5407.         /* Format: @com.interface(iid=AFBF15E5-C37C-11d2-B88E-00A0C9B471B8, thread=AUTO, type=DUAL) */
  5408.  
  5409.         atcDesc.atcFlavor = AC_COM_INTF;
  5410.         atcName = "iid";
  5411.         goto GET_GUID;
  5412.  
  5413.     AT_COM_REGSTR:
  5414.  
  5415.         /* Format: @com.register(clsid=8a664d00-7450-11d2-b99c-0080c7e8daa5) */
  5416.  
  5417.         atcDesc.atcFlavor = AC_COM_REGISTER;
  5418.         atcName = "clsid";
  5419.  
  5420.     GET_GUID:
  5421.  
  5422.         if  (readNextChar() != '(')
  5423.             { ATCerror(); goto ERR1; }
  5424.  
  5425.         atcDesc.atcInfo.atcReg.atcGUID = NULL;
  5426.         atcDesc.atcInfo.atcReg.atcDual = false;
  5427.  
  5428.         for (;;)
  5429.         {
  5430.             /* Look for the next "name=value" pair */
  5431.  
  5432.             if  (!scanCollectId())
  5433.                 { ATCerror(); goto ERR1; }
  5434.             if  (readNextChar() != '=')
  5435.                 { ATCerror(); goto ERR1; }
  5436.  
  5437.             if  (!_stricmp(scannerBuff, atcName))
  5438.             {
  5439.                 if  (atcDesc.atcInfo.atcReg.atcGUID)
  5440.                     { ATCerror(); goto ERR1; }
  5441.                 atcDesc.atcInfo.atcReg.atcGUID = scanCollectGUID();
  5442.                 if  (!atcDesc.atcInfo.atcReg.atcGUID)
  5443.                     { ATCerror(); goto ERR1; }
  5444.             }
  5445.             else
  5446.             {
  5447.                 /* Only @com.interface is allowed to have other args */
  5448.  
  5449.                 if  (atcDesc.atcFlavor != AC_COM_INTF)
  5450.                     { ATCerror(); goto ERR1; }
  5451.  
  5452.                 if      (!_stricmp(scannerBuff, "thread"))
  5453.                 {
  5454.                     if  (!scanCollectId())
  5455.                         { ATCerror(); goto ERR1; }
  5456.                     if  (_stricmp(scannerBuff, "auto") && _stricmp(scannerBuff, "no"))
  5457.                         { ATCerror(); goto ERR1; }
  5458.                 }
  5459.                 else if (!_stricmp(scannerBuff, "type"))
  5460.                 {
  5461.                     if  (!scanCollectId())
  5462.                         { ATCerror(); goto ERR1; }
  5463.                     if  (!_stricmp(scannerBuff, "dual"))
  5464.                         atcDesc.atcInfo.atcReg.atcDual = true;
  5465.                 }
  5466.                 else
  5467.                     { ATCerror(); goto ERR1; }
  5468.             }
  5469.  
  5470.             ch = readNextChar();
  5471.             if  (ch != ',')
  5472.                 break;
  5473.         }
  5474.  
  5475.         if  (ch != ')')
  5476.             { ATCerror(); goto ERR1; }
  5477.  
  5478.         goto NEXT;
  5479.  
  5480.     AT_DLL_STRUCT:
  5481.         {
  5482.             unsigned        strings = 0;
  5483.             unsigned        pack    = 0;
  5484.  
  5485.             if  (readNextChar() != '(')
  5486.                 { ATCerror(); goto ERR1; }
  5487.  
  5488.             if  (readNextChar() != ')')
  5489.             {
  5490.                 undoNextChar();
  5491.  
  5492.                 for (;;)
  5493.                 {
  5494.                     if  (!scanCollectId())
  5495.                         { ATCerror(); goto ERR1; }
  5496.  
  5497.                     if      (!strcmp(scannerBuff, "pack"))
  5498.                     {
  5499.                         if  (readNextChar() != '=')
  5500.                             { ATCerror(); goto ERR1; }
  5501.                         pack = scanCollectNum();
  5502.                         if  ((int)pack == -1)
  5503.                             { ATCerror(); goto ERR1; }
  5504.                     }
  5505.                     else if (!_stricmp(scannerBuff, "ansi"))
  5506.                     {
  5507.                         strings = 2;
  5508.                     }
  5509.                     else if (!_stricmp(scannerBuff, "unicode"))
  5510.                     {
  5511.                         strings = 3;
  5512.                     }
  5513.                     else if (!_stricmp(scannerBuff, "auto"))
  5514.                     {
  5515.                         strings = 4;
  5516.                     }
  5517.                     else if (!_stricmp(scannerBuff, "ole"))
  5518.                     {
  5519.                         strings = 5;
  5520.                     }
  5521.                     else if (!_stricmp(scannerBuff, "noAutoOffset"))
  5522.                     {
  5523.                     }
  5524.                     else
  5525.                         { ATCerror(); goto ERR1; }
  5526.  
  5527.                     switch (scanSkipWsp(readNextChar()))
  5528.                     {
  5529.                     case ')':
  5530.                         break;
  5531.                     case ',':
  5532.                         continue;
  5533.                     default:
  5534.                         { ATCerror(); goto ERR1; }
  5535.                     }
  5536.  
  5537.                     break;
  5538.                 }
  5539.             }
  5540.  
  5541.             atcDesc.atcFlavor                    = AC_DLL_STRUCT;
  5542.             atcDesc.atcInfo.atcStruct.atcStrings = strings;
  5543.             atcDesc.atcInfo.atcStruct.atcPack    = pack;
  5544.         }
  5545.         goto NEXT;
  5546.  
  5547.     AT_DLL_STRMAP:
  5548.         {
  5549.             CorNativeType   type;
  5550.             size_t          size;
  5551.             MarshalInfo     desc;
  5552.             unsigned        offs;
  5553.  
  5554.             if  (readNextChar() != '(')
  5555.                 { ATCerror(); goto ERR1; }
  5556.             if  (readNextChar() != '[')
  5557.                 { ATCerror(); goto ERR1; }
  5558.  
  5559.             for (;;)
  5560.             {
  5561.                 if  (!scanCollectId())
  5562.                     { ATCerror(); goto ERR1; }
  5563.  
  5564.                 if  (!strcmp(scannerBuff, "offset"))
  5565.                 {
  5566.                     if  (readNextChar() != '=')
  5567.                         { ATCerror(); goto ERR1; }
  5568.                     offs = scanCollectNum();
  5569.                     if  ((int)offs == -1)
  5570.                         { ATCerror(); goto ERR1; }
  5571.  
  5572. //                  scanComp->cmpGenWarn(WRNignAtCm, "structmap/offset");
  5573.                     goto NXT_MAP;
  5574.                 }
  5575.  
  5576.                 if  (!strcmp(scannerBuff, "thread"))
  5577.                 {
  5578.                     if  (readNextChar() != '=')
  5579.                         { ATCerror(); goto ERR1; }
  5580.                     if  (!scanCollectId())
  5581.                         { ATCerror(); goto ERR1; }
  5582.                     if  (_stricmp(scannerBuff, "auto"))
  5583.                         { ATCerror(); goto ERR1; }
  5584.  
  5585. //                  scanComp->cmpGenWarn(WRNignAtCm, "structmap/thread");
  5586.                     goto NXT_MAP;
  5587.                 }
  5588.  
  5589.                 if  (!strcmp(scannerBuff, "iid"))
  5590.                 {
  5591.                     if  (readNextChar() != '=')
  5592.                         { ATCerror(); goto ERR1; }
  5593.  
  5594. //                  scanComp->cmpGenWarn(WRNignAtCm, "structmap/iid");
  5595.  
  5596.                     for (;;)
  5597.                     {
  5598.                         switch (readNextChar())
  5599.                         {
  5600.                         case ']':
  5601.                         case ',':
  5602.                             undoNextChar();
  5603.                             goto NXT_MAP;
  5604.                         }
  5605.                     }
  5606.                 }
  5607.  
  5608.                 if  (!strcmp(scannerBuff, "customMarshal"))
  5609.                 {
  5610.                     if  (readNextChar() != '=')
  5611.                         { ATCerror(); goto ERR1; }
  5612.                     if  (readNextChar() != '"')
  5613.                         { ATCerror(); goto ERR1; }
  5614.                     if  (!scanCollectId(true))
  5615.                         { ATCerror(); goto ERR1; }
  5616.                     if  (readNextChar() != '"')
  5617.                         { ATCerror(); goto ERR1; }
  5618.  
  5619. //                  scanComp->cmpGenWarn(WRNignAtCm, "structmap/customMarshall");
  5620.                     goto NXT_MAP;
  5621.                 }
  5622.  
  5623.                 if  (!strcmp(scannerBuff, "type"))
  5624.                 {
  5625.                     if  (scanSkipWsp(readNextChar()) != '=')
  5626.                         { ATCerror(); goto ERR1; }
  5627.                     if  (scanNativeType(&type, &size))
  5628.                         { ATCerror(); goto ERR1; }
  5629.                 }
  5630.  
  5631.             NXT_MAP:
  5632.  
  5633.                 if  (readNextChar() != ',')
  5634.                     break;
  5635.             }
  5636.  
  5637.             undoNextChar();
  5638.  
  5639.             if  (readNextChar() != ']')
  5640.                 { ATCerror(); goto ERR1; }
  5641.  
  5642.             ch = scanSkipWsp(readNextChar());
  5643.             if  (ch != ')')
  5644.             {
  5645.                 undoNextChar();
  5646.                 if  (!scanCollectId())
  5647.                     { ATCerror(); goto ERR1; }
  5648.                 if  (scanSkipWsp(readNextChar()) != ')')
  5649.                     { ATCerror(); goto ERR1; }
  5650.             }
  5651.  
  5652.             desc = (MarshalInfo)scanComp->cmpAllocPerm.nraAlloc(sizeof(*desc));
  5653.             desc->marshType  = type;
  5654.             desc->marshSubTp = 0;
  5655.             desc->marshSize  = size;
  5656.  
  5657.             atcDesc.atcFlavor          = AC_DLL_STRUCTMAP;
  5658.             atcDesc.atcInfo.atcMarshal = desc;
  5659.         }
  5660.         goto NEXT;
  5661.  
  5662.     CONDITIONAL:
  5663.         {
  5664.             if  (scanSkipWsp(readNextChar()) != '(')
  5665.                 { ATCerror(); goto ERR1; }
  5666.             if  (!scanCollectId())
  5667.                 { ATCerror(); goto ERR1; }
  5668.             if  (scanSkipWsp(readNextChar()) != ')')
  5669.                 { ATCerror(); goto ERR1; }
  5670.  
  5671.             atcDesc.atcFlavor          = AC_CONDITIONAL;
  5672.             atcDesc.atcInfo.atcCondYes = scanIsMacro(scannerBuff);
  5673.         }
  5674.         goto NEXT;
  5675.  
  5676.     AT_COM_CLASS:
  5677.  
  5678.         atcDesc.atcFlavor = AC_COM_CLASS;
  5679.  
  5680. //  SKIPIT:
  5681.  
  5682.         skipRest = true;
  5683. #ifdef  DEBUG
  5684.         ignored  = true;
  5685. #endif
  5686.  
  5687.     NEXT:
  5688.  
  5689.         atcDesc.atcNext = NULL;
  5690.  
  5691.         /* Allocate and append a record to the list */
  5692.  
  5693.         atcThis = (AtComment)scanComp->cmpAllocPerm.nraAlloc(sizeof(*atcThis));
  5694.        *atcThis = atcDesc;
  5695.  
  5696.         if  (atcList)
  5697.             atcLast->atcNext = atcThis;
  5698.         else
  5699.             atcList          = atcThis;
  5700.  
  5701.         atcLast = atcThis;
  5702.  
  5703.     SKIP:
  5704.  
  5705.         /* Find the end of the comment or the next directive */
  5706.  
  5707.         for (;;)
  5708.         {
  5709.             switch  (charType(scanSkipWsp(readNextChar())))
  5710.             {
  5711.             case _C_AT:
  5712.  
  5713.                 goto AGAIN;
  5714.  
  5715.             case _C_MUL:
  5716.  
  5717.                 /* Check for end of comment */
  5718.  
  5719.                 if  (charType(readNextChar()) != _C_SLH)
  5720.                     break;
  5721.  
  5722. #ifdef  DEBUG
  5723.                 if  (ignored)
  5724.                 {
  5725.                     size_t          strLen = (char*)scanInputFile.inputBuffNext - begAddr;
  5726.                     char            strBuff[128];
  5727.  
  5728.                     if  (strLen >= arraylen(strBuff) - 1)
  5729.                          strLen  = arraylen(strBuff) - 1;
  5730.  
  5731.                     memcpy(strBuff, begAddr, strLen); strBuff[strLen]  = 0;
  5732.  
  5733.                     for (;;)
  5734.                     {
  5735.                         char    *       crPos = strchr(strBuff, '\r');
  5736.                         char    *       lfPos = strchr(strBuff, '\n');
  5737.  
  5738.                         if      (crPos)
  5739.                         {
  5740.                             *crPos = 0;
  5741.                             if  (lfPos)
  5742.                                 *lfPos = 0;
  5743.                         }
  5744.                         else if (lfPos)
  5745.                         {
  5746.                             *lfPos = 0;
  5747.                         }
  5748.                         else
  5749.                             break;
  5750.                     }
  5751.  
  5752.                     scanComp->cmpGenWarn(WRNignAtCm, strBuff);
  5753.                 }
  5754. #endif
  5755.  
  5756.                 goto DONE;
  5757.  
  5758.             default:
  5759.  
  5760.                 if  (!skipRest)
  5761.                     { ATCerror(); goto ERR1; }
  5762.  
  5763.                 break;
  5764.             }
  5765.         }
  5766.     }
  5767.  
  5768. DONE:
  5769.  
  5770.     scanTok.tok               = tkAtComment;
  5771.     scanTok.atComm.tokAtcList = atcList;
  5772.  
  5773.     /* Restore the initial position for the whole deal */
  5774.  
  5775.     scanTokLineNo = saveTokLineNo;
  5776. //  scanTokColumn = saveTokColumn;
  5777.     scanTokSrcPos = saveTokSrcPos;
  5778.  
  5779.     return  true;
  5780. }
  5781.  
  5782. /*****************************************************************************/
  5783.