Browse Source

BCC now working on brfs, fixed bug in brfs_write, removed strncpy which was incomplete.

bart 7 tháng trước cách đây
mục cha
commit
852baffec6

+ 4 - 3
BCC/BDOS/lib/brfs.c

@@ -944,11 +944,12 @@ word brfs_read(word file_pointer, word* buffer, word length)
       // - repeat until length is 0
       while (length > 0)
       {
-        word words_until_end_of_block = superblock->words_per_block - (MATH_modU(brfs_cursors[i], superblock->words_per_block));
+        word cursor_in_block = MATH_modU(brfs_cursors[i], superblock->words_per_block);
+        word words_until_end_of_block = superblock->words_per_block - cursor_in_block;
         word words_to_read = words_until_end_of_block > length ? length : words_until_end_of_block;
 
         // Copy words to buffer
-        memcpy(buffer, data_block_addr + (current_fat_idx * superblock->words_per_block) + MATH_modU(brfs_cursors[i], superblock->words_per_block), words_to_read);
+        memcpy(buffer, data_block_addr + (current_fat_idx * superblock->words_per_block) + cursor_in_block, words_to_read);
         
         // Update cursor and length
         brfs_cursors[i] += words_to_read;
@@ -1033,7 +1034,7 @@ word brfs_write(word file_pointer, word* buffer, word length)
         buffer += words_to_write;
 
         // Get next block from FAT, or find next free block if end of block
-        if (words_until_end_of_block == words_to_write && length > 0)
+        if (words_until_end_of_block == words_to_write)
         {
           
           word next_fat_idx = brfs_ram_storage[SUPERBLOCK_SIZE + current_fat_idx];

+ 0 - 21
BCC/BDOS/lib/stdlib.c

@@ -120,27 +120,6 @@ word strcat(char* dest, char* src)
     return strcpy(dest+endOfDest, src);
 }
 
-/*
-Appends string from src to dest up to n characters
-Returns pointer to resulting dest string
-*/
-char *strncat(char *dest, char *src, word n)
-{
-  word len1 = strlen(dest);
-  word len2 = strlen(src);
-    
-  if (len2 < n) 
-  {
-	  strcpy(&dest[len1], src);
-  }
-  else
-  {
-    strncpy(&dest[len1], src, n);
-    dest[len1 + n] = '\0';
-  }
-  return dest;
-}
-
 
 /*
 Compares two strings a and b

+ 6 - 6
BCC/FPGCbuildTools/bcc/backend.c

@@ -1,5 +1,5 @@
 /*
-Copyright (c) 2021-2022, bartpleiter
+Copyright (c) 2021-2024, bartpleiter
 Copyright (c) 2012-2015, Alexey Frunze
 All rights reserved.
 
@@ -627,13 +627,13 @@ void GenWriteFrameSize(void) //WORDSIZE
 void GenUpdateFrameSize(void)
 {
   word curpos = 0;
-  curpos = fgetpos(OutFile);
+  curpos = fs_getcursor(OutFile);
   //printf("cur: ");
   //printd(curpos);
   //printf("\ngoto: ");
   //printd(GenPrologPos);
   //printf("\n");
-  fsetpos(OutFile, GenPrologPos);
+  fs_setcursor(OutFile, GenPrologPos);
   GenWriteFrameSize();
 
   //printf("back to cur: ");
@@ -641,7 +641,7 @@ void GenUpdateFrameSize(void)
   //printf("\n");
   //printf("\n");
 
-  fsetpos(OutFile, curpos);
+  fs_setcursor(OutFile, curpos);
 }
 
 void GenFxnProlog(void)
@@ -664,7 +664,7 @@ void GenFxnProlog(void)
 
   GenLeaf = 1; // will be reset to 0 if a call is generated
 
-  GenPrologPos = fgetpos(OutFile);
+  GenPrologPos = fs_getcursor(OutFile);
   
   // write an empty space for the frame size
   word x;
@@ -1767,7 +1767,7 @@ void GenExpr0(void)
       if (maxCallDepth == 1 && paramOfs >= 0 && paramOfs <= 12)
       {
         // Work directly in A0-A3 instead of working in V0 and avoid copying V0 to A0-A3
-        GenWreg = B32POpRegA0 + division(paramOfs, 4); //(paramOfs >> 2); //division(paramOfs, 4);
+        GenWreg = B32POpRegA0 + MATH_divU(paramOfs, 4); //(paramOfs >> 2); //MATH_divU(paramOfs, 4);
       }
       break;
 

+ 104 - 90
BCC/FPGCbuildTools/bcc/bcc.c

@@ -1,5 +1,5 @@
 /*
-Copyright (c) 2021, bartpleiter
+Copyright (c) 2021-2024, bartpleiter
 Copyright (c) 2012-2020, Alexey Frunze
 All rights reserved.
 
@@ -38,15 +38,6 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 /*                                                                           */
 /*****************************************************************************/
 
-/* PLAN:
-- move through program from execution start to finish
-- implement missing (mostly FS) functions on the go (skip unimportant ones first, and do them later)
-- try to implement vararg printf, since it will save hours of printf replacements
-- FS functions (test/create library in a seperate test program):
-  - fopen: just return a pointer to (global var!) the full path of the file, init cursor (private)
-  - fput/get: open the file if not already opened, use cursor to read/write
-*/
-
 // Making most functions static helps with code optimization,
 // use that to further reduce compiler's code size on RetroBSD.
 #define word char
@@ -90,9 +81,8 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 #include "lib/math.c"
 #include "lib/sys.c"
-//#include "lib/gfx.c"
 #include "lib/stdlib.c"
-#include "lib/fs.c"
+#include "lib/brfs.c"
 #include "lib/stdio.c"
 
 ////////////////////////////////////////////////////////////////////////////////
@@ -106,7 +96,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #define MAX_MACRO_TABLE_LEN   (4096+1024)
 #define MAX_IDENT_TABLE_LEN   (4096+1024+512) // must be greater than MAX_IDENT_LEN
 #define SYNTAX_STACK_MAX      (2048+1024)
-#define MAX_FILE_NAME_LEN     95
+#define MAX_FILE_NAME_LEN     128
 
 #define MAX_INCLUDES         8
 #define PREP_STACK_SIZE      8
@@ -410,6 +400,7 @@ char (*FileNames)[MAX_FILE_NAME_LEN + 1] = (char (*)[MAX_FILE_NAME_LEN + 1]) FIL
 
 
 word Files[MAX_INCLUDES]; // FILE
+word FileSizes[MAX_INCLUDES]; // file size in words
 word OutFile; // FILE
 char CharQueues[MAX_INCLUDES][3];
 word LineNos[MAX_INCLUDES];
@@ -781,7 +772,7 @@ word GetTokenByWord(char* wrd)
 {
   unsigned i;
 
-  for (i = 0; i < division(sizeof rws, sizeof rws[0]); i++)
+  for (i = 0; i < MATH_divU(sizeof rws, sizeof rws[0]); i++)
     if (!strcmp(rws[i], wrd))
       return rwtk[i];
 
@@ -841,12 +832,12 @@ char* GetTokenName(word token)
 /* +-~* /% &|^! << >> && || < <= > >= == !=  () *[] ++ -- = += -= ~= *= /= %= &= |= ^= <<= >>= {} ,;: -> ... */
 
   // Tokens other than reserved keywords:
-  for (i = 0; i < division(sizeof tktk , sizeof tktk[0]); i++)
+  for (i = 0; i < MATH_divU(sizeof tktk , sizeof tktk[0]); i++)
     if (tktk[i] == token)
       return tks[i];
 
   // Reserved keywords:
-  for (i = 0; i < division(sizeof rws , sizeof rws[0]); i++)
+  for (i = 0; i < MATH_divU(sizeof rws , sizeof rws[0]); i++)
     if (rwtk[i] == token)
       return rws[i];
 
@@ -861,9 +852,9 @@ word GetNextChar(void)
 
   if (FileCnt && Files[FileCnt - 1])
   {
-    if ((ch = fgetc(Files[FileCnt - 1])) == EOF)
+    if ((ch = fgetc(Files[FileCnt - 1], FileSizes[FileCnt - 1])) == EOF)
     {
-      fclose(Files[FileCnt - 1]);
+      fs_close(Files[FileCnt - 1]);
       Files[FileCnt - 1] = NULL;
 
       // store the last line/pos, they may still be needed later
@@ -951,7 +942,12 @@ void IncludeFile(word quot)
     }
     strcpy(FileNames[FileCnt], TokenValueString);
     strcat(cFileDir, FileNames[FileCnt]);
-    Files[FileCnt] = fopen(cFileDir, 0);
+    Files[FileCnt] = fs_open(cFileDir);
+
+    // Get file size
+    struct brfs_dir_entry* entry = (struct brfs_dir_entry*)fs_stat(cFileDir);
+    word filesize = entry->filesize;
+    FileSizes[FileCnt] = filesize;
   }
 
   // Next, iterate the search paths trying to open "file" or <file>.
@@ -980,8 +976,14 @@ void IncludeFile(word quot)
           // Use '/' as a separator, typical for Linux/Unix,
           // but also supported by file APIs in DOS/Windows just as '\\'
           FileNames[FileCnt][plen] = '/';
-          if ((Files[FileCnt] = fopen(FileNames[FileCnt], 0)) != NULL)
+          if ((Files[FileCnt] = fs_open(FileNames[FileCnt])) != NULL)
+          {
+            // Get file size
+            struct brfs_dir_entry* entry = (struct brfs_dir_entry*)fs_stat(FileNames[FileCnt]);
+            word filesize = entry->filesize;
+            FileSizes[FileCnt] = filesize;
             break;
+          }
         }
         i += plen + 1;
       }
@@ -2017,7 +2019,7 @@ word isop(word tok)
     '?'
   };
   unsigned i;
-  for (i = 0; i < division(sizeof toks , sizeof toks[0]); i++)
+  for (i = 0; i < MATH_divU(sizeof toks , sizeof toks[0]); i++)
     if (toks[i] == tok)
       return 1;
   return 0;
@@ -2076,8 +2078,8 @@ char* lab2str(char* p, word n)
 {
   do
   {
-    *--p = '0' + modulo(n , 10);
-    n = division(n, 10);
+    *--p = '0' + MATH_modU(n , 10);
+    n = MATH_divU(n, 10);
   } while (n);
 
   return p;
@@ -2192,7 +2194,7 @@ word exprUnary(word tok, word* gotUnary, word commaSeparator, word argOfSizeOf)
       // DONE: can this break incomplete yet declarations???, e.g.: int x[sizeof("az")][5];
       PushSyntax2(tokIdent, id = AddNumericIdent(lbl));
       PushSyntax('[');
-      PushSyntax2(tokNumUint, division(sz, chsz));
+      PushSyntax2(tokNumUint, MATH_divU(sz, chsz));
       PushSyntax(']');
 
       PushSyntax(tokChar);
@@ -2781,7 +2783,7 @@ word divCheckAndCalc(word tok, word* psl, word sr, word Unsigned, word ConstExpr
   {
     return !div0;
   }
-  else if (!Unsigned && ((sl == int_min && sr == -1) || division(sl , sr) != truncInt(division(sl , sr))))
+  else if (!Unsigned && ((sl == int_min && sr == -1) || MATH_divU(sl , sr) != truncInt(MATH_divU(sl , sr))))
   {
     div0 = 1;
   }
@@ -2790,9 +2792,9 @@ word divCheckAndCalc(word tok, word* psl, word sr, word Unsigned, word ConstExpr
     if (Unsigned)
     {
       if (tok == '/')
-        sl = (word)((unsigned)division(sl , sr));
+        sl = (word)((unsigned)MATH_divU(sl , sr));
       else
-        sl = (word)((unsigned)modulo(sl , sr));
+        sl = (word)((unsigned)MATH_modU(sl , sr));
     }
     else
     {
@@ -2801,9 +2803,9 @@ word divCheckAndCalc(word tok, word* psl, word sr, word Unsigned, word ConstExpr
       // A stricter, C99-conforming implementation, non-dependent on the
       // compiler used to compile Smaller C is needed.
       if (tok == '/')
-        sl = division(sl, sr);
+        sl = MATH_divU(sl, sr);
       else
-        sl = modulo(sl, sr);
+        sl = MATH_modU(sl, sr);
     }
     *psl = sl;
   }
@@ -4614,7 +4616,7 @@ void error(char* strToPrint)
 
   for (i = 0; i < FileCnt; i++)
     if (Files[i])
-      fclose(Files[i]);
+      fs_close(Files[i]);
 
   /*
   puts2("");
@@ -4635,7 +4637,7 @@ void error(char* strToPrint)
   //GenStartCommentLine(); printf2("Compilation failed.\n");
 
   if (OutFile)
-    fclose(OutFile);
+    fs_close(OutFile);
 
   printf("Error in ");
   printf(FileNames[fidx]);
@@ -4770,7 +4772,7 @@ word TokenStartsDeclaration(word t, word params)
 {
   unsigned i;
 
-  for (i = 0; i < division(sizeof tsd, sizeof tsd[0]); i++)
+  for (i = 0; i < MATH_divU(sizeof tsd, sizeof tsd[0]); i++)
     if (tsd[i] == t)
       return 1;
 
@@ -7445,7 +7447,7 @@ word ParseStatement(word tok, word BrkCntTarget[2], word casesIdx)
         errorUnexpectedToken(tok);
 
       // Try to reorder expr3 with body to reduce the number of jumps, favor small expr3's
-      if (gotUnary && sp <= 16 && (unsigned)sp <= division(sizeof expr3Stack , sizeof expr3Stack[0]) - expr3Sp)
+      if (gotUnary && sp <= 16 && (unsigned)sp <= MATH_divU(sizeof expr3Stack , sizeof expr3Stack[0]) - expr3Sp)
       {
         word cnt = sp;
         // Stash the stack containing expr3
@@ -7781,6 +7783,50 @@ word ParseBlock(word BrkCntTarget[2], word casesIdx)
 int main() 
 {
   printf("BCC Compiler\n");
+
+  // Read number of arguments
+  word argc = shell_argc();
+  if (argc < 2)
+  {
+    printf("Usage: BCC <source file> <output file>\n");
+    return 1;
+  }
+
+  // Get input filename
+  char** args = shell_argv();
+  char* filename = args[1];
+
+  char absolute_path_in[MAX_PATH_LENGTH];
+  // Check if absolute path
+  if (filename[0] != '/')
+  {
+    strcpy(absolute_path_in, fs_getcwd());
+    strcat(absolute_path_in, "/");
+    strcat(absolute_path_in, filename);
+  }
+  else
+  {
+    strcpy(absolute_path_in, filename);
+  }
+
+  // Get output filename
+  args = shell_argv();
+  filename = args[2];
+
+  char absolute_path_out[MAX_PATH_LENGTH];
+  // Check if absolute path
+  if (filename[0] != '/')
+  {
+    strcpy(absolute_path_out, fs_getcwd());
+    strcat(absolute_path_out, "/");
+    strcat(absolute_path_out, filename);
+  }
+  else
+  {
+    strcpy(absolute_path_out, filename);
+  }
+
+
   // Run-time initializer for SyntaxStack0[] to reduce
   // executable file size (SyntaxStack0[] will be in .bss)
   static unsigned char SyntaxStackInit[] =
@@ -7803,47 +7849,27 @@ int main()
 
   GenInit();
 
-  // TODO: add BDOS path to filenames if not absolute path
   compileOS = 0;
   compileUserBDOS = 1;
 
-  char infilename[64];
-  BDOS_GetArgN(1, infilename);
-  if (infilename[0] == 0)
-  {
-    strcat(infilename, BDOS_GetPath());
-    if (infilename[strlen(infilename)-1] != '/')
-    {
-        strcat(infilename, "/");
-    }
-    strcat(infilename, "CODE.C");
-    //strcpy(infilename, "/TEST/TEST.C");
-  }
-  if (infilename[0] != '/')
-  {
-    char bothPath[64];
-    bothPath[0] = 0;
-    strcat(bothPath, BDOS_GetPath());
-    if (bothPath[strlen(bothPath)-1] != '/')
-    {
-        strcat(bothPath, "/");
-    }
-    strcat(bothPath, infilename);
-    strcpy(infilename, bothPath);
-  }
 
   if (FileCnt == 0)
   {
     // If it's none of the known options,
     // assume it's the source code file name
-    if (strlen(infilename) > MAX_FILE_NAME_LEN)
+    if (strlen(absolute_path_in) > MAX_FILE_NAME_LEN)
     {
       //error("File name too long\n");
       errorFileName();
     }
-    strcpy(FileNames[0], infilename);
-    Files[0] = fopen(FileNames[0], 0);
-    if (fcanopen(Files[0]) == EOF)
+    strcpy(FileNames[0], absolute_path_in);
+    Files[0] = fs_open(FileNames[0]);
+    // Get file size
+    struct brfs_dir_entry* entry = (struct brfs_dir_entry*)fs_stat(FileNames[0]);
+    word filesize = entry->filesize;
+    FileSizes[0] = filesize;
+    
+    if (Files[0] == EOF)
     {
       //error("Cannot open file \"%s\"\n", FileNames[0]);
       errorFile(FileNames[0]);
@@ -7857,39 +7883,19 @@ int main()
     FileCnt++;
   }
 
-  char outfilename[64];
-  BDOS_GetArgN(2, outfilename);
-  if (outfilename[0] == 0)
-  {
-    strcat(outfilename, BDOS_GetPath());
-    if (outfilename[strlen(outfilename)-1] != '/')
-    {
-        strcat(outfilename, "/");
-    }
-    strcat(outfilename, "OUT.ASM");
-    //strcpy(outfilename, "/TEST/A.OUT");
-  }
-  if (outfilename[0] != '/')
-  {
-    char bothPath[64];
-    bothPath[0] = 0;
-    strcat(bothPath, BDOS_GetPath());
-    if (bothPath[strlen(bothPath)-1] != '/')
-    {
-        strcat(bothPath, "/");
-    }
-    strcat(bothPath, outfilename);
-    strcpy(outfilename, bothPath);
-  }
 
   if (FileCnt == 1 && OutFile == NULL)
   {
+    // (re)create file for output
+    fs_delete(absolute_path_out);
+    fs_mkfile(absolute_path_out);
+
     // This should be the output file name
-    OutFile = fopen(outfilename, 1);
-    if (fcanopen(OutFile) == EOF)
+    OutFile = fs_open(absolute_path_out);
+    if (OutFile == EOF)
     {
       //error("Cannot open output file \"%s\"\n", argv[i]);
-      errorFile(outfilename);
+      errorFile(absolute_path_out);
     }
     else
     {
@@ -7942,11 +7948,19 @@ int main()
   printf("Finished compiling\n");
 
   if (OutFile)
-    fclose(OutFile);
+    fs_close(OutFile);
 
   return 'q';
 }
 
 void interrupt()
 {
+  // Handle all interrupts
+  word i = get_int_id();
+  switch(i)
+  {
+    case INTID_TIMER1:
+      timer1Value = 1;  // Notify ending of timer1
+      break;
+  }
 }

+ 15 - 0
BCC/FPGCbuildTools/bcc/lib/brfs.c

@@ -0,0 +1,15 @@
+/**
+ * User library for file system operations
+*/
+
+#define MAX_DIR_ENTRIES 128 // Safe bound on max number of entries in a directory (128 -> full dir on block size of 512 words)
+#define MAX_PATH_LENGTH 127
+
+struct brfs_dir_entry
+{
+  word filename[4];       // 4 chars per word
+  word modify_date;       // TBD when RTC added to FPGC
+  word flags;             // 32 flags, from right to left: directory, hidden 
+  word fat_idx;           // idx of first FAT block
+  word filesize;          // file size in words, not bytes
+};

+ 0 - 546
BCC/FPGCbuildTools/bcc/lib/fs.c

@@ -1,546 +0,0 @@
-/*
-* Filesystem library
-* Handles all filesystem related work for userBDOS programs using CH376.
-* Uses only bottom USB port (SPI1 CH376), 
-*  allowing top USB top to be used for other USB devices (like HID).
-* Uses blocking delays for now.
-*/
-
-// uses stdlib.c
-
-#define FS_INTERRUPT_ADDR 0xC0272D
-
-//CH376 Codes
-#define FS_CMD_GET_IC_VER           0x01
-#define FS_CMD_SET_BAUDRATE         0x02
-#define FS_CMD_ENTER_SLEEP          0x03
-#define FS_CMD_SET_USB_SPEED        0x04
-#define FS_CMD_RESET_ALL            0x05
-#define FS_CMD_CHECK_EXIST          0x06
-#define FS_CMD_SET_SD0_INT          0x0b
-#define FS_CMD_SET_RETRY            0x0b
-#define FS_CMD_GET_FILE_SIZE        0x0c
-#define FS_CMD_SET_FILE_SIZE        0x0d
-#define FS_CMD_SET_USB_ADDRESS      0x13
-#define FS_CMD_SET_USB_MODE         0x15
-#define FS_MODE_HOST_0              0x05
-#define FS_MODE_HOST_1              0x07
-#define FS_MODE_HOST_2              0x06
-#define FS_CMD_GET_STATUS           0x22
-#define FS_CMD_RD_USB_DATA0         0x27
-#define FS_CMD_WR_USB_DATA          0x2c
-#define FS_CMD_WR_REQ_DATA          0x2d
-#define FS_CMD_WR_OFS_DATA          0x2e
-#define FS_CMD_SET_FILE_NAME        0x2f
-#define FS_CMD_DISK_CONNECT         0x30
-#define FS_CMD_DISK_MOUNT           0x31
-#define FS_CMD_FILE_OPEN            0x32
-#define FS_CMD_FILE_ENUM_GO         0x33
-#define FS_CMD_FILE_CREATE          0x34
-#define FS_CMD_FILE_ERASE           0x35
-#define FS_CMD_FILE_CLOSE           0x36
-#define FS_CMD_DIR_INFO_READ        0x37
-#define FS_CMD_DIR_INFO_SAVE        0x38
-#define FS_CMD_BYTE_LOCATE          0x39
-#define FS_CMD_BYTE_READ            0x3a
-#define FS_CMD_BYTE_RD_GO           0x3b
-#define FS_CMD_BYTE_WRITE           0x3c
-#define FS_CMD_BYTE_WR_GO           0x3d
-#define FS_CMD_DISK_CAPACITY        0x3e
-#define FS_CMD_DISK_QUERY           0x3f
-#define FS_CMD_DIR_CREATE           0x40
-#define FS_CMD_SET_ADDRESS          0x45
-#define FS_CMD_GET_DESCR            0x46
-#define FS_CMD_SET_CONFIG           0x49
-#define FS_CMD_AUTO_CONFIG          0x4D
-#define FS_CMD_ISSUE_TKN_X          0x4E
-
-#define FS_ANSW_RET_SUCCESS         0x51
-#define FS_ANSW_USB_INT_SUCCESS     0x14
-#define FS_ANSW_USB_INT_CONNECT     0x15
-#define FS_ANSW_USB_INT_DISCONNECT  0x16
-#define FS_ANSW_USB_INT_USB_READY   0x18
-#define FS_ANSW_USB_INT_DISK_READ   0x1d
-#define FS_ANSW_USB_INT_DISK_WRITE  0x1e
-#define FS_ANSW_RET_ABORT           0x5F
-#define FS_ANSW_USB_INT_DISK_ERR    0x1f
-#define FS_ANSW_USB_INT_BUF_OVER    0x17
-#define FS_ANSW_ERR_OPEN_DIR        0x41
-#define FS_ANSW_ERR_MISS_FILE       0x42
-#define FS_ANSW_ERR_FOUND_NAME      0x43
-#define FS_ANSW_ERR_DISK_DISCON     0x82
-#define FS_ANSW_ERR_LARGE_SECTOR    0x84
-#define FS_ANSW_ERR_TYPE_ERROR      0x92
-#define FS_ANSW_ERR_BPB_ERROR       0xa1
-#define FS_ANSW_ERR_DISK_FULL       0xb1
-#define FS_ANSW_ERR_FDT_OVER        0xb2
-#define FS_ANSW_ERR_FILE_CLOSE      0xb4
-#define FS_ERR_LONGFILENAME         0x01
-#define FS_ATTR_READ_ONLY           0x01
-#define FS_ATTR_HIDDEN              0x02
-#define FS_ATTR_SYSTEM              0x04
-#define FS_ATTR_VOLUME_ID           0x08
-#define FS_ATTR_DIRECTORY           0x10 
-#define FS_ATTR_ARCHIVE             0x20
-
-// Sets SPI1_CS low
-void FS_spiBeginTransfer()
-{
-    asm(
-        "; backup regs\n"
-        "push r1\n"
-        "push r2\n"
-
-        "load32 0xC0272C r2          ; r2 = 0xC0272C\n"
-
-        "load 0 r1                          ; r1 = 0 (enable)\n"
-        "write 0 r2 r1                      ; write to SPI1_CS\n"
-
-        "; restore regs\n"
-        "pop r2\n"
-        "pop r1\n"
-        );
-}
-
-// Sets SPI1_CS high
-void FS_spiEndTransfer()
-{
-    asm(
-        "; backup regs\n"
-        "push r1\n"
-        "push r2\n"
-
-        "load32 0xC0272C r2          ; r2 = 0xC0272C\n"
-
-        "load 1 r1                          ; r1 = 1 (disable)\n"
-        "write 0 r2 r1                      ; write to SPI1_CS\n"
-
-        "; restore regs\n"
-        "pop r2\n"
-        "pop r1\n"
-        );
-}
-
-// write dataByte and return read value
-// write 0x00 for a read
-// Writes byte over SPI1 to CH376
-word FS_spiTransfer(word dataByte)
-{
-    word retval = 0;
-    asm(
-        "load32 0xC0272B r2             ; r2 = 0xC0272B\n"
-        "write 0 r2 r4                      ; write r4 over SPI1\n"
-        "read 0 r2 r2                       ; read return value\n"
-        "write -4 r14 r2                    ; write to stack to return\n"
-        );
-
-    return retval;
-}
-
-
-
-
-// Get status after waiting for an interrupt
-word FS_WaitGetStatus()
-{
-    word intValue = 1;
-    while(intValue)
-    {
-        word *i = (word *) FS_INTERRUPT_ADDR;
-        intValue = *i;
-    }
-    FS_spiBeginTransfer();
-    FS_spiTransfer(FS_CMD_GET_STATUS);
-    FS_spiEndTransfer(); 
-    //delay(1);
-
-    FS_spiBeginTransfer();
-    word retval = FS_spiTransfer(0x00);
-    FS_spiEndTransfer(); 
-
-    return retval;
-}
-
-// Function to send a string (without terminating 0)
-void FS_sendString(char* str)
-{
-    char chr = *str;            // first character of str
-
-    while (chr != 0)            // continue until null value
-    {
-        FS_spiTransfer(chr);
-        str++;                  // go to next character address
-        chr = *str;             // get character from address
-    }
-}
-
-
-// Function to send data d of size s
-void FS_sendData(char* d, word s)
-{
-    char chr = *d;          // first byte of data
-
-    word i;
-    for(i = 0; (unsigned int) i < (unsigned int)s; i++)  // write s bytes
-    {
-        FS_spiTransfer(chr);
-        d++;                    // go to next data address
-        chr = *d;           // get data from address
-    }
-}
-
-// Returns file size of currently opened file (32 bits)
-word FS_getFileSize()
-{
-    FS_spiBeginTransfer();
-    FS_spiTransfer(FS_CMD_GET_FILE_SIZE);
-    FS_spiTransfer(0x68);
-    word retval = FS_spiTransfer(0);
-    retval = retval + (FS_spiTransfer(0) << 8);
-    retval = retval + (FS_spiTransfer(0) << 16);
-    retval = retval + (FS_spiTransfer(0) << 24);
-    FS_spiEndTransfer();
-
-    return retval;
-}
-
-
-// Sets cursor to position s
-// Returns FS_ANSW_USB_INT_SUCCESS on success
-word FS_setCursor(word s) 
-{
-    FS_spiBeginTransfer();
-    FS_spiTransfer(FS_CMD_BYTE_LOCATE);
-    FS_spiTransfer(s);
-    FS_spiTransfer((unsigned) s >> 8);
-    FS_spiTransfer((unsigned) s >> 16);
-    FS_spiTransfer((unsigned) s >> 24);
-    FS_spiEndTransfer();
-
-    return FS_WaitGetStatus();
-}
-
-
-// Reads s bytes into buf
-// If bytesToWord is true, four bytes will be stored in one address/word
-// Can read 65536 bytes per call
-// Returns FS_ANSW_USB_INT_SUCCESS on success
-// TODO: this surely can be optimized for speed in some way!
-word FS_readFile(char* buf, word s, word bytesToWord) 
-{
-    if (s == 0)
-        return FS_ANSW_USB_INT_SUCCESS;
-
-    FS_spiBeginTransfer();
-    FS_spiTransfer(FS_CMD_BYTE_READ);
-    FS_spiTransfer(s);
-    FS_spiTransfer((unsigned) s >> 8);
-    FS_spiEndTransfer();
-
-    word retval = FS_WaitGetStatus();
-    // Return on error or EOF
-    if (retval == FS_ANSW_USB_INT_SUCCESS) // eof
-        return 0;
-    if (retval != FS_ANSW_USB_INT_DISK_READ)
-        return retval;
-
-
-    word bytesRead = 0; 
-    word wordsRead = 0;
-    word doneReading = 0;
-
-    // clear first address
-    buf[wordsRead] = 0;
-
-    // used for shifting bytes to word
-    word currentByteShift = 24;
-
-    while (doneReading == 0)
-    {
-        // Read set of bytes (max 255)
-        FS_spiBeginTransfer();
-        FS_spiTransfer(FS_CMD_RD_USB_DATA0);
-        word readLen = FS_spiTransfer(0x00);
-
-        word readByte;
-
-        word i;
-        for (i = 0; i < readLen; i++) 
-        {
-            readByte = FS_spiTransfer(0x00);
-
-            // Read 4 bytes into one word, from left to right
-            if (bytesToWord)
-            {
-                readByte = readByte << currentByteShift;
-                buf[wordsRead] = buf[wordsRead] + readByte;
-
-
-                if (currentByteShift == 0)
-                {
-                    currentByteShift = 24;
-                    wordsRead++;
-                    buf[wordsRead] = 0;
-                }
-                else
-                {
-                    currentByteShift -= 8;
-                }
-
-            }
-            else
-            {
-                buf[bytesRead] = (char)readByte;
-                bytesRead = bytesRead + 1;
-            }
-        }
-        FS_spiEndTransfer();
-
-        // requesting another set of data
-        FS_spiBeginTransfer();
-        FS_spiTransfer(FS_CMD_BYTE_RD_GO);
-        FS_spiEndTransfer();
-
-        retval = FS_WaitGetStatus();
-        if (retval == FS_ANSW_USB_INT_SUCCESS)
-            doneReading = 1;
-        else if (retval == FS_ANSW_USB_INT_DISK_READ)
-        {
-            // read another block
-        }
-        else
-        {
-            uprintln("E: Error while reading data");
-            return retval;
-        }
-    }
-
-    return retval;
-}
-
-
-// Writes data d of size s
-// Can only write 65536 bytes at a time
-// returns FS_ANSW_USB_INT_SUCCESS on success
-// TODO: optimize for speed
-word FS_writeFile(char* d, word s) 
-{
-    if (s == 0)
-        return FS_ANSW_USB_INT_SUCCESS;
-
-    FS_spiBeginTransfer();
-    FS_spiTransfer(FS_CMD_BYTE_WRITE);
-    FS_spiTransfer(s);
-    FS_spiTransfer((unsigned) s >> 8);
-    FS_spiEndTransfer();
-
-    word retval = FS_WaitGetStatus();
-    // Return on error
-    if (retval != FS_ANSW_USB_INT_DISK_WRITE)
-        return retval;
-
-
-    word bytesWritten = 0;
-    word doneWriting = 0;
-
-    while (doneWriting == 0)
-    {
-        // Write set of bytes (max 255)
-        FS_spiBeginTransfer();
-        FS_spiTransfer(FS_CMD_WR_REQ_DATA);
-        word wrLen = FS_spiTransfer(0x00);
-
-        FS_sendData(d + bytesWritten, wrLen);
-        bytesWritten = bytesWritten + wrLen;
-        FS_spiEndTransfer();
-
-        // update file size
-        FS_spiBeginTransfer();
-        FS_spiTransfer(FS_CMD_BYTE_WR_GO);
-        FS_spiEndTransfer();
-
-
-        retval = FS_WaitGetStatus();
-        if (retval == FS_ANSW_USB_INT_SUCCESS)
-            doneWriting = 1;
-        else if (retval == FS_ANSW_USB_INT_DISK_WRITE)
-        {
-            // write another block
-        }
-        else
-        {
-            uprintln("E: Error while writing data");
-            return retval;
-        }
-
-    }
-    
-    return retval;
-}
-
-
-// returns status of opening a file/directory
-// Usually the successful status codes are:
-//  FS_ANSW_USB_INT_SUCCESS || FS_ANSW_ERR_OPEN_DIR || FS_ANSW_USB_INT_DISK_READ
-word FS_open() 
-{
-    FS_spiBeginTransfer();
-    FS_spiTransfer(FS_CMD_FILE_OPEN);
-    FS_spiEndTransfer();
-
-    return FS_WaitGetStatus();
-}
-
-
-// returns FS_ANSW_USB_INT_SUCCESS on success
-word FS_close() 
-{  
-    FS_spiBeginTransfer();
-    FS_spiTransfer(FS_CMD_FILE_CLOSE);
-    FS_spiTransfer(0x01); //0x01 if update filesize, else 0x00
-    FS_spiEndTransfer();
-
-    return FS_WaitGetStatus();
-}
-
-
-// Creates file (recreates if exists)
-// New files are 1 byte long
-// Have not found a way to set it to 0 bytes, 
-// since FS_CMD_SET_FILE_SIZE does not work
-// Automatically closes file
-// returns FS_ANSW_USB_INT_SUCCESS on success
-word FS_createFile() 
-{
-    FS_spiBeginTransfer();
-    FS_spiTransfer(FS_CMD_FILE_CREATE);
-    FS_spiEndTransfer();
-
-    word retval = FS_WaitGetStatus();
-    // Return on error
-    if (retval != FS_ANSW_USB_INT_SUCCESS)
-        return retval;
-
-    // open and close file
-    FS_open();
-    FS_close();
-
-    return FS_ANSW_USB_INT_SUCCESS;
-}
-
-
-// Sends single path f
-// No processing of f is done, it is directly sent
-// This means no error checking on file length!
-void FS_sendSinglePath(char* f) 
-{
-
-    // send buf
-    FS_spiBeginTransfer();
-    FS_spiTransfer(FS_CMD_SET_FILE_NAME);
-    FS_sendString(f);      // send file name
-    FS_spiTransfer(0);       // close with null
-    FS_spiEndTransfer();
-}
-
-
-// Sends path f
-// Can be relative or absolute file or directory
-// REQUIRES CAPITAL LETTERS and must conform the 8.3 filename standard
-// Function can handle folders with forward slashes
-// returns FS_ANSW_USB_INT_SUCCESS on success
-word FS_sendFullPath(char* f) 
-{
-    // path to uppercase and replace backslash by slash
-    word i = 0;
-    while (f[i] != 0)
-    {
-        f[i] = toUpper(f[i]);
-        if (f[i] == '\\')
-            f[i] = '/';
-        i++;
-    }
-
-    word removedSlash = 0; // to restore removed slash
-    // remove (single) trailing slash if exists
-    // we reuse i here since it points to the end of the path
-    if (i > 1) // ignore the root path
-    {
-        if (f[i-1] == '/')
-        {
-            f[i-1] = 0;
-            removedSlash = 1;
-        }
-    }
-
-    // if first char is a /, then we go back to root
-    if (f[0] == '/')
-    {
-        FS_sendSinglePath("/");
-        FS_open();
-    }
-
-    i = 0;
-    char buf[16]; // buffer for single folder/file name
-    word bufi = 0;
-
-    while (f[i] != 0)
-    {
-        // handle all directories
-        if (f[i] == 47) // forward slash
-        {
-            // return error on opening folders containing a single or double dot
-            if ((bufi == 1 && buf[0] == '.') || (bufi == 2 && buf[0] == '.' && buf[1] == '.'))
-                return FS_ANSW_ERR_OPEN_DIR;
-
-            // add null to end of buf
-            buf[bufi] = 0;
-            // send buf
-            FS_spiBeginTransfer();
-            FS_spiTransfer(FS_CMD_SET_FILE_NAME);
-            FS_sendString(buf);      // send folder name
-            FS_spiTransfer(0);       // close with null
-            FS_spiEndTransfer();
-            // reset bufi
-            bufi = 0;
-            // open folder
-            word retval = FS_open();
-            // Return on if failure / folder not found
-            if (retval != FS_ANSW_USB_INT_SUCCESS && retval != FS_ANSW_ERR_OPEN_DIR)
-                return retval;
-        }
-        else
-        {
-            buf[bufi] = f[i];
-            bufi++;
-            if (bufi > 13)
-                return FS_ERR_LONGFILENAME; // exit if folder/file name is too long
-        }
-        i++;
-    }
-    if (removedSlash) // restore removed slash if there
-    {
-        f[i] = '/';
-        f[i+1] = 0;
-    }
-
-    // handle filename itself (if any)
-    // add null to end of buf
-    buf[bufi] = 0;
-    if (bufi == 0)
-        return FS_ANSW_USB_INT_SUCCESS; // exit if there is no filename after the folder
-
-    // return error on opening folders containing a single or double dot
-    if ((bufi == 1 && buf[0] == '.') || (bufi == 2 && buf[0] == '.' && buf[1] == '.'))
-        return FS_ANSW_ERR_OPEN_DIR;
-
-    // send buf (last part of string)
-    FS_spiBeginTransfer();
-    FS_spiTransfer(FS_CMD_SET_FILE_NAME);
-    FS_sendString(buf);      // send file name
-    FS_spiTransfer(0);       // close with null
-    FS_spiEndTransfer();
-
-    return FS_ANSW_USB_INT_SUCCESS;
-}
-

+ 4 - 3
BCC/FPGCbuildTools/bcc/lib/math.c

@@ -165,13 +165,14 @@ word MATH_abs(word x)
     return -x;
 }
 
-
+/*
 word division(word dividend, word divisor)
 {
-    return MATH_divU(dividend, divisor);
+  return MATH_divU(dividend, divisor);
 }
 
 word modulo(word dividend, word divisor)
 {
-    return MATH_modU(dividend, divisor);
+  return MATH_modU(dividend, divisor);
 }
+*/

+ 19 - 371
BCC/FPGCbuildTools/bcc/lib/stdio.c

@@ -1,399 +1,47 @@
 /*
 * Stdio replacement library
-* Contains a subset of functions to use as drop-in replacement
-* Specifically made for porting the BCC compiler
-* Getc has a memory buffer, and puts is put entirely into memory
+* Maps common stdio functions to brfs functions
 */
 
-// maximum number of files to open at the same time (+1 because we skip index 0)
-#define FOPEN_MAX_FILES 16
-#define FOPEN_FILENAME_LIMIT 32
 #define EOF -1
 
-#define FOPEN_OUTFILE_ADDR 0x500000
 
-char fopenList[FOPEN_MAX_FILES][FOPEN_FILENAME_LIMIT]; // filenames for each opened file
-word fopenCurrentlyOpen[FOPEN_MAX_FILES]; // which indexes are currently opened
-word fopenCursors[FOPEN_MAX_FILES]; // cursors of currently opened files
-word CH376CurrentlyOpened = 0; // index in fopenList which is currently opened on CH376
-
-// Buffers for reading/writing
-// Length of buffer always should be less than 65536, since this is the maximum FS_readFile can do in a single call
-#define STDIO_FBUF_LEN 4096
-char *inputBuffer = (char*) INPUTBUFFER_ADDR; //[STDIO_FBUF_LEN];
-word inbufStartPos = 0; // where in the file the buffer starts
-word inbufCursor = 0; // where in the buffer we currently are working
-
-word outbufCursor = 0;
-word outFileIndex = 0;
-
-word includeDepth = 0; // keeping track how many levels we are deep compiling, for progress bar
-
-// fopen replacement
-// requires full paths
-// returns 0 on error
-// otherwise returns the index to the fopenList buffer
-// creates new file if write is 1
-// append is not an option for now
-word fopen(const char* fname, const word write)
-{
-    if (strlen(fname) >= FOPEN_FILENAME_LIMIT)
-    {
-        BDOS_PrintConsole("E: Path too large\n");
-        return 0;
-    }
-
-    if (fname[0] != '/')
-    {
-        BDOS_PrintConsole("E: Filename should be a full path\n");
-        return 0;
-    }
-
-    // conver to uppercase
-    strToUpper(fname);
-
-    // if write, create the file
-    if (write)
-    {
-        outbufCursor = 0; // where in the buffer we currently are working
-
-        FS_close(); // to be sure
-        CH376CurrentlyOpened = 0;
-
-        // if current path is correct (can be file or directory)
-        if (FS_sendFullPath(fname) == FS_ANSW_USB_INT_SUCCESS)
-        {
-            // create the file
-            
-            if (FS_createFile() == FS_ANSW_USB_INT_SUCCESS)
-            {
-                //BDOS_PrintConsole("File created\n");
-            }
-            else
-            {
-                BDOS_PrintConsole("E: Could not create file\n");
-                return 0;
-            }
-        }
-        else
-        {
-            BDOS_PrintConsole("E: Invalid path\n");
-            return 0;
-        }
-    }
-    else // read
-    {
-        FS_close();
-        CH376CurrentlyOpened = 0;
-
-        // init read buffer
-        inbufStartPos = 0; // start at 0
-        inbufCursor = 0; // start at 0
-    }
-
-    word i = 1; // skip index 0
-    while (i < FOPEN_MAX_FILES)
-    {
-        if (fopenCurrentlyOpen[i] == 0)
-        {
-            // found a free spot
-            fopenCurrentlyOpen[i] = 1;
-            fopenCursors[i] = 0;
-            // write filename
-            strcpy(fopenList[i], fname);
-
-            // so we know which file is the output file
-            if (write)
-            {
-                outFileIndex = i;
-            }
-            else
-            {
-                word x;
-                for (x = 0; x < includeDepth; x++)
-                {
-                    BDOS_PrintConsole("-");
-                }
-                BDOS_PrintlnConsole(fname);
-                includeDepth++;
-            }
-            return i; // return index
-        }
-        i++;
-    }
-
-    BDOS_PrintConsole("E: The maximum number of files are already opened. Forgot to close some files?\n");
-    return 0;
-}
-
-// returns EOF if file cannot be opened
-word fcanopen(word i)
-{
-    if (CH376CurrentlyOpened == i)
-    {
-        return 0;
-    }
-
-    FS_close();
-    CH376CurrentlyOpened = 0;
-
-    // if the resulting path is correct (can be file or directory)
-    if (FS_sendFullPath(fopenList[i]) == FS_ANSW_USB_INT_SUCCESS)
-    {
-
-        // if we can successfully open the file (not directory)
-        if (FS_open() == FS_ANSW_USB_INT_SUCCESS)
-        {
-            FS_close();
-            return 0;
-        }
-        else
-        {
-            return EOF;
-        }
-    }
-    else
-    {
-        return EOF;
-    }
-
-    return EOF;
-}
-
-
-// closes file at index
-// also closes the file on CH376 if it is currently open there as well
-void fclose(word i)
-{
-    if (CH376CurrentlyOpened == i)
-    {
-        FS_close(); // to be sure
-        CH376CurrentlyOpened = 0;
-    }
-
-    // if output file, write entire buffer to the file
-    if (outFileIndex == i && i > 0)
-    {
-        BDOS_PrintConsole("\nWriting to output file:\n");
-        // close other file if open
-        FS_close();
-        CH376CurrentlyOpened = 0;
-
-        // if the resulting path is correct (can be file or directory)
-        if (FS_sendFullPath(fopenList[i]) == FS_ANSW_USB_INT_SUCCESS)
-        {
-
-            // if we can successfully open the file (not directory)
-            if (FS_open() == FS_ANSW_USB_INT_SUCCESS)
-            {
-                FS_setCursor(0); // set cursor to start
-                word bytesWritten = 0;
-                word* outbufAddr = (word*) FOPEN_OUTFILE_ADDR;
-
-                // loop until all bytes are sent
-                while (bytesWritten != outbufCursor)
-                {
-                    word partToSend = outbufCursor - bytesWritten;
-                    // send in parts of 0xFFFF
-                    if (partToSend > 0xFFFF)
-                        partToSend = 0xFFFF;
-
-                    // write away
-                    if (FS_writeFile((outbufAddr +bytesWritten), partToSend) != FS_ANSW_USB_INT_SUCCESS)
-                        BDOS_PrintConsole("write error\n");
-
-                    // Update the amount of bytes sent
-                    bytesWritten += partToSend;
-
-                    BDOS_PrintConsole(".");
-                }
-                BDOS_PrintConsole("\nDone!\n");
-                FS_close();
-            }
-            else
-            {
-                BDOS_PrintConsole("E: could not open outfile\n");
-                return;
-            }
-        }
-        else
-        {
-            BDOS_PrintConsole("E: could not open outfile\n");
-            return;
-        }
-
-        outFileIndex = 0;
-    }
-    else
-    {
-        includeDepth--;
-        word x;
-        for (x = 0; x < includeDepth; x++)
-        {
-            BDOS_PrintConsole("-");
-        }
-        BDOS_PrintlnConsole("Done");
-    }
-
-    fopenCurrentlyOpen[i] = 0;
-    fopenList[i][0] = 0; // to be sure
-}
-
-
-// returns the current char at cursor (EOF is end of file)
+// returns the current char at cursor within the opened file (EOF if end of file)
 // increments the cursor
-word fgetc(word i)
+word fgetc(word fd, word filesize)
 {
-    // check if file is open
-    if (fopenCurrentlyOpen[i] == 0)
-    {
-        BDOS_PrintConsole("fgetc: File is not open\n");
-        return EOF;
-    }
-
-    // open on CH376 if not open already
-    if (CH376CurrentlyOpened != i)
-    {
-        // close last one first, unless there is no last
-        if (CH376CurrentlyOpened != 0)
-        {
-            //BDOS_PrintConsole("fgetc: Closed previous file\n");
-            FS_close();
-        }
-
-
-        // if the resulting path is correct (can be file or directory)
-        if (FS_sendFullPath(fopenList[i]) == FS_ANSW_USB_INT_SUCCESS)
-        {
-
-            // if we can successfully open the file (not directory)
-            if (FS_open() == FS_ANSW_USB_INT_SUCCESS)
-            {
-                CH376CurrentlyOpened = i;
-                // set cursor to last position
-                FS_setCursor(fopenCursors[i]);
-
-                // reset the buffer
-                inbufStartPos = fopenCursors[i];
-                inbufCursor = 0;
-
-                //BDOS_PrintConsole("fgetc: File opened on CH376\n");
-            }
-            else
-            {
-                BDOS_PrintConsole("E: Could not open file\n");
-                return EOF;
-            }
-        }
-        else
-        {
-            BDOS_PrintConsole("E: Invalid path\n");
-            return EOF;
-        }
-    }
-
-    // workaround for missing compiler check for ALU constants > 11 bit
-    word stdioBufLen = STDIO_FBUF_LEN;
-
-    if (inbufCursor >= STDIO_FBUF_LEN || inbufCursor == 0)  // we are at the end of the buffer (or it is not initialized yet)
-    {
-        // get filesize
-        word sizeOfFile = FS_getFileSize();
-        
-        // if we cannot completely fill the buffer:
-        if (inbufStartPos + stdioBufLen > sizeOfFile)
-        {
-            //  fill the buffer, and append with EOF token
-            FS_readFile(inputBuffer, sizeOfFile - inbufStartPos, 0);
-            inputBuffer[sizeOfFile - inbufStartPos] = EOF;
-        }
-        else
-        {
-            //  Fill buffer again
-            FS_readFile(inputBuffer, STDIO_FBUF_LEN, 0);
-        }
-        
-        inbufStartPos += stdioBufLen; // for the next fill
-
-        inbufCursor = 0; // start at the beginning of the buffer again
-    }
-
-    // return from the buffer, and increment
-    char gotchar = inputBuffer[inbufCursor];
-    inbufCursor++;
-    fopenCursors[i]++;
-    // BDOS_PrintcConsole(gotchar); // useful for debugging
-    return gotchar;
-}
-
+  word cursor = fs_getcursor(fd);
+  if (cursor == filesize)
+  {
+    return EOF;
+  }
 
-// write to memory buffer
-word fputs(word i, char* s)
-{
-    if (i != outFileIndex)
-    {
-        BDOS_PrintConsole("W: Writing to something else than outfile!\n");
-    }
-    word* outbufAddr = (word*) FOPEN_OUTFILE_ADDR;
-    word slen = strlen(s);
-    memcpy((outbufAddr +outbufCursor), s, slen);
-    outbufCursor += slen;
-    return 1;
+  char c;
+  fs_read(fd, &c, 1);
+  return c;
 }
 
 
-// write to memory buffer
-word fputc(word i, char c)
+// write string to file
+word fputs(word fd, char* s)
 {
-    if (i != outFileIndex)
-    {
-        BDOS_PrintConsole("W: Writing to something else than outfile!\n");
-    }
-    word* outbufAddr = (word*) FOPEN_OUTFILE_ADDR;
-    *(outbufAddr +outbufCursor) = c;
-    outbufCursor++;
+    fs_write(fd, s, strlen(s));
     return 1;
 }
 
-int fgetpos(word i)
+// write string to file
+word fputc(word fd, char c)
 {
-    if (i != outFileIndex)
-    {
-        BDOS_PrintConsole("W: Getting cursor for something else than outfile!\n");
-    }
-    return outbufCursor;
-}
-
-int fsetpos(word i, word c)
-{
-    if (i != outFileIndex)
-    {
-        BDOS_PrintConsole("W: Setting cursor for something else than outfile!\n");
-    }
-    outbufCursor = c;
+    fs_write(fd, &c, 1);
     return 1;
 }
 
 word printf(char* s)
 {
-    BDOS_PrintConsole(s);
+    bdos_print(s);
 }
 
 word printd(word d)
 {
-    if (d < 0)
-    {
-        BDOS_PrintcConsole('-');
-        BDOS_PrintDecConsole(-d);
-    }
-    else
-    {
-        BDOS_PrintDecConsole(d);
-    }
-    
+    bdos_printdec(d);
 }
-
-void exit(word i)
-{
-    asm("jump Return_BDOS\n");
-}

+ 102 - 9
BCC/FPGCbuildTools/bcc/lib/stdlib.c

@@ -16,6 +16,16 @@
 #define TIMER3_VAL 0xC0273D
 #define TIMER3_CTRL 0xC0273E
 
+word timer1Value = 0;
+word timer2Value = 0;
+word timer3Value = 0;
+
+/*
+* TODO:
+* - Convert most of these functions to assembly
+*/
+
+
 // isalpha
 word isalpha(word argument)
 {
@@ -139,6 +149,66 @@ char* strchr (const char *s, word c)
   return (0);
 }
 
+/*
+Returns a pointer to the last occurance of a character, or 0 if the character is not found.
+*/
+char* strrchr (const char *s, int c)
+{
+  char *rtnval = 0;
+
+  do {
+    if (*s == c)
+      rtnval = (char*) s;
+  } while (*s++);
+  return (rtnval);
+}
+
+
+char * strtok_old_str;
+/* 
+Parse str into tokens separated by characters in delim.
+If S is NULL, the last string strtok() was called with is used.
+Note that strtok() modifies the input string.
+For example:
+	char s[] = "-abc-=-def";
+	x = strtok(s, "-");		// x = "abc"
+	x = strtok(NULL, "-=");		// x = "def"
+	x = strtok(NULL, "=");		// x = NULL
+		// s = "abc\0=-def\0"
+*/
+char* strtok(char* str, const char* delim)
+{
+  if (str != (word*)-1)
+    strtok_old_str = str;
+
+  if (strtok_old_str == (word*)-1)
+    return (word*)-1;
+
+  // Return reached end of string
+  if (*strtok_old_str == 0)
+  {
+    return (word*)-1;
+  }
+  // Skip leading delimiters
+  while (strchr(delim, *strtok_old_str) != 0)
+    strtok_old_str++;
+
+  // Find end of token
+  char* start = strtok_old_str;
+  while (*strtok_old_str != 0 && strchr(delim, *strtok_old_str) == 0)
+    strtok_old_str++;
+
+  if (*strtok_old_str == 0)
+  {
+    strtok_old_str = (word*)-1;
+    return start;
+  }
+
+  *strtok_old_str = 0;
+  strtok_old_str++;
+  return start;
+}
+
 
 word strcmp(const char* s1, const char* s2)
 {
@@ -168,19 +238,42 @@ word strncmp(const char * s1, const char * s2, size_t n )
   }
 }
 
-// Returns interrupt ID by using the readintid asm instruction
-word getIntID()
+/**
+ * Return the basename of a path
+ * path: full path
+*/
+char* basename(char *path)
 {
-  word retval = 0;
-
-  asm(
-    "readintid r2  ;reads interrupt id to r2\n"
-    "write -4 r14 r2 ;write to stack to return\n"
-    );
+  char *base = strrchr(path, '/');
+  return base ? base + 1 : path;
+}
 
-  return retval;
+/**
+ * Return the dirname of a path
+ * output: buffer to store the dirname
+ * path: full path
+*/
+char* dirname(char* output, char *path)
+{
+  strcpy(output, path);
+  char *last_slash = strrchr(output, '/');
+  if (last_slash != 0)
+  {
+    *last_slash = 0;
+    // If the last slash is the first character, return "/"
+    if (last_slash == output)
+    {
+      strcpy(output, "/");
+    }
+  } else
+  {
+    // No slash found, return "."
+    strcpy(output, ".");
+  }
+  return output;
 }
 
+
 /*
 Recursive helper function for itoa
 Eventually returns the number of digits in n

+ 353 - 112
BCC/FPGCbuildTools/bcc/lib/sys.c

@@ -1,9 +1,8 @@
-/*
-Contains System Call functions
+/**
+ * Contains system functions for user programs
+ * Contains code for system calls and interrupt handling
 */
 
-#define SYSCALL_RETVAL_ADDR 0x200000
-
 // Interrupt IDs for interrupt handler
 #define INTID_TIMER1  0x1
 #define INTID_TIMER2  0x2
@@ -14,134 +13,376 @@ Contains System Call functions
 #define INTID_UART1   0x7
 #define INTID_UART2   0x8
 
+#define SYSCALL_RETVAL_ADDR 0x200000
+
+// System call IDs
+#define SYS_HID_CHECKFIFO 1
+#define SYS_HID_READFIFO 2
+#define SYS_BDOS_PRINTC 3
+#define SYS_BDOS_PRINT 4
+#define SYS_FS_OPEN 5
+#define SYS_FS_CLOSE 6
+#define SYS_FS_READ 7
+#define SYS_FS_WRITE 8
+#define SYS_FS_SETCURSOR 9
+#define SYS_FS_GETCURSOR 10
+#define SYS_FS_DELETE 11
+#define SYS_FS_MKDIR 12
+#define SYS_FS_MKFILE 13
+#define SYS_FS_STAT 14
+#define SYS_FS_READDIR 15
+#define SYS_FS_GETCWD 16
+#define SYS_FS_SYNCFLASH 17
+// Syscalls 18-19 are reserved for future use
+#define SYS_SHELL_ARGC 20
+#define SYS_SHELL_ARGV 21
+#define SYS_USB_KB_BUF 99
 
-// executes system call to BDOS
-// ID is written to the same location as the output of the system call
-//  at address SYSCALL_RETVAL_ADDR
-// This address is also returned
+
+/**
+ * Returns the interrupt ID
+*/
+word get_int_id()
+{
+  word retval = 0;
+
+  asm(
+    "readintid r2     ;reads interrupt id to r2\n"
+    "write -4 r14 r2  ;write to stack to return\n"
+    );
+
+  return retval;
+}
+
+/**
+ * Executes system call to BDOS
+ * Argument specifies the system call ID
+ * Returns the address of the return value
+*/
 word* syscall(word ID)
 {
-    word* p = (word*) SYSCALL_RETVAL_ADDR;
-    *p = ID;
-
-    asm("push r1\n"
-        "push r2\n"
-        "push r3\n"
-        "push r4\n"
-        "push r5\n"
-        "push r6\n"
-        "push r7\n"
-        "push r8\n"
-        "push r9\n"
-        "push r10\n"
-        "push r11\n"
-        "push r12\n"
-        "push r13\n"
-        "push r14\n"
-        "push r15\n"
-        "savpc r1\n"
-        "push r1\n"
-        "jump 4\n"
-        "pop r15\n"
-        "pop r14\n"
-        "pop r13\n"
-        "pop r12\n"
-        "pop r11\n"
-        "pop r10\n"
-        "pop r9\n"
-        "pop r8\n"
-        "pop r7\n"
-        "pop r6\n"
-        "pop r5\n"
-        "pop r4\n"
-        "pop r3\n"
-        "pop r2\n"
-        "pop r1\n");
-
-    return p;
-}
-
-void BDOS_PrintcConsole(char c)
-{
-    char* p = (char*) SYSCALL_RETVAL_ADDR;
-    p[1] = c;
-    syscall(3);
-}
-
-// Prints string on BDOS console untill terminator
-// Does not add newline at end
-void BDOS_PrintConsole(char* str)
-{
-    char chr = *str;            // first character of str
-
-    while (chr != 0)            // continue until null value
-    {
-        BDOS_PrintcConsole(chr);
-        str++;                  // go to next character address
-        chr = *str;             // get character from address
-    }
+  word* p = (word*) SYSCALL_RETVAL_ADDR;
+  *p = ID;
+
+  asm("push r1\n"
+    "push r2\n"
+    "push r3\n"
+    "push r4\n"
+    "push r5\n"
+    "push r6\n"
+    "push r7\n"
+    "push r8\n"
+    "push r9\n"
+    "push r10\n"
+    "push r11\n"
+    "push r12\n"
+    "push r13\n"
+    "push r14\n"
+    "push r15\n"
+    "savpc r1\n"
+    "push r1\n"
+    "jump 4\n"
+    "pop r15\n"
+    "pop r14\n"
+    "pop r13\n"
+    "pop r12\n"
+    "pop r11\n"
+    "pop r10\n"
+    "pop r9\n"
+    "pop r8\n"
+    "pop r7\n"
+    "pop r6\n"
+    "pop r5\n"
+    "pop r4\n"
+    "pop r3\n"
+    "pop r2\n"
+    "pop r1\n");
+
+  return p;
+}
+
+/**
+ * Exits the user program and returns to BDOS in a somewhat controlled way
+*/
+void exit(word n)
+{
+  asm("ccache\n");
+  asm("jump Return_BDOS\n");
+}
+
+/**
+ * Returns 1 if the HID buffer is not empty
+*/
+word hid_checkfifo()
+{
+  char* p = (char*) SYSCALL_RETVAL_ADDR;
+  syscall(SYS_HID_CHECKFIFO);
+  return p[0];
+}
+
+/**
+ * Reads a character from the HID buffer
+*/
+word hid_fiforead()
+{
+  char* p = (char*) SYSCALL_RETVAL_ADDR;
+  syscall(SYS_HID_READFIFO);
+  return p[0];
 }
 
-void BDOS_PrintlnConsole(char* str)
+/**
+ * Prints a character on the BDOS console
+*/
+void bdos_printc(char c)
 {
-    BDOS_PrintConsole(str);
-    BDOS_PrintcConsole('\n');
+  char* p = (char*) SYSCALL_RETVAL_ADDR;
+  p[1] = c;
+  syscall(SYS_BDOS_PRINTC);
 }
 
-void BDOS_PrintDecConsole(word i)
+/**
+ * Prints a string on the BDOS console
+*/
+void bdos_print(char* c)
 {
-    char buffer[11];
+  char* p = (char*) SYSCALL_RETVAL_ADDR;
+  p[1] = (char)c;
+  syscall(SYS_BDOS_PRINT);
+}
+
+/**
+ * Prints a string with newline on the BDOS console
+*/
+void bdos_println(char* str)
+{
+  bdos_print(str);
+  bdos_printc('\n');
+}
+
+/**
+ * Prints a decimal on the BDOS console
+*/
+void bdos_printdec(word i)
+{
+  char buffer[12];
+
+  if (i < 0)
+  {
+    buffer[0] = '-';
+    itoa(MATH_abs(i), &buffer[1]);
+  }
+  else
+  {
     itoa(i, buffer);
-    BDOS_PrintConsole(buffer);
+  }
+  bdos_print(buffer);
 }
 
-// Returns command line args
-char* BDOS_GetArgs()
+/**
+ * Prints a decimal with newline on the BDOS console
+*/
+void bdos_printdecln(word i)
 {
-    char* p = syscall(4);
-    return (char*) p[0];
+  bdos_printdec(i);
+  bdos_printc('\n');
 }
 
+/**
+ * Prints a hexadecimal on the BDOS console
+*/
+void bdos_printhex(word i)
+{
+  char buffer[11];
+  itoah(i, buffer);
+  bdos_print(buffer);
+}
 
-// Writes command line argument n into buf
-// Arg 0 is the command itself
-void BDOS_GetArgN(word n, char* buf)
+/**
+ * Opens a file in the filesystem
+*/
+word fs_open(char* filename)
 {
-    char* args = BDOS_GetArgs();
+  char* p = (char*) SYSCALL_RETVAL_ADDR;
+  p[1] = (char) filename;
+  syscall(SYS_FS_OPEN);
+  return p[0];
+}
 
-    word i = 0;
-    word bufi = 0;
-    word currentArg = 0;
-    char prevChar = 0;
-    buf[0] = 0;
-    while (args[i] != 0)
-    {
-        // new argument
-        if (args[i] == ' ' && prevChar != ' ')
-        {
-            currentArg++;
-        }
-
-        if (args[i] != ' ')
-        {
-            if (currentArg == n)
-            {
-                buf[bufi] = args[i];
-                bufi++;
-            }
-        }
-
-        prevChar = args[i];
-        i++;
-    }
+/**
+ * Closes a file in the filesystem
+*/
+word fs_close(word fp)
+{
+  char* p = (char*) SYSCALL_RETVAL_ADDR;
+  p[1] = fp;
+  syscall(SYS_FS_CLOSE);
+  return p[0];
+}
 
-    buf[bufi] = 0; // terminate
+/**
+ * Reads from a file in the filesystem
+*/
+word fs_read(word fp, char* buffer, word len)
+{
+  char* p = (char*) SYSCALL_RETVAL_ADDR;
+  p[1] = fp;
+  p[2] = (char) buffer;
+  p[3] = len;
+  syscall(SYS_FS_READ);
+  return p[0];
 }
 
+/**
+ * Writes to a file in the filesystem
+*/
+word fs_write(word fp, char* buffer, word len)
+{
+  char* p = (char*) SYSCALL_RETVAL_ADDR;
+  p[1] = fp;
+  p[2] = (char) buffer;
+  p[3] = len;
+  syscall(SYS_FS_WRITE);
+  return p[0];
+}
+
+/**
+ * Sets the cursor position in the filesystem
+*/
+word fs_setcursor(word fp, word pos)
+{
+  char* p = (char*) SYSCALL_RETVAL_ADDR;
+  p[1] = fp;
+  p[2] = pos;
+  syscall(SYS_FS_SETCURSOR);
+  return p[0];
+}
+
+/**
+ * Gets the cursor position in the filesystem
+*/
+word fs_getcursor(word fp)
+{
+  char* p = (char*) SYSCALL_RETVAL_ADDR;
+  p[1] = fp;
+  syscall(SYS_FS_GETCURSOR);
+  return p[0];
+}
+
+/**
+ * Deletes a file in the filesystem
+*/
+word fs_delete(char* filename)
+{
+  char* p = (char*) SYSCALL_RETVAL_ADDR;
+  p[1] = (char) filename;
+  syscall(SYS_FS_DELETE);
+  return p[0];
+}
 
-// Returns BDOS current path
-char* BDOS_GetPath()
+/**
+ * Creates a directory in the filesystem
+*/
+word fs_mkdir(char* dirname)
+{
+  char* p = (char*) SYSCALL_RETVAL_ADDR;
+  p[1] = (char) dirname;
+  syscall(SYS_FS_MKDIR);
+  return p[0];
+}
+
+/**
+ * Creates a file in the filesystem
+*/
+word fs_mkfile(char* filename)
 {
-    word* p = syscall(5);
-    return (char*) p[0];
-}
+  char* p = (char*) SYSCALL_RETVAL_ADDR;
+  p[1] = (char) filename;
+  syscall(SYS_FS_MKFILE);
+  return p[0];
+}
+
+/**
+ * Gets the status of a file in the filesystem
+*/
+word fs_stat(char* filename)
+{
+  char* p = (char*) SYSCALL_RETVAL_ADDR;
+  p[1] = (char) filename;
+  syscall(SYS_FS_STAT);
+  return p[0];
+}
+
+/**
+ * Lists the contents of a directory in the filesystem
+ * Returns the number of entries in the directory
+*/
+word fs_readdir(char* dirname, char* buffer)
+{
+  char* p = (char*) SYSCALL_RETVAL_ADDR;
+  p[1] = (char) dirname;
+  p[2] = (char) buffer;  
+  syscall(SYS_FS_READDIR);
+  return p[0];
+}
+
+/**
+ * Gets the current working directory in the filesystem
+ * Note: The pointer returned is only valid until the next syscall
+*/
+char* fs_getcwd()
+{
+  char* p = (char*) SYSCALL_RETVAL_ADDR;
+  syscall(SYS_FS_GETCWD);
+  return p;
+}
+
+/**
+ * Synchronizes the filesystem with the flash memory
+*/
+word fs_syncflash()
+{
+  char* p = (char*) SYSCALL_RETVAL_ADDR;
+  syscall(SYS_FS_SYNCFLASH);
+  return p[0];
+}
+
+/**
+ * Returns the number of command line arguments
+*/
+word shell_argc()
+{
+  char* p = (char*) SYSCALL_RETVAL_ADDR;
+  syscall(SYS_SHELL_ARGC);
+  return p[0];
+}
+
+/**
+ * Returns the command line arguments
+ * Note: The pointer returned is only valid until the next syscall
+*/
+char* shell_argv()
+{
+  char* p = (char*) SYSCALL_RETVAL_ADDR;
+  syscall(SYS_SHELL_ARGV);
+  return p;
+}
+
+/**
+ * Returns 1 if key is being held on USB keyboard
+*/
+word bdos_usbkey_held(word c)
+{
+  char* p = (char*) SYSCALL_RETVAL_ADDR;
+  syscall(SYS_USB_KB_BUF);
+  word* usbKeyBuffer = (char*) p[0];
+  
+  word i;
+  for (i = 0; i < 8; i++)
+  {
+    if (usbKeyBuffer[i] == c)
+    {
+      return 1;
+    }
+  }
+  return 0;
+}

+ 0 - 8223
BCC/FPGCbuildTools/bcc/nodefbcc.c

@@ -1,8223 +0,0 @@
-/*
-Copyright (c) 2021, bartpleiter
-Copyright (c) 2012-2020, Alexey Frunze
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions are met:
-
-1. Redistributions of source code must retain the above copyright notice, this
-   list of conditions and the following disclaimer.
-2. Redistributions in binary form must reproduce the above copyright notice,
-   this list of conditions and the following disclaimer in the documentation
-   and/or other materials provided with the distribution.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
-ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
-ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
-(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
-LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
-ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-*/
-
-/*****************************************************************************/
-/*                                                                           */
-/*                           BCC (B322 C Compiler)                           */
-/*                                                                           */
-/*                           C compiler for B322                             */
-/*                                                                           */
-/*                            Based on SmallerC:                             */
-/*                 A simple and small single-pass C compiler                 */
-/*                                                                           */
-/*                                Main file                                  */
-/*                                                                           */
-/*****************************************************************************/
-
-// NOTE: still has a lot of extras in it that are not needed
-//  only the "MIPS" part is needed with no extras
-
-// Making most functions static helps with code optimization,
-// use that to further reduce compiler's code size on RetroBSD.
-#define STATIC
-
-#define NO_EXTRAS
-#define CAN_COMPILE_32BIT
-#define MIPS
-#define B322
-#define NO_PPACK
-#define NO_TYPEDEF_ENUM
-#define NO_FUNC_
-#define NO_EXTRA_WARNS
-#define NO_FOR_DECL
-#define NO_STRUCT_BY_VAL
-#define NO_FP
-#define NO_WCHAR
-
-#define NULL 0
-
-#define size_t unsigned int
-
-#define CHAR_BIT (8)
-#define CHAR_MIN (-128)
-#define CHAR_MAX (127)
-
-#define INT_MAX (2147483647)
-#define INT_MIN (-2147483647-1)
-
-#define UINT_MAX (4294967295u)
-#define UINT_MIN (0u)
-
-#define EXIT_FAILURE 1
-
-void exit(int);
-int atoi(char*);
-
-size_t strlen(char*);
-char* strcpy(char*, char*);
-char* strchr(char*, int);
-int strcmp(char*, char*);
-int strncmp(char*, char*, size_t);
-void* memmove(void*, void*, size_t);
-void* memcpy(void*, void*, size_t);
-void* memset(void*, int, size_t);
-int memcmp(void*, void*, size_t);
-
-int isspace(int);
-int isdigit(int);
-int isalpha(int);
-int isalnum(int);
-
-#define FILE void
-#define EOF (-1)
-FILE* fopen(char*, char*);
-int fclose(FILE*);
-//int putchar(int);
-int fputc(int, FILE*);
-int fgetc(FILE*);
-//int puts(char*);
-int fputs(char*, FILE*);
-//int sprintf(char*, char*, ...);
-//int vsprintf(char*, char*, va_list);
-//int vsprintf(char*, char*, void*);
-int printf(char*, ...);
-//int fprintf(FILE*, char*, ...);
-//int vprintf(char*, va_list);
-//int vprintf(char*, void*);
-//int vfprintf(FILE*, char*, va_list);
-int vfprintf(FILE*, char*, void*);
-
-/*
-struct fpos_t_
-{
-  union
-  {
-    unsigned short halves[2]; // for 16-bit memory models without 32-bit longs
-    int align; // for alignment on machine word boundary
-  } u;
-}; // keep in sync with stdio.h !!!
-#define fpos_t struct fpos_t_
-int fgetpos(FILE*, fpos_t*);
-int fsetpos(FILE*, fpos_t*);
-*/
-
-
-////////////////////////////////////////////////////////////////////////////////
-
-// all public macros
-
-#define MAX_IDENT_LEN         63
-#define MAX_STRING_LEN        255
-#define MAX_CHAR_QUEUE_LEN    (MAX_STRING_LEN + 1)
-#define MAX_MACRO_TABLE_LEN   (4096+1024)
-#define MAX_IDENT_TABLE_LEN   (4096+1024+512) // must be greater than MAX_IDENT_LEN
-#define SYNTAX_STACK_MAX      (2048+1024)
-#define MAX_FILE_NAME_LEN     95
-
-#define MAX_INCLUDES         8
-#define PREP_STACK_SIZE      8
-#define MAX_SEARCH_PATH      256
-
-
-/* +-~* /% &|^! << >> && || < <= > >= == !=  () *[] ++ -- = += -= ~= *= /= %= &= |= ^= <<= >>= {} ,;: -> ... */
-
-#define tokEof        0
-#define tokNumInt     1
-#define tokNumUint    2
-#define tokLitStr     3
-
-#define tokLShift     4
-#define tokRShift     5
-#define tokLogAnd     6
-#define tokLogOr      7
-#define tokEQ         8
-#define tokNEQ        9
-#define tokLEQ        10
-#define tokGEQ        11
-#define tokInc        12
-#define tokDec        13
-#define tokArrow      14
-#define tokEllipsis   15
-
-#define tokIdent      16
-#define tokVoid       17
-#define tokChar       18
-#define tokInt        19
-#define tokReturn     20
-#define tokGoto       21
-#define tokIf         22
-#define tokElse       23
-#define tokWhile      24
-#define tokCont       25
-#define tokBreak      26
-#define tokSizeof     27
-
-#define tokAssignMul  'A'
-#define tokAssignDiv  'B'
-#define tokAssignMod  'C'
-#define tokAssignAdd  'D'
-#define tokAssignSub  'E'
-#define tokAssignLSh  'F'
-#define tokAssignRSh  'G'
-#define tokAssignAnd  'H'
-#define tokAssignXor  'I'
-#define tokAssignOr   'J'
-
-#define tokFloat      'a'
-#define tokDouble     'b'
-#define tokLong       'c'
-#define tokShort      'd'
-#define tokUnsigned   'e'
-#define tokSigned     'f'
-#define tokConst      'g'
-#define tokVolatile   'h'
-#define tokRestrict   'i'
-#define tokStatic     'j'
-#define tokInline     'k'
-#define tokExtern     'l'
-#define tokAuto       'm'
-#define tokRegister   'n'
-#define tokTypedef    'o'
-#define tokEnum       'p'
-#define tokStruct     'q'
-#define tokUnion      'r'
-#define tokDo         's'
-#define tokFor        't'
-#define tokSwitch     'u'
-#define tokCase       'v'
-#define tokDefault    'w'
-#define tok_Bool      'x'
-#define tok_Complex   'y'
-#define tok_Imagin    'z'
-
-#define tok_Asm       '`'
-
-/* Pseudo-tokens (converted from others or generated) */
-#define tokURShift    28
-#define tokUDiv       29
-#define tokUMod       30
-#define tokAssignURSh 31
-#define tokAssignUDiv '@'
-#define tokAssignUMod 'K'
-#define tokComma      '0'
-
-#define tokIfNot      'L'
-
-#define tokUnaryAnd   'M'
-#define tokUnaryStar  'N'
-#define tokUnaryPlus  'O'
-#define tokUnaryMinus 'P'
-
-#define tokPostInc    'Q'
-#define tokPostDec    'R'
-#define tokPostAdd    'S'
-#define tokPostSub    'T'
-
-#define tokULess      'U'
-#define tokUGreater   'V'
-#define tokULEQ       'W'
-#define tokUGEQ       'X'
-
-#define tokLocalOfs   'Y'
-#define tokShortCirc  'Z'
-
-#define tokSChar      0x80
-#define tokUChar      0x81
-#define tokUShort     0x82
-#define tokULong      0x83
-//#define tokLongLong   0x84
-//#define tokULongLong  0x85
-//#define tokLongDbl    0x86
-#define tokGotoLabel  0x8F
-#define tokStructPtr  0x90
-#define tokTag        0x91
-#define tokMemberIdent 0x92
-#define tokEnumPtr    0x93
-#define tokIntr       0x94
-#define tokNumFloat   0x95
-#define tokNumCharWide 0x96
-#define tokLitStrWide 0x97
-
-//#define FormatFlat      0
-#define FormatSegmented 1
-//#define FormatSegTurbo  2
-#define FormatSegHuge   3
-#define FormatSegUnreal 4
-
-#define SymVoidSynPtr 0
-#define SymIntSynPtr  1
-#define SymUintSynPtr 2
-#define SymWideCharSynPtr 3
-#define SymFloatSynPtr 4
-#define SymFuncPtr    5
-
-#define STACK_SIZE 129
-
-#define SymFxn       1
-#define SymGlobalVar 2
-#define SymGlobalArr 3
-#define SymLocalVar  4
-#define SymLocalArr  5
-
-// Division and Modulo without / and %
-STATIC
-int divmod(int dividend, int divisor, int* rem)
-{
-    int quotient = 1;
-
-    int neg = 1;
-    if ((dividend>0 &&divisor<0)||(dividend<0 && divisor>0))
-        neg = -1;
-
-    // Convert to positive
-    int tempdividend = (dividend < 0) ? -dividend : dividend;
-    int tempdivisor = (divisor < 0) ? -divisor : divisor;
-
-    if (tempdivisor == tempdividend) {
-        *rem = 0;
-        return 1*neg;
-    }
-    else if (tempdividend < tempdivisor) {
-        if (dividend < 0)
-            *rem = tempdividend*neg;
-        else
-            *rem = tempdividend;
-        return 0;
-    }
-    while (tempdivisor<<1 <= tempdividend)
-    {
-        tempdivisor = tempdivisor << 1;
-        quotient = quotient << 1;
-    }
-
-    // Call division recursively
-    if(dividend < 0)
-        quotient = quotient*neg + divmod(-(tempdividend-tempdivisor), divisor, rem);
-    else
-        quotient = quotient*neg + divmod(tempdividend-tempdivisor, divisor, rem);
-     return quotient;
-}
-
-STATIC
-int division(int dividend, int divisor)
-{
-    int rem = 0;
-    return divmod(dividend, divisor, &rem);
-}
-
-STATIC
-int modulo(int dividend, int divisor)
-{
-    int rem = 0;
-    divmod(dividend, divisor, &rem);
-    return rem;
-}
-
-
-// isalpha
-STATIC
-int isalpha(int argument)
-{
-  if (argument >= 'A' && argument <= 'Z')
-    return 2;
-  if (argument >= 'a' && argument <= 'z')
-    return 1;
-  return 0;
-}
-
-// isdigit
-STATIC
-int isdigit(int argument)
-{
-  if (argument >= '0' && argument <= '9')
-    return 1;
-  return 0;
-}
-
-// isalnum
-STATIC
-int isalnum(int argument)
-{
-  if (isdigit(argument) || isalpha(argument))
-    return 1;
-  return 0;
-}
-
-
-
-STATIC
-void* memcpy(void *dest, const void *src, size_t len)
-{
-   // Typecast src and dest addresses to (char *)
-   char *csrc = (char *)src;
-   char *cdest = (char *)dest;
-  
-   // Copy contents of src[] to dest[]
-   int i;
-   for (i=0; i<len; i++)
-       cdest[i] = csrc[i];
-}
-
-STATIC
-void* memmove(void* dest, const void* src, size_t n)
-{
-  unsigned char* from = (unsigned char*) src;
-  unsigned char* to = (unsigned char*) dest;
-
-  if (from == to || n == 0)
-    return dest;
-  if (to > from && to-from < (int)n) {
-    /* to overlaps with from */
-    /*  <from......>         */
-    /*         <to........>  */
-    /* copy in reverse, to avoid overwriting from */
-    int i;
-    for(i=n-1; i>=0; i--)
-      to[i] = from[i];
-    return dest;
-  }
-  if (from > to && from-to < (int)n) {
-    /* to overlaps with from */
-    /*        <from......>   */
-    /*  <to........>         */
-    /* copy forwards, to avoid overwriting from */
-    size_t i;
-    for(i=0; i<n; i++)
-      to[i] = from[i];
-    return dest;
-  }
-  memcpy(dest, src, n);
-  return dest;
-}
-
-// Function to implement `strcpy()` function
-STATIC
-char* strcpy(char* destination, const char* source)
-{
-    // return if no memory is allocated to the destination
-    if (destination == NULL) {
-        return NULL;
-    }
- 
-    // take a pointer pointing to the beginning of the destination string
-    char *ptr = destination;
- 
-    // copy the C-string pointed by source into the array
-    // pointed by destination
-    while (*source != '\0')
-    {
-        *destination = *source;
-        destination++;
-        source++;
-    }
- 
-    // include the terminating null character
-    *destination = '\0';
- 
-    // the destination is returned by standard `strcpy()`
-    return ptr;
-}
-
-
-STATIC
-size_t strlen(const char *str)
-{
-        const char *s;
-        for (s = str; *s; ++s);
-        return (s - str);
-}
-
-STATIC
-char* strcat (char *dest, const char *src)
-{
-  strcpy (dest + strlen (dest), src);
-  return dest;
-}
-
-STATIC
-char* strchr (const char *s, int c)
-{
-  do {
-    if (*s == c)
-      {
-        return (char*)s;
-      }
-  } while (*s++);
-  return (0);
-}
-
-
-STATIC
-int strcmp(const char* s1, const char* s2)
-{
-  while(*s1 && (*s1 == *s2))
-  {
-    s1++;
-    s2++;
-  }
-  return *(unsigned char*)s1 - *(unsigned char*)s2;
-}
-
-//STATIC
-
-int strncmp(const char * s1, const char * s2, size_t n )
-{
-  while ( n && *s1 && ( *s1 == *s2 ) )
-  {
-    ++s1;
-    ++s2;
-    --n;
-  }
-  if ( n == 0 )
-  {
-    return 0;
-  }
-  else
-  {
-    return ( *(unsigned char *)s1 - *(unsigned char *)s2 );
-  }
-}
-
-
-
-// all public prototypes
-STATIC
-unsigned truncUint(unsigned);
-STATIC
-int truncInt(int);
-
-STATIC
-int GetToken(void);
-STATIC
-char* GetTokenName(int token);
-
-
-STATIC
-void DumpMacroTable(void);
-
-
-STATIC
-int AddIdent(char* name);
-STATIC
-int FindIdent(char* name);
-
-STATIC
-void DumpIdentTable(void);
-
-STATIC
-char* lab2str(char* p, int n);
-
-STATIC
-void GenInit(void);
-STATIC
-void GenFin(void);
-STATIC
-int GenInitParams(int argc, char** argv, int* idx);
-STATIC
-void GenInitFinalize(void);
-STATIC
-void GenStartCommentLine(void);
-STATIC
-void GenWordAlignment(int bss);
-STATIC
-void GenLabel(char* Label, int Static);
-STATIC
-void GenNumLabel(int Label);
-STATIC
-void GenZeroData(unsigned Size, int bss);
-STATIC
-void GenIntData(int Size, int Val);
-STATIC
-void GenStartAsciiString(void);
-STATIC
-void GenAddrData(int Size, char* Label, int ofs);
-
-STATIC
-void GenJumpUncond(int Label);
-STATIC
-void GenJumpIfZero(int Label);
-STATIC
-void GenJumpIfNotZero(int Label);
-STATIC
-void GenJumpIfEqual(int val, int Label);
-
-STATIC
-void GenFxnProlog(void);
-STATIC
-void GenFxnEpilog(void);
-void GenIsrProlog(void);
-void GenIsrEpilog(void);
-
-STATIC
-int GenMaxLocalsSize(void);
-
-STATIC
-void GenDumpChar(int ch);
-STATIC
-void GenExpr(void);
-
-STATIC
-void PushSyntax(int t);
-STATIC
-void PushSyntax2(int t, int v);
-
-
-STATIC
-void DumpSynDecls(void);
-
-
-STATIC
-void push2(int v, int v2);
-STATIC
-void ins2(int pos, int v, int v2);
-STATIC
-void ins(int pos, int v);
-STATIC
-void del(int pos, int cnt);
-
-STATIC
-int TokenStartsDeclaration(int t, int params);
-STATIC
-int ParseDecl(int tok, unsigned structInfo[4], int cast, int label);
-
-STATIC
-void ShiftChar(void);
-STATIC
-int puts2(char*);
-STATIC
-int printf2(char*, ...);
-
-STATIC
-void error(char* format, ...);
-STATIC
-void warning(char* format, ...);
-STATIC
-void errorFile(char* n);
-STATIC
-void errorFileName(void);
-STATIC
-void errorInternal(int n);
-STATIC
-void errorChrStr(void);
-STATIC
-void errorStrLen(void);
-STATIC
-void errorUnexpectedToken(int tok);
-STATIC
-void errorDirective(void);
-STATIC
-void errorCtrlOutOfScope(void);
-STATIC
-void errorDecl(void);
-STATIC
-void errorVarSize(void);
-STATIC
-void errorInit(void);
-STATIC
-void errorUnexpectedVoid(void);
-STATIC
-void errorOpType(void);
-STATIC
-void errorNotLvalue(void);
-STATIC
-void errorNotConst(void);
-STATIC
-void errorLongExpr(void);
-
-STATIC
-int FindSymbol(char* s);
-STATIC
-int SymType(int SynPtr);
-STATIC
-int FindTaggedDecl(char* s, int start, int* CurScope);
-STATIC
-int GetDeclSize(int SyntaxPtr, int SizeForDeref);
-
-STATIC
-int ParseExpr(int tok, int* GotUnary, int* ExprTypeSynPtr, int* ConstExpr, int* ConstVal, int option, int option2);
-STATIC
-int GetFxnInfo(int ExprTypeSynPtr, int* MinParams, int* MaxParams, int* ReturnExprTypeSynPtr, int* FirstParamSynPtr);
-
-// all data
-
-int verbose = 0;
-int warnings = 0;
-int warnCnt = 0;
-
-// custom compiler flags
-int compileUserBDOS = 0;
-int compileOS = 0;
-
-// prep.c data
-
-// TBD!!! get rid of TokenIdentName[] and TokenValueString[]
-// and work with CharQueue[] directly
-int TokenValueInt = 0;
-char TokenIdentName[MAX_IDENT_LEN + 1];
-int TokenIdentNameLen = 0;
-char TokenValueString[MAX_STRING_LEN + 1];
-unsigned TokenStringLen = 0;
-unsigned TokenStringSize = 0; // TokenStringLen * sizeof(char/wchar_t)
-int LineNo = 1;
-int LinePos = 1;
-char CharQueue[MAX_CHAR_QUEUE_LEN];
-int CharQueueLen = 0;
-
-/*
-  Macro table entry format:
-    idlen char:     identifier length (<= 127)
-    id char[idlen]: identifier (ASCIIZ)
-    exlen char:     length of what the identifier expands into (<= 127)
-    ex char[exlen]: what the identifier expands into (ASCII)
-*/
-char MacroTable[MAX_MACRO_TABLE_LEN];
-int MacroTableLen = 0;
-
-/*
-  Identifier table entry format:
-    id char[idlen]: string (ASCIIZ)
-    idlen char:     string length (<= 127)
-*/
-char IdentTable[MAX_IDENT_TABLE_LEN];
-int IdentTableLen = 0;
-int DummyIdent; // corresponds to empty string
-
-#define MAX_GOTO_LABELS 16
-
-int gotoLabels[MAX_GOTO_LABELS][2];
-// gotoLabStat[]: bit 1 = used (by "goto label;"), bit 0 = defined (with "label:")
-char gotoLabStat[MAX_GOTO_LABELS];
-int gotoLabCnt = 0;
-
-#define MAX_CASES 128
-
-int Cases[MAX_CASES][2]; // [0] is case constant, [1] is case label number
-int CasesCnt = 0;
-
-// Data structures to support #include
-int FileCnt = 0;
-char FileNames[MAX_INCLUDES][MAX_FILE_NAME_LEN + 1];
-FILE* Files[MAX_INCLUDES];
-FILE* OutFile;
-char CharQueues[MAX_INCLUDES][3];
-int LineNos[MAX_INCLUDES];
-int LinePoss[MAX_INCLUDES];
-char SysSearchPaths[MAX_SEARCH_PATH];
-int SysSearchPathsLen = 0;
-char SearchPaths[MAX_SEARCH_PATH];
-int SearchPathsLen = 0;
-
-// Data structures to support #ifdef/#ifndef,#else,#endif
-int PrepDontSkipTokens = 1;
-int PrepStack[PREP_STACK_SIZE][2];
-int PrepSp = 0;
-
-
-// expr.c data
-
-int ExprLevel = 0;
-
-// TBD??? merge expression and operator stacks into one
-int stack[STACK_SIZE][2];
-int sp = 0;
-
-#define OPERATOR_STACK_SIZE STACK_SIZE
-int opstack[OPERATOR_STACK_SIZE][2];
-int opsp = 0;
-
-// smc.c data
-
-int OutputFormat = FormatSegmented;
-int GenExterns = 1;
-int UseBss = 1;
-
-// Names of C functions and variables are usually prefixed with an underscore.
-// One notable exception is the ELF format used by gcc in Linux.
-// Global C identifiers in the ELF format should not be predixed with an underscore.
-int UseLeadingUnderscores = 1;
-
-char* FileHeader = "";
-char* CodeHeaderFooter[2] = { "", "" };
-char* DataHeaderFooter[2] = { "", "" };
-char* RoDataHeaderFooter[2] = { "", "" };
-char* BssHeaderFooter[2] = { "", "" };
-char** CurHeaderFooter;
-
-int CharIsSigned = 1;
-int SizeOfWord = 2; // in chars (char can be a multiple of octets); ints and pointers are of word size
-int SizeOfWideChar = 2; // in chars/bytes, 2 or 4
-int WideCharIsSigned = 0; // 0 or 1
-int WideCharType1;
-int WideCharType2; // (un)signed counterpart of WideCharType1
-
-// TBD??? implement a function to allocate N labels with overflow checks
-int LabelCnt = 1; // label counter for jumps
-int StructCpyLabel = 0; // label of the function to copy structures/unions
-int StructPushLabel = 0; // label of the function to push structures/unions onto the stack
-
-// call stack (from higher to lower addresses):
-//   arg n
-//   ...
-//   arg 1
-//   return address
-//   saved xbp register
-//   local var 1
-//   ...
-//   local var n
-int CurFxnSyntaxPtr = 0;
-int CurFxnParamCntMin = 0;
-int CurFxnParamCntMax = 0;
-int CurFxnLocalOfs = 0; // negative
-int CurFxnMinLocalOfs = 0; // negative
-
-int CurFxnReturnExprTypeSynPtr = 0;
-int CurFxnEpilogLabel = 0;
-
-char* CurFxnName = NULL;
-int IsMain; // if inside main()
-
-int ParseLevel = 0; // Parse level/scope (file:0, fxn:1+)
-int ParamLevel = 0; // 1+ if parsing params, 0 otherwise
-
-unsigned char SyntaxStack0[SYNTAX_STACK_MAX];
-int SyntaxStack1[SYNTAX_STACK_MAX];
-int SyntaxStackCnt;
-
-// all code
-
-STATIC
-unsigned truncUint(unsigned n)
-{
-  // Truncate n to SizeOfWord * 8 bits
-  if (SizeOfWord == 2)
-    n &= ~(~0u << 8 << 8);
-  else if (SizeOfWord == 4)
-    n &= ~(~0u << 8 << 12 << 12);
-  return n;
-}
-
-STATIC
-int truncInt(int n)
-{
-  // Truncate n to SizeOfWord * 8 bits and then sign-extend it
-  unsigned un = n;
-  if (SizeOfWord == 2)
-  {
-    un &= ~(~0u << 8 << 8);
-    un |= (((un >> 8 >> 7) & 1) * ~0u) << 8 << 8;
-  }
-  else if (SizeOfWord == 4)
-  {
-    un &= ~(~0u << 8 << 12 << 12);
-    un |= (((un >> 8 >> 12 >> 11) & 1) * ~0u) << 8 << 12 << 12;
-  }
-  return (int)un;
-}
-
-// prep.c code
-
-STATIC
-int FindMacro(char* name)
-{
-  int i;
-
-  for (i = 0; i < MacroTableLen; )
-  {
-    if (!strcmp(MacroTable + i + 1, name))
-      return i + 1 + MacroTable[i];
-
-    i = i + 1 + MacroTable[i]; // skip id
-    i = i + 1 + MacroTable[i]; // skip ex
-  }
-
-  return -1;
-}
-
-STATIC
-int UndefineMacro(char* name)
-{
-  int i;
-
-  for (i = 0; i < MacroTableLen; )
-  {
-    if (!strcmp(MacroTable + i + 1, name))
-    {
-      int len = 1 + MacroTable[i]; // id part len
-      len = len + 1 + MacroTable[i + len]; // + ex part len
-
-      memmove(MacroTable + i,
-              MacroTable + i + len,
-              MacroTableLen - i - len);
-      MacroTableLen -= len;
-
-      return 1;
-    }
-
-    i = i + 1 + MacroTable[i]; // skip id
-    i = i + 1 + MacroTable[i]; // skip ex
-  }
-
-  return 0;
-}
-
-STATIC
-void AddMacroIdent(char* name)
-{
-  int l = strlen(name);
-
-  if (l >= 127)
-    error("Macro identifier too long '%s'\n", name);
-
-  if (MAX_MACRO_TABLE_LEN - MacroTableLen < l + 3)
-    error("Macro table exhausted\n");
-
-  MacroTable[MacroTableLen++] = l + 1; // idlen
-  strcpy(MacroTable + MacroTableLen, name);
-  MacroTableLen += l + 1;
-
-  MacroTable[MacroTableLen] = 0; // exlen
-}
-
-STATIC
-void AddMacroExpansionChar(char e)
-{
-  if (e == '\0')
-  {
-    // finalize macro definition entry
-    // remove trailing space first
-    while (MacroTable[MacroTableLen] &&
-           strchr(" \t", MacroTable[MacroTableLen + MacroTable[MacroTableLen]]))
-      MacroTable[MacroTableLen]--;
-    MacroTableLen += 1 + MacroTable[MacroTableLen];
-    return;
-  }
-
-  if (MacroTableLen + 1 + MacroTable[MacroTableLen] >= MAX_MACRO_TABLE_LEN)
-    error("Macro table exhausted\n");
-
-  if (MacroTable[MacroTableLen] >= 127)
-    error("Macro definition too long\n");
-
-  MacroTable[MacroTableLen + 1 + MacroTable[MacroTableLen]] = e;
-  MacroTable[MacroTableLen]++;
-}
-
-STATIC
-void DefineMacro(char* name, char* expansion)
-{
-  AddMacroIdent(name);
-  do
-  {
-    AddMacroExpansionChar(*expansion);
-  } while (*expansion++ != '\0');
-}
-
-STATIC
-void DumpMacroTable(void)
-{
-  int i, j;
-
-  puts2("");
-  GenStartCommentLine(); printf2("Macro table:\n");
-  for (i = 0; i < MacroTableLen; )
-  {
-    GenStartCommentLine(); printf2("Macro %s = ", MacroTable + i + 1);
-    i = i + 1 + MacroTable[i]; // skip id
-    printf2("`");
-    j = MacroTable[i++];
-    while (j--)
-      printf2("%c", MacroTable[i++]);
-    printf2("`\n");
-  }
-  GenStartCommentLine(); printf2("Bytes used: %d/%d\n\n", MacroTableLen, MAX_MACRO_TABLE_LEN);
-}
-
-STATIC
-int FindIdent(char* name)
-{
-  int i;
-  for (i = IdentTableLen; i > 0; )
-  {
-    i -= 1 + IdentTable[i - 1];
-    if (!strcmp(IdentTable + i, name))
-      return i;
-  }
-  return -1;
-}
-
-STATIC
-int AddIdent(char* name)
-{
-  int i, len;
-
-  if ((i = FindIdent(name)) >= 0)
-    return i;
-
-  i = IdentTableLen;
-  len = strlen(name);
-
-  if (len >= 127)
-    error("Identifier too long\n");
-
-  if (MAX_IDENT_TABLE_LEN - IdentTableLen < len + 2)
-    error("Identifier table exhausted\n");
-
-  strcpy(IdentTable + IdentTableLen, name);
-  IdentTableLen += len + 1;
-  IdentTable[IdentTableLen++] = len + 1;
-
-  return i;
-}
-
-STATIC
-int AddNumericIdent(int n)
-{
-  char s[1 + (2 + CHAR_BIT * sizeof n) / 3];
-  char *p = s + sizeof s;
-  *--p = '\0';
-  p = lab2str(p, n);
-  return AddIdent(p);
-}
-
-STATIC
-int AddGotoLabel(char* name, int label)
-{
-  int i;
-  for (i = 0; i < gotoLabCnt; i++)
-  {
-    if (!strcmp(IdentTable + gotoLabels[i][0], name))
-    {
-      if (gotoLabStat[i] & label)
-        error("Redefinition of label '%s'\n", name);
-      gotoLabStat[i] |= 2*!label + label;
-      return gotoLabels[i][1];
-    }
-  }
-  if (gotoLabCnt >= MAX_GOTO_LABELS)
-    error("Goto table exhausted\n");
-  gotoLabels[gotoLabCnt][0] = AddIdent(name);
-  gotoLabels[gotoLabCnt][1] = LabelCnt++;
-  gotoLabStat[gotoLabCnt] = 2*!label + label;
-  return gotoLabels[gotoLabCnt++][1];
-}
-
-STATIC
-void UndoNonLabelIdents(int len)
-{
-  int i;
-  IdentTableLen = len;
-  for (i = 0; i < gotoLabCnt; i++)
-    if (gotoLabels[i][0] >= len)
-    {
-      char* pfrom = IdentTable + gotoLabels[i][0];
-      char* pto = IdentTable + IdentTableLen;
-      int l = strlen(pfrom) + 2;
-      memmove(pto, pfrom, l);
-      IdentTableLen += l;
-      gotoLabels[i][0] = pto - IdentTable;
-    }
-}
-
-STATIC
-void AddCase(int val, int label)
-{
-  if (CasesCnt >= MAX_CASES)
-    error("Case table exhausted\n");
-
-  Cases[CasesCnt][0] = val;
-  Cases[CasesCnt++][1] = label;
-}
-
-STATIC
-void DumpIdentTable(void)
-{
-  int i;
-  puts2("");
-  GenStartCommentLine(); printf2("Identifier table:\n");
-  for (i = 0; i < IdentTableLen; )
-  {
-    GenStartCommentLine(); printf2("Ident %s\n", IdentTable + i);
-    i += strlen(IdentTable + i) + 2;
-  }
-  GenStartCommentLine(); printf2("Bytes used: %d/%d\n\n", IdentTableLen, MAX_IDENT_TABLE_LEN);
-}
-
-char* rws[] =
-{
-  "break", "case", "char", "continue", "default", "do", "else",
-  "extern", "for", "if", "int", "return", "signed", "sizeof",
-  "static", "switch", "unsigned", "void", "while", "asm", "auto",
-  "const", "double", "enum", "float", "goto", "inline", "long",
-  "register", "restrict", "short", "struct", "typedef", "union",
-  "volatile", "_Bool", "_Complex", "_Imaginary",
-  "__interrupt"
-};
-
-unsigned char rwtk[] =
-{
-  tokBreak, tokCase, tokChar, tokCont, tokDefault, tokDo, tokElse,
-  tokExtern, tokFor, tokIf, tokInt, tokReturn, tokSigned, tokSizeof,
-  tokStatic, tokSwitch, tokUnsigned, tokVoid, tokWhile, tok_Asm, tokAuto,
-  tokConst, tokDouble, tokEnum, tokFloat, tokGoto, tokInline, tokLong,
-  tokRegister, tokRestrict, tokShort, tokStruct, tokTypedef, tokUnion,
-  tokVolatile, tok_Bool, tok_Complex, tok_Imagin,
-  tokIntr
-};
-
-STATIC
-int GetTokenByWord(char* word)
-{
-  unsigned i;
-
-  for (i = 0; i < division(sizeof rws, sizeof rws[0]); i++)
-    if (!strcmp(rws[i], word))
-      return rwtk[i];
-
-  return tokIdent;
-}
-
-unsigned char tktk[] =
-{
-  tokEof,
-  // Single-character operators and punctuators:
-  '+', '-', '~', '*', '/', '%', '&', '|', '^', '!',
-  '<', '>', '(', ')', '[', ']',
-  '{', '}', '=', ',', ';', ':', '.', '?',
-  // Multi-character operators and punctuators:
-  tokLShift, tokLogAnd, tokEQ, tokLEQ, tokInc, tokArrow, tokAssignMul,
-  tokAssignMod, tokAssignSub, tokAssignRSh, tokAssignXor,
-  tokRShift, tokLogOr, tokNEQ, tokGEQ, tokDec, tokEllipsis,
-  tokAssignDiv, tokAssignAdd, tokAssignLSh, tokAssignAnd, tokAssignOr,
-  // Some of the above tokens get converted into these in the process:
-  tokUnaryAnd, tokUnaryPlus, tokPostInc, tokPostAdd,
-  tokULess, tokULEQ, tokURShift, tokUDiv, tokUMod, tokComma,
-  tokUnaryStar, tokUnaryMinus, tokPostDec, tokPostSub,
-  tokUGreater, tokUGEQ, tokAssignURSh, tokAssignUDiv, tokAssignUMod,
-  // Helper (pseudo-)tokens:
-  tokNumInt, tokLitStr, tokLocalOfs, tokNumUint, tokIdent, tokShortCirc,
-  tokSChar, tokShort, tokLong, tokUChar, tokUShort, tokULong, tokNumFloat,
-  tokNumCharWide, tokLitStrWide
-};
-
-char* tks[] =
-{
-  "<EOF>",
-  // Single-character operators and punctuators:
-  "+", "-", "~", "*", "/", "%", "&", "|", "^", "!",
-  "<", ">", "(", ")", "[", "]",
-  "{", "}", "=", ",", ";", ":", ".", "?",
-  // Multi-character operators and punctuators:
-  "<<", "&&", "==", "<=", "++", "->", "*=",
-  "%=", "-=", ">>=", "^=",
-  ">>", "||", "!=", ">=", "--", "...",
-  "/=", "+=", "<<=", "&=", "|=",
-  // Some of the above tokens get converted into these in the process:
-  "&u", "+u", "++p", "+=p",
-  "<u", "<=u", ">>u", "/u", "%u", ",b",
-  "*u", "-u", "--p", "-=p",
-  ">u", ">=u", ">>=u", "/=u", "%=u",
-  // Helper (pseudo-)tokens:
-  "<NumInt>",  "<LitStr>", "<LocalOfs>", "<NumUint>", "<Ident>", "<ShortCirc>",
-  "signed char", "short", "long", "unsigned char", "unsigned short", "unsigned long", "float",
-  "<NumCharWide>", "<LitStrWide>"
-};
-
-STATIC
-char* GetTokenName(int token)
-{
-  unsigned i;
-
-/* +-~* /% &|^! << >> && || < <= > >= == !=  () *[] ++ -- = += -= ~= *= /= %= &= |= ^= <<= >>= {} ,;: -> ... */
-
-  // Tokens other than reserved keywords:
-  for (i = 0; i < division(sizeof tktk , sizeof tktk[0]); i++)
-    if (tktk[i] == token)
-      return tks[i];
-
-  // Reserved keywords:
-  for (i = 0; i < division(sizeof rws , sizeof rws[0]); i++)
-    if (rwtk[i] == token)
-      return rws[i];
-
-  //error("Internal Error: GetTokenName(): Invalid token %d\n", token);
-  errorInternal(1);
-  return "";
-}
-
-STATIC
-int GetNextChar(void)
-{
-  int ch = EOF;
-
-  if (FileCnt && Files[FileCnt - 1])
-  {
-    if ((ch = fgetc(Files[FileCnt - 1])) == EOF)
-    {
-      fclose(Files[FileCnt - 1]);
-      Files[FileCnt - 1] = NULL;
-
-      // store the last line/pos, they may still be needed later
-      LineNos[FileCnt - 1] = LineNo;
-      LinePoss[FileCnt - 1] = LinePos;
-
-      // don't drop the file record just yet
-    }
-  }
-
-  return ch;
-}
-
-STATIC
-void ShiftChar(void)
-{
-  if (CharQueueLen)
-    memmove(CharQueue, CharQueue + 1, --CharQueueLen);
-
-  // make sure there always are at least 3 chars in the queue
-  while (CharQueueLen < 3)
-  {
-    int ch = GetNextChar();
-    if (ch == EOF)
-      ch = '\0';
-    CharQueue[CharQueueLen++] = ch;
-  }
-}
-
-STATIC
-void ShiftCharN(int n)
-{
-  while (n-- > 0)
-  {
-    ShiftChar();
-    LinePos++;
-  }
-}
-
-STATIC
-void IncludeFile(int quot)
-{
-  int nlen = strlen(TokenValueString);
-
-  if (CharQueueLen != 3)
-    //error("#include parsing error\n");
-    errorInternal(2);
-
-  if (FileCnt >= MAX_INCLUDES)
-    error("Too many include files\n");
-
-  // store the including file's position and buffered chars
-  LineNos[FileCnt - 1] = LineNo;
-  LinePoss[FileCnt - 1] = LinePos;
-  memcpy(CharQueues[FileCnt - 1], CharQueue, CharQueueLen);
-
-  // open the included file
-
-  if (nlen > MAX_FILE_NAME_LEN)
-    //error("File name too long\n");
-    errorFileName();
-
-  // DONE: differentiate between quot == '"' and quot == '<'
-
-  // First, try opening "file" in the current directory
-  // (Open Watcom C/C++ 1.9, Turbo C++ 1.01 use the current directory,
-  // unlike gcc, which uses the same directory as the current file)
-  if (quot == '"')
-  {
-    // Get path from c file to compile, so it can be appended to the include paths
-    char cFileDir[255] = "";
-    strcpy(cFileDir, FileNames[0]);
-
-    int len = strlen(cFileDir);  
-    while (len > 0) 
-    {
-       len--;
-       if (cFileDir[len] == '/') 
-       {
-          cFileDir[len+1] = '\0'; // keep the slash
-          break;
-       }
-    }
-    if (len == 0) // remove directory if there is none
-    {
-      cFileDir[0] = '\0';
-    }
-    strcpy(FileNames[FileCnt], TokenValueString);
-    strcat(cFileDir, FileNames[FileCnt]);
-    Files[FileCnt] = fopen(cFileDir, "r");
-  }
-
-  // Next, iterate the search paths trying to open "file" or <file>.
-  // "file" is first searched using the list provided by the -I option.
-  // "file" is then searched using the list provided by the -SI option.
-  // <file> is searched using the list provided by the -SI option.
-  if (Files[FileCnt] == NULL)
-  {
-    int i;
-    char *paths = SearchPaths;
-    int pl = SearchPathsLen;
-    for (;;)
-    {
-      if (quot == '<')
-      {
-        paths = SysSearchPaths;
-        pl = SysSearchPathsLen;
-      }
-      for (i = 0; i < pl; )
-      {
-        int plen = strlen(paths + i);
-        if (plen + 1 + nlen < MAX_FILE_NAME_LEN)
-        {
-          strcpy(FileNames[FileCnt], paths + i);
-          strcpy(FileNames[FileCnt] + plen + 1, TokenValueString);
-          // Use '/' as a separator, typical for Linux/Unix,
-          // but also supported by file APIs in DOS/Windows just as '\\'
-          FileNames[FileCnt][plen] = '/';
-          if ((Files[FileCnt] = fopen(FileNames[FileCnt], "r")) != NULL)
-            break;
-        }
-        i += plen + 1;
-      }
-      if (Files[FileCnt] || quot == '<')
-        break;
-      quot = '<';
-    }
-  }
-
-  if (Files[FileCnt] == NULL)
-  {
-    //error("Cannot open file \"%s\"\n", TokenValueString);
-    errorFile(TokenValueString);
-  }
-
-  // reset line/pos and empty the char queue
-  CharQueueLen = 0;
-  LineNo = LinePos = 1;
-  FileCnt++;
-
-  // fill the char queue with file data
-  ShiftChar();
-}
-
-STATIC
-int EndOfFiles(void)
-{
-  // if there are no including files, we're done
-  if (!--FileCnt)
-    return 1;
-
-  // restore the including file's position and buffered chars
-  LineNo = LineNos[FileCnt - 1];
-  LinePos = LinePoss[FileCnt - 1];
-  CharQueueLen = 3;
-  memcpy(CharQueue, CharQueues[FileCnt - 1], CharQueueLen);
-
-  return 0;
-}
-
-STATIC
-void SkipSpace(int SkipNewLines)
-{
-  char* p = CharQueue;
-
-  while (*p != '\0')
-  {
-    if (strchr(" \t\f\v", *p))
-    {
-      ShiftCharN(1);
-      continue;
-    }
-
-    if (strchr("\r\n", *p))
-    {
-      if (!SkipNewLines)
-        return;
-
-      if (*p == '\r' && p[1] == '\n')
-        ShiftChar();
-
-      ShiftChar();
-      LineNo++;
-      LinePos = 1;
-      continue;
-    }
-
-    if (*p == '/')
-    {
-      if (p[1] == '/')
-      {
-        // // comment
-        ShiftCharN(2);
-        while (!strchr("\r\n", *p))
-          ShiftCharN(1);
-        continue;
-      }
-      else if (p[1] == '*')
-      {
-        // /**/ comment
-        ShiftCharN(2);
-        while (*p != '\0' && !(*p == '*' && p[1] == '/'))
-        {
-          if (strchr("\r\n", *p))
-          {
-            if (!SkipNewLines)
-              error("Invalid comment\n");
-
-            if (*p == '\r' && p[1] == '\n')
-              ShiftChar();
-
-            ShiftChar();
-            LineNo++;
-            LinePos = 1;
-          }
-          else
-          {
-            ShiftCharN(1);
-          }
-        }
-        if (*p == '\0')
-          error("Invalid comment\n");
-        ShiftCharN(2);
-        continue;
-      }
-    } // endof if (*p == '/')
-
-    break;
-  } // endof while (*p != '\0')
-}
-
-STATIC
-void SkipLine(void)
-{
-  char* p = CharQueue;
-
-  while (*p != '\0')
-  {
-    if (strchr("\r\n", *p))
-    {
-      if (*p == '\r' && p[1] == '\n')
-        ShiftChar();
-
-      ShiftChar();
-      LineNo++;
-      LinePos = 1;
-      break;
-    }
-    else
-    {
-      ShiftCharN(1);
-    }
-  }
-}
-
-STATIC
-void GetIdent(void)
-{
-  char* p = CharQueue;
-
-  if (*p != '_' && !isalpha(*p & 0xFFu))
-    error("Identifier expected\n");
-
-  TokenIdentNameLen = 0;
-  TokenIdentName[TokenIdentNameLen++] = *p;
-  TokenIdentName[TokenIdentNameLen] = '\0';
-  ShiftCharN(1);
-
-  while (*p == '_' || isalnum(*p & 0xFFu))
-  {
-    if (TokenIdentNameLen == MAX_IDENT_LEN)
-      error("Identifier too long '%s'\n", TokenIdentName);
-    TokenIdentName[TokenIdentNameLen++] = *p;
-    TokenIdentName[TokenIdentNameLen] = '\0';
-    ShiftCharN(1);
-  }
-}
-
-STATIC
-unsigned GetCharValue(int wide)
-{
-  char* p = CharQueue;
-  unsigned ch = 0;
-  int cnt = 0;
-  if (*p == '\\')
-  {
-    ShiftCharN(1);
-    if (strchr("\n\r", *p))
-      goto lerr;
-    if (*p == 'x')
-    {
-      // hexadecimal character codes \xN+
-      // hexadecimal escape sequence is not limited in length per se
-      // (may have many leading zeroes)
-      static char digs[] = "0123456789ABCDEFabcdef";
-      static char vals[] =
-      {
-        0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
-        10, 11, 12, 13, 14, 15,
-        10, 11, 12, 13, 14, 15
-      };
-      char* pp;
-      int zeroes = 0;
-      ShiftCharN(1);
-      if (strchr("\n\r", *p))
-        goto lerr;
-      if (*p == '0')
-      {
-        do
-        {
-          ShiftCharN(1);
-        } while (*p == '0');
-        zeroes = 1;
-      }
-      while (*p && (pp = strchr(digs, *p)) != NULL)
-      {
-        ch <<= 4;
-        ch |= vals[pp - digs];
-        ShiftCharN(1);
-        if (++cnt > 2)
-        {
-          if (PrepDontSkipTokens)
-            goto lerr;
-        }
-      }
-      if (zeroes + cnt == 0)
-        goto lerr;
-    }
-    else if (*p >= '0' && *p <= '7')
-    {
-      // octal character codes \N+
-      // octal escape sequence is terminated after three octal digits
-      do
-      {
-        ch <<= 3;
-        ch |= *p - '0';
-        ShiftCharN(1);
-        ++cnt;
-      } while (*p >= '0' && *p <= '7' && cnt < 3);
-      if (ch >> 8)
-        goto lerr;
-    }
-    else
-    {
-      switch (*p)
-      {
-      case 'a': ch = '\a'; ShiftCharN(1); break;
-      case 'b': ch = '\b'; ShiftCharN(1); break;
-      case 'f': ch = '\f'; ShiftCharN(1); break;
-      case 'n': ch = '\n'; ShiftCharN(1); break;
-      case 'r': ch = '\r'; ShiftCharN(1); break;
-      case 't': ch = '\t'; ShiftCharN(1); break;
-      case 'v': ch = '\v'; ShiftCharN(1); break;
-      default:
-        goto lself;
-      }
-    }
-  }
-  else
-  {
-lself:
-    if (strchr("\n\r", *p))
-    {
-lerr:
-      //error("Unsupported or invalid character/string constant\n");
-      errorChrStr();
-    }
-    ch = *p & 0xFFu;
-    ShiftCharN(1);
-  }
-  return ch;
-}
-
-STATIC
-void GetString(char terminator, int wide, int option)
-{
-  char* p = CharQueue;
-  unsigned ch = '\0';
-  unsigned chsz = 1;
-  int i;
-
-  TokenStringLen = 0;
-  TokenStringSize = 0;
-  TokenValueString[TokenStringLen] = '\0';
-
-  ShiftCharN(1);
-  while (!(*p == terminator || strchr("\n\r", *p)))
-  {
-    ch = GetCharValue(wide);
-    switch (option)
-    {
-    case '#': // string literal (with file name) for #line and #include
-      if (TokenStringLen == MAX_STRING_LEN)
-        errorStrLen();
-      TokenValueString[TokenStringLen++] = ch;
-      TokenValueString[TokenStringLen] = '\0';
-      TokenStringSize += chsz;
-      break;
-    case 'a': // string literal for asm()
-      printf2("%c", ch);
-      break;
-    case 'd': // string literal / array of char in expression or initializer
-      // Dump the char data to the appropriate data section
-      for (i = 0; i < chsz; i++)
-      {
-        GenDumpChar(ch & 0xFFu);
-        ch >>= 8;
-        TokenStringLen++; // GenDumpChar() expects it to grow, doesn't know about wchar_t
-      }
-      TokenStringLen -= chsz;
-      // fallthrough
-    default: // skipped string literal (we may still need the size)
-      if (TokenStringSize > UINT_MAX - chsz)
-        errorStrLen();
-      TokenStringSize += chsz;
-      TokenStringLen++;
-      break;
-    } // endof switch (option)
-  } // endof while (!(*p == '\0' || *p == terminator || strchr("\n\r", *p)))
-
-  if (*p != terminator)
-    //error("Unsupported or invalid character/string constant\n");
-    errorChrStr();
-
-  if (option == 'd')
-    GenDumpChar(-1);
-
-  ShiftCharN(1);
-
-  SkipSpace(option != '#');
-}
-
-STATIC
-void pushPrep(int NoSkip)
-{
-  if (PrepSp >= PREP_STACK_SIZE)
-    error("Too many #if(n)def's\n");
-  PrepStack[PrepSp][0] = PrepDontSkipTokens;
-  PrepStack[PrepSp++][1] = NoSkip;
-  PrepDontSkipTokens &= NoSkip;
-}
-
-STATIC
-int popPrep(void)
-{
-  if (PrepSp <= 0)
-    error("#else or #endif without #if(n)def\n");
-  PrepDontSkipTokens = PrepStack[--PrepSp][0];
-  return PrepStack[PrepSp][1];
-}
-
-
-STATIC
-int GetNumber(void)
-{
-  char* p = CharQueue;
-  int ch = *p;
-  int leadingZero = (ch == '0');
-  unsigned n = 0;
-  int type = 0;
-  int uSuffix = 0;
-  int lSuffix = 0;
-  char* eTooBig = "Constant too big\n";
-
-  // First, detect and handle hex constants. Octals can't be detected immediately
-  // because floating-point constants also may begin with the digit 0.
-
-  if (leadingZero && (p[1] == 'x' || p[1] == 'X'))
-  {
-    // this is a hex constant
-    int cnt = 0;
-    type = 'h';
-    ShiftCharN(1);
-    ShiftCharN(1);
-    while ((ch = *p) != '\0' && (isdigit(ch & 0xFFu) || strchr("abcdefABCDEF", ch)))
-    {
-      if (ch >= 'a') ch -= 'a' - 10;
-      else if (ch >= 'A') ch -= 'A' - 10;
-      else ch -= '0';
-      //if (PrepDontSkipTokens && (n * 16 / 16 != n || n * 16 + ch < n * 16))
-      //  error(eTooBig);
-      n = n * 16 + ch;
-      ShiftCharN(1);
-      cnt++;
-    }
-    if (!cnt)
-      error("Invalid hexadecimal constant\n");
-  }
-  else
-  {
-    // handle decimal and octal integers
-    int base = leadingZero ? 8 : 10;
-    type = leadingZero ? 'o' : 'd';
-    while ((ch = *p) >= '0' && ch < base + '0')
-    {
-      ch -= '0';
-      if (PrepDontSkipTokens && (n * base + ch < n * base)) //n * base / base != n || 
-        error(eTooBig);
-      n = n * base + ch;
-      ShiftCharN(1);
-    }
-  }
-
-  // possible combinations of integer suffixes:
-  //   none
-  //   U
-  //   UL
-  //   L
-  //   LU
-  {
-    if ((ch = *p) == 'u' || ch == 'U')
-    {
-      uSuffix = 1;
-      ShiftCharN(1);
-    }
-    if ((ch = *p) == 'l' || ch == 'L')
-    {
-      lSuffix = 1;
-      ShiftCharN(1);
-      if (!uSuffix && ((ch = *p) == 'u' || ch == 'U'))
-      {
-        uSuffix = 1;
-        ShiftCharN(1);
-      }
-    }
-  }
-
-  if (!PrepDontSkipTokens)
-  {
-    // Don't fail on big constants when skipping tokens under #if
-    TokenValueInt = 0;
-    return tokNumInt;
-  }
-
-
-  // Ensure the constant fits into 16(32) bits
-  if (
-      (SizeOfWord == 2 && n >> 8 >> 8) // equiv. to SizeOfWord == 2 && n > 0xFFFF
-      || (SizeOfWord == 2 && lSuffix) // long (which must have at least 32 bits) isn't supported in 16-bit models
-      || (SizeOfWord == 4 && n >> 8 >> 12 >> 12) // equiv. to SizeOfWord == 4 && n > 0xFFFFFFFF
-     )
-    error("Constant too big for %d-bit type\n", SizeOfWord * 8);
-
-  TokenValueInt = (int)n;
-
-  // Unsuffixed (with 'u') integer constants (octal, decimal, hex)
-  // fitting into 15(31) out of 16(32) bits are signed ints
-  if (!uSuffix &&
-      (
-       (SizeOfWord == 2 && !(n >> 15)) // equiv. to SizeOfWord == 2 && n <= 0x7FFF
-       || (SizeOfWord == 4 && !(n >> 8 >> 12 >> 11)) // equiv. to SizeOfWord == 4 && n <= 0x7FFFFFFF
-      )
-     )
-    return tokNumInt;
-
-  // Unlike octal and hex constants, decimal constants are always
-  // a signed type. Error out when a decimal constant doesn't fit
-  // into an int since currently there's no next bigger signed type
-  // (e.g. long) to use instead of int.
-  if (!uSuffix && type == 'd')
-    error("Constant too big for %d-bit signed type\n", SizeOfWord * 8);
-
-  return tokNumUint;
-}
-
-STATIC
-int GetTokenInner(void)
-{
-  char* p = CharQueue;
-  int ch = *p;
-  int wide = 0;
-
-  // these single-character tokens/operators need no further processing
-  if (strchr(",;:()[]{}~?", ch))
-  {
-    ShiftCharN(1);
-    return ch;
-  }
-
-  // parse multi-character tokens/operators
-
-  // DONE: other assignment operators
-  switch (ch)
-  {
-  case '+':
-    if (p[1] == '+') { ShiftCharN(2); return tokInc; }
-    if (p[1] == '=') { ShiftCharN(2); return tokAssignAdd; }
-    ShiftCharN(1); return ch;
-  case '-':
-    if (p[1] == '-') { ShiftCharN(2); return tokDec; }
-    if (p[1] == '=') { ShiftCharN(2); return tokAssignSub; }
-    if (p[1] == '>') { ShiftCharN(2); return tokArrow; }
-    ShiftCharN(1); return ch;
-  case '!':
-    if (p[1] == '=') { ShiftCharN(2); return tokNEQ; }
-    ShiftCharN(1); return ch;
-  case '=':
-    if (p[1] == '=') { ShiftCharN(2); return tokEQ; }
-    ShiftCharN(1); return ch;
-  case '<':
-    if (p[1] == '=') { ShiftCharN(2); return tokLEQ; }
-    if (p[1] == '<') { ShiftCharN(2); if (p[0] != '=') return tokLShift; ShiftCharN(1); return tokAssignLSh; }
-    ShiftCharN(1); return ch;
-  case '>':
-    if (p[1] == '=') { ShiftCharN(2); return tokGEQ; }
-    if (p[1] == '>') { ShiftCharN(2); if (p[0] != '=') return tokRShift; ShiftCharN(1); return tokAssignRSh; }
-    ShiftCharN(1); return ch;
-  case '&':
-    if (p[1] == '&') { ShiftCharN(2); return tokLogAnd; }
-    if (p[1] == '=') { ShiftCharN(2); return tokAssignAnd; }
-    ShiftCharN(1); return ch;
-  case '|':
-    if (p[1] == '|') { ShiftCharN(2); return tokLogOr; }
-    if (p[1] == '=') { ShiftCharN(2); return tokAssignOr; }
-    ShiftCharN(1); return ch;
-  case '^':
-    if (p[1] == '=') { ShiftCharN(2); return tokAssignXor; }
-    ShiftCharN(1); return ch;
-  case '.':
-    if (p[1] == '.' && p[2] == '.') { ShiftCharN(3); return tokEllipsis; }
-    ShiftCharN(1); return ch;
-  case '*':
-    if (p[1] == '=') { ShiftCharN(2); return tokAssignMul; }
-    ShiftCharN(1); return ch;
-  case '%':
-    if (p[1] == '=') { ShiftCharN(2); return tokAssignMod; }
-    ShiftCharN(1); return ch;
-  case '/':
-    if (p[1] == '=') { ShiftCharN(2); return tokAssignDiv; }
-    ShiftCharN(1); return ch;
-  }
-
-  // DONE: hex and octal constants
-  if (isdigit(ch & 0xFFu))
-    return GetNumber();
-
-  // parse character and string constants
-  if (ch == '\'')
-  {
-    unsigned v = 0;
-    int cnt = 0;
-    int max_cnt = SizeOfWord;
-    ShiftCharN(1);
-    if (strchr("'\n\r", *p))
-      //error("Character constant too short\n");
-      errorChrStr();
-    do
-    {
-      v <<= 8;
-      v |= GetCharValue(wide);
-      if (++cnt > max_cnt)
-        //error("Character constant too long\n");
-        errorChrStr();
-    } while (!strchr("'\n\r", *p));
-    if (*p != '\'')
-      //error("Unsupported or invalid character/string constant\n");
-      errorChrStr();
-    ShiftCharN(1);
-    {
-      if (cnt == 1)
-      {
-        TokenValueInt = v;
-        TokenValueInt -= (CharIsSigned && TokenValueInt >= 0x80) * 0x100;
-      }
-      else
-      {
-        TokenValueInt = v;
-        TokenValueInt -= (SizeOfWord == 2 && TokenValueInt >= 0x8000) * 0x10000;
-      }
-      return tokNumInt;
-    }
-  }
-  else if (ch == '"')
-  {
-    // The caller of GetTokenInner()/GetToken() will call GetString('"', wide, 'd')
-    // to complete string literal parsing and storing as appropriate
-
-    return tokLitStr;
-
-  }
-
-  return tokEof;
-}
-
-
-STATIC
-void Reserve4Expansion(char* name, int len)
-{
-  if (MAX_CHAR_QUEUE_LEN - CharQueueLen < len + 1)
-    error("Too long expansion of macro '%s'\n", name);
-
-  memmove(CharQueue + len + 1, CharQueue, CharQueueLen);
-
-  CharQueue[len] = ' '; // space to avoid concatenation
-
-  CharQueueLen += len + 1;
-}
-
-
-// TBD??? implement file I/O for input source code and output code (use fxn ptrs/wrappers to make librarization possible)
-// DONE: support string literals
-STATIC
-int GetToken(void)
-{
-  char* p = CharQueue;
-  int ch;
-  int tok;
-
-  for (;;)
-  {
-/* +-~* /% &|^! << >> && || < <= > >= == !=  () *[] ++ -- = += -= ~= *= /= %= &= |= ^= <<= >>= {} ,;: -> ... */
-
-    // skip white space and comments
-    SkipSpace(1);
-
-    if ((ch = *p) == '\0')
-    {
-      // done with the current file, drop its record,
-      // pick up the including files (if any) or terminate
-      if (EndOfFiles())
-        break;
-      continue;
-    }
-
-    if ((tok = GetTokenInner()) != tokEof)
-    {
-      if (PrepDontSkipTokens)
-        return tok;
-      if (tok == tokLitStr)
-        GetString('"', 0, 0);
-
-      continue;
-    }
-
-    // parse identifiers and reserved keywords
-    if (ch == '_' || isalpha(ch & 0xFFu))
-    {
-
-      int midx;
-
-
-      GetIdent();
-
-      if (!PrepDontSkipTokens)
-        continue;
-
-      tok = GetTokenByWord(TokenIdentName);
-
-
-      // TBD!!! think of expanding macros in the context of concatenating string literals,
-      // maybe factor out this piece of code
-      if (!strcmp(TokenIdentName, "__FILE__"))
-      {
-        char* p = FileNames[FileCnt - 1];
-        int len = strlen(p);
-        Reserve4Expansion(TokenIdentName, len + 2);
-        *CharQueue = '"';
-        memcpy(CharQueue + 1, p, len);
-        CharQueue[len + 1] = '"';
-        continue;
-      }
-      else if (!strcmp(TokenIdentName, "__LINE__"))
-      {
-        char s[(2 + CHAR_BIT * sizeof LineNo) / 3];
-        char *p = lab2str(s + sizeof s, LineNo);
-        int len = s + sizeof s - p;
-        Reserve4Expansion(TokenIdentName, len);
-        memcpy(CharQueue, p, len);
-        continue;
-      }
-      else if ((midx = FindMacro(TokenIdentName)) >= 0)
-      {
-        // this is a macro identifier, need to expand it
-        int len = MacroTable[midx];
-        Reserve4Expansion(TokenIdentName, len);
-        memcpy(CharQueue, MacroTable + midx + 1, len);
-        continue;
-      }
-
-
-      // treat keywords auto, const, register, restrict and volatile as white space for now
-      if ((tok == tokConst) | (tok == tokVolatile) |
-          (tok == tokAuto) | (tok == tokRegister) |
-          (tok == tokRestrict))
-        continue;
-
-      return tok;
-    } // endof if (ch == '_' || isalpha(ch))
-
-    // parse preprocessor directives
-    if (ch == '#')
-    {
-      int line = 0;
-
-      ShiftCharN(1);
-
-      // Skip space
-      SkipSpace(0);
-
-      // Allow # not followed by a directive
-      if (strchr("\r\n", *p))
-        continue;
-
-      // Get preprocessor directive
-      if (isdigit(*p & 0xFFu))
-      {
-        // gcc-style #line directive without "line"
-        line = 1;
-      }
-      else
-      {
-        GetIdent();
-        if (!strcmp(TokenIdentName, "line"))
-        {
-          // C89-style #line directive
-          SkipSpace(0);
-          if (!isdigit(*p & 0xFFu))
-            errorDirective();
-          line = 1;
-        }
-      }
-
-      if (line)
-      {
-        // Support for external, gcc-like, preprocessor output:
-        //   # linenum filename flags
-        //
-        // no flags, flag = 1 -- start of a file
-        //           flag = 2 -- return to a file after #include
-        //        other flags -- uninteresting
-
-        // DONE: should also support the following C89 form:
-        // # line linenum filename-opt
-
-        if (GetNumber() != tokNumInt)
-          //error("Invalid line number in preprocessor output\n");
-          errorDirective();
-        line = TokenValueInt;
-
-        SkipSpace(0);
-
-        if (*p == '"' || *p == '<')
-        {
-          if (*p == '"')
-            GetString('"', 0, '#');
-          else
-            GetString('>', 0, '#');
-
-          if (strlen(TokenValueString) > MAX_FILE_NAME_LEN)
-            //error("File name too long in preprocessor output\n");
-            errorFileName();
-          strcpy(FileNames[FileCnt - 1], TokenValueString);
-        }
-
-        // Ignore gcc-style #line's flags, if any
-        while (!strchr("\r\n", *p))
-          ShiftCharN(1);
-
-        LineNo = line - 1; // "line" is the number of the next line
-        LinePos = 1;
-
-        continue;
-      } // endof if (line)
-
-
-
-      if (!strcmp(TokenIdentName, "define"))
-      {
-        // Skip space and get macro name
-        SkipSpace(0);
-        GetIdent();
-
-        if (!PrepDontSkipTokens)
-        {
-          SkipSpace(0);
-          while (!strchr("\r\n", *p))
-            ShiftCharN(1);
-          continue;
-        }
-
-        if (FindMacro(TokenIdentName) >= 0)
-          error("Redefinition of macro '%s'\n", TokenIdentName);
-        if (*p == '(')
-          //error("Unsupported type of macro '%s'\n", TokenIdentName);
-          errorDirective();
-
-        AddMacroIdent(TokenIdentName);
-
-        SkipSpace(0);
-
-        // accumulate the macro expansion text
-        while (!strchr("\r\n", *p))
-        {
-          AddMacroExpansionChar(*p);
-          ShiftCharN(1);
-          if (*p != '\0' && (strchr(" \t", *p) || (*p == '/' && (p[1] == '/' || p[1] == '*'))))
-          {
-            SkipSpace(0);
-            AddMacroExpansionChar(' ');
-          }
-        }
-        AddMacroExpansionChar('\0');
-
-        continue;
-      }
-      else if (!strcmp(TokenIdentName, "undef"))
-      {
-        // Skip space and get macro name
-        SkipSpace(0);
-        GetIdent();
-
-        if (PrepDontSkipTokens)
-          UndefineMacro(TokenIdentName);
-
-        SkipSpace(0);
-        if (!strchr("\r\n", *p))
-          //error("Invalid preprocessor directive\n");
-          errorDirective();
-        continue;
-      }
-      else if (!strcmp(TokenIdentName, "include"))
-      {
-        int quot;
-
-        // Skip space and get file name
-        SkipSpace(0);
-
-        quot = *p;
-        if (*p == '"')
-          GetString('"', 0, '#');
-        else if (*p == '<')
-          GetString('>', 0, '#');
-        else
-          //error("Invalid file name\n");
-          errorFileName();
-
-        SkipSpace(0);
-        if (!strchr("\r\n", *p))
-          //error("Unsupported or invalid preprocessor directive\n");
-          errorDirective();
-
-        if (PrepDontSkipTokens)
-          IncludeFile(quot);
-
-        continue;
-      }
-      else if (!strcmp(TokenIdentName, "ifdef"))
-      {
-        int def;
-        // Skip space and get macro name
-        SkipSpace(0);
-        GetIdent();
-        def = FindMacro(TokenIdentName) >= 0;
-        SkipSpace(0);
-        if (!strchr("\r\n", *p))
-          //error("Invalid preprocessor directive\n");
-          errorDirective();
-        pushPrep(def);
-        continue;
-      }
-      else if (!strcmp(TokenIdentName, "ifndef"))
-      {
-        int def;
-        // Skip space and get macro name
-        SkipSpace(0);
-        GetIdent();
-        def = FindMacro(TokenIdentName) >= 0;
-        SkipSpace(0);
-        if (!strchr("\r\n", *p))
-          //error("Invalid preprocessor directive\n");
-          errorDirective();
-        pushPrep(!def);
-        continue;
-      }
-      else if (!strcmp(TokenIdentName, "else"))
-      {
-        int def;
-        SkipSpace(0);
-        if (!strchr("\r\n", *p))
-          //error("Invalid preprocessor directive\n");
-          errorDirective();
-        def = popPrep();
-        if (def >= 2)
-          error("#else or #endif without #if(n)def\n");
-        pushPrep(2 + !def); // #else works in opposite way to its preceding #if(n)def
-        continue;
-      }
-      else if (!strcmp(TokenIdentName, "endif"))
-      {
-        SkipSpace(0);
-        if (!strchr("\r\n", *p))
-          //error("Invalid preprocessor directive\n");
-          errorDirective();
-        popPrep();
-        continue;
-      }
-
-      if (!PrepDontSkipTokens)
-      {
-        // If skipping code and directives under #ifdef/#ifndef/#else,
-        // ignore unsupported directives #if, #elif, #error (no error checking)
-        if (!strcmp(TokenIdentName, "if"))
-          pushPrep(0);
-        else if (!strcmp(TokenIdentName, "elif"))
-          popPrep(), pushPrep(0);
-        SkipLine();
-        continue;
-      }
-
-      //error("Unsupported or invalid preprocessor directive\n");
-      errorDirective();
-    } // endof if (ch == '#')
-
-    error("Invalid or unsupported character with code 0x%02X\n", *p & 0xFFu);
-  } // endof for (;;)
-
-  return tokEof;
-}
-
-STATIC
-void errorRedecl(char* s)
-{
-  error("Invalid or unsupported redeclaration of '%s'\n", s);
-}
-
-
-#include "backend.c"
-
-// expr.c code
-
-STATIC
-void push2(int v, int v2)
-{
-  if (sp >= STACK_SIZE)
-    //error("expression stack overflow!\n");
-    errorLongExpr();
-  stack[sp][0] = v;
-  stack[sp++][1] = v2;
-}
-
-STATIC
-void push(int v)
-{
-  push2(v, 0);
-}
-
-STATIC
-int stacktop()
-{
-  if (sp == 0)
-    //error("expression stack underflow!\n");
-    errorInternal(3);
-  return stack[sp - 1][0];
-}
-
-STATIC
-int pop2(int* v2)
-{
-  int v = stacktop();
-  *v2 = stack[sp - 1][1];
-  sp--;
-  return v;
-}
-
-int pop()
-{
-  int v2;
-  return pop2(&v2);
-}
-
-STATIC
-void ins2(int pos, int v, int v2)
-{
-  if (sp >= STACK_SIZE)
-    //error("expression stack overflow!\n");
-    errorLongExpr();
-  memmove(&stack[pos + 1], &stack[pos], sizeof(stack[0]) * (sp - pos));
-  stack[pos][0] = v;
-  stack[pos][1] = v2;
-  sp++;
-}
-
-STATIC
-void ins(int pos, int v)
-{
-  ins2(pos, v, 0);
-}
-
-STATIC
-void del(int pos, int cnt)
-{
-  memmove(stack[pos],
-          stack[pos + cnt],
-          sizeof(stack[0]) * (sp - (pos + cnt)));
-  sp -= cnt;
-}
-
-
-STATIC
-void pushop2(int v, int v2)
-{
-  if (opsp >= OPERATOR_STACK_SIZE)
-    //error("operator stack overflow!\n");
-    errorLongExpr();
-  opstack[opsp][0] = v;
-  opstack[opsp++][1] = v2;
-}
-
-STATIC
-void pushop(int v)
-{
-  pushop2(v, 0);
-}
-
-STATIC
-int opstacktop()
-{
-  if (opsp == 0)
-    //error("operator stack underflow!\n");
-    errorInternal(4);
-  return opstack[opsp - 1][0];
-}
-
-STATIC
-int popop2(int* v2)
-{
-  int v = opstacktop();
-  *v2 = opstack[opsp - 1][1];
-  opsp--;
-  return v;
-}
-
-STATIC
-int popop()
-{
-  int v2;
-  return popop2(&v2);
-}
-
-STATIC
-int isop(int tok)
-{
-  static unsigned char toks[] =
-  {
-    '!',
-    '~',
-    '&',
-    '*',
-    '/', '%',
-    '+', '-',
-    '|', '^',
-    '<', '>',
-    '=',
-    tokLogOr, tokLogAnd,
-    tokEQ, tokNEQ,
-    tokLEQ, tokGEQ,
-    tokLShift, tokRShift,
-    tokInc, tokDec,
-    tokSizeof,
-    tokAssignMul, tokAssignDiv, tokAssignMod,
-    tokAssignAdd, tokAssignSub,
-    tokAssignLSh, tokAssignRSh,
-    tokAssignAnd, tokAssignXor, tokAssignOr,
-    tokComma,
-    '?'
-  };
-  unsigned i;
-  for (i = 0; i < division(sizeof toks , sizeof toks[0]); i++)
-    if (toks[i] == tok)
-      return 1;
-  return 0;
-}
-
-STATIC
-int isunary(int tok)
-{
-  return (tok == '!') | (tok == '~') | (tok == tokInc) | (tok == tokDec) | (tok == tokSizeof);
-}
-
-STATIC
-int preced(int tok)
-{
-  switch (tok)
-  {
-  case '*': case '/': case '%': return 13;
-  case '+': case '-': return 12;
-  case tokLShift: case tokRShift: return 11;
-  case '<': case '>': case tokLEQ: case tokGEQ: return 10;
-  case tokEQ: case tokNEQ: return 9;
-  case '&': return 8;
-  case '^': return 7;
-  case '|': return 6;
-  case tokLogAnd: return 5;
-  case tokLogOr: return 4;
-  case '?': case ':': return 3;
-  case '=':
-  case tokAssignMul: case tokAssignDiv: case tokAssignMod:
-  case tokAssignAdd: case tokAssignSub:
-  case tokAssignLSh: case tokAssignRSh:
-  case tokAssignAnd: case tokAssignXor: case tokAssignOr:
-    return 2;
-  case tokComma:
-    return 1;
-  }
-  return 0;
-}
-
-STATIC
-int precedGEQ(int lfttok, int rhttok)
-{
-  // DONE: rethink the comma operator as it could be implemented similarly
-  // DONE: is this correct:???
-  int pl = preced(lfttok);
-  int pr = preced(rhttok);
-  // ternary/conditional operator ?: is right-associative
-  if (pl == 3 && pr >= 3)
-    pl = 0;
-  // assignment is right-associative
-  if (pl == 2 && pr >= 2)
-    pl = 0;
-  return pl >= pr;
-}
-
-STATIC
-int expr(int tok, int* gotUnary, int commaSeparator);
-
-STATIC
-char* lab2str(char* p, int n)
-{
-  do
-  {
-    *--p = '0' + modulo(n , 10);
-    n = division(n, 10);
-  } while (n);
-
-  return p;
-}
-
-STATIC
-int exprUnary(int tok, int* gotUnary, int commaSeparator, int argOfSizeOf)
-{
-  static int sizeofLevel = 0;
-
-  int decl = 0;
-  *gotUnary = 0;
-
-  if (isop(tok) && (isunary(tok) || strchr("&*+-", tok)))
-  {
-    int lastTok = tok;
-    int sizeofLevelInc = lastTok == tokSizeof;
-
-    sizeofLevel += sizeofLevelInc;
-    tok = exprUnary(GetToken(), gotUnary, commaSeparator, sizeofLevelInc);
-    sizeofLevel -= sizeofLevelInc;
-
-    if (!*gotUnary)
-      //error("exprUnary(): primary expression expected after token %s\n", GetTokenName(lastTok));
-      errorUnexpectedToken(tok);
-    switch (lastTok)
-    {
-    // DONE: remove all collapsing of all unary operators.
-    // It's wrong because type checking must occur before any optimizations.
-    // WRONG: DONE: collapse alternating & and * (e.g. "*&*&x" "&*&*x")
-    // WRONGISH: DONE: replace prefix ++/-- with +=1/-=1
-    case '&':
-      push(tokUnaryAnd);
-      break;
-    case '*':
-      push(tokUnaryStar);
-      break;
-    case '+':
-      push(tokUnaryPlus);
-      break;
-    case '-':
-      push(tokUnaryMinus);
-      break;
-    case '!':
-      // replace "!" with "== 0"
-      push(tokNumInt);
-      push(tokEQ);
-      break;
-    default:
-      push(lastTok);
-      break;
-    }
-  }
-  else
-  {
-    int inspos = sp;
-
-    if (tok == tokNumInt ||
-
-
-        tok == tokNumUint)
-    {
-      push2(tok, TokenValueInt);
-      *gotUnary = 1;
-      tok = GetToken();
-    }
-    else if (tok == tokLitStr
-
-            )
-    {
-      int lbl = LabelCnt++;
-      int id;
-      int ltok = tok;
-
-      int wide = 0;
-      unsigned chsz = 1;
-
-      unsigned sz = chsz;
-
-      // imitate definition: char #[len] = "...";
-
-      if (!sizeofLevel)
-      {
-        if (CurHeaderFooter)
-          puts2(CurHeaderFooter[1]);
-        puts2(RoDataHeaderFooter[0]);
-
-
-        GenNumLabel(lbl);
-      }
-
-      do
-      {
-        GetString('"', wide, sizeofLevel ? 0 : 'd'); // throw away string data inside sizeof, e.g. sizeof "a" or sizeof("a" + 1)
-        if (sz + TokenStringSize < sz ||
-            sz + TokenStringSize >= truncUint(-1))
-          errorStrLen();
-        sz += TokenStringSize;
-        tok = GetToken();
-      } while (tok == ltok); // concatenate adjacent string literals
-
-
-
-      if (!sizeofLevel)
-      {
-        GenZeroData(chsz, 0);
-
-        puts2(RoDataHeaderFooter[1]);
-        if (CurHeaderFooter)
-          puts2(CurHeaderFooter[0]);
-      }
-
-      // DONE: can this break incomplete yet declarations???, e.g.: int x[sizeof("az")][5];
-      PushSyntax2(tokIdent, id = AddNumericIdent(lbl));
-      PushSyntax('[');
-      PushSyntax2(tokNumUint, division(sz, chsz));
-      PushSyntax(']');
-
-      PushSyntax(tokChar);
-
-      push2(tokIdent, id);
-      *gotUnary = 1;
-    }
-    else if (tok == tokIdent)
-    {
-      push2(tok, AddIdent(TokenIdentName));
-      *gotUnary = 1;
-      tok = GetToken();
-    }
-    else if (tok == '(')
-    {
-      tok = GetToken();
-      decl = TokenStartsDeclaration(tok, 1);
-
-      if (decl)
-      {
-        int synPtr;
-        int lbl = LabelCnt++;
-        char s[1 + (2 + CHAR_BIT * sizeof lbl) / 3 + sizeof "<something>" - 1];
-        char *p = s + sizeof s;
-
-        tok = ParseDecl(tok, NULL, !argOfSizeOf, 0);
-        if (tok != ')')
-          //error("exprUnary(): ')' expected, unexpected token %s\n", GetTokenName(tok));
-          errorUnexpectedToken(tok);
-        synPtr = FindSymbol("<something>");
-
-        // Rename "<something>" to "<something#>", where # is lbl.
-        // This makes the nameless declaration uniquely identifiable by name.
-
-        *--p = '\0';
-        *--p = ")>"[argOfSizeOf]; // differentiate casts (something#) from not casts <something#>
-
-        p = lab2str(p, lbl);
-
-        p -= sizeof "<something>" - 2 - 1;
-        memcpy(p, "something", sizeof "something" - 1);
-
-        *--p = "(<"[argOfSizeOf]; // differentiate casts (something#) from not casts <something#>
-
-        SyntaxStack1[synPtr] = AddIdent(p);
-        tok = GetToken();
-        if (argOfSizeOf)
-        {
-          // expression: sizeof(type)
-          *gotUnary = 1;
-        }
-        else
-        {
-          // unary type cast operator: (type)
-          decl = 0;
-          tok = exprUnary(tok, gotUnary, commaSeparator, 0);
-          if (!*gotUnary)
-            //error("exprUnary(): primary expression expected after '(type)'\n");
-            errorUnexpectedToken(tok);
-        }
-        push2(tokIdent, SyntaxStack1[synPtr]);
-      }
-      else
-      {
-        tok = expr(tok, gotUnary, 0);
-        if (tok != ')')
-          //error("exprUnary(): ')' expected, unexpected token %s\n", GetTokenName(tok));
-          errorUnexpectedToken(tok);
-        if (!*gotUnary)
-          //error("exprUnary(): primary expression expected in '()'\n");
-          errorUnexpectedToken(tok);
-        tok = GetToken();
-      }
-    }
-
-    while (*gotUnary && !decl)
-    {
-      // DONE: f(args1)(args2) and the like: need stack order: args2, args1, f, (), ()
-      // DONE: reverse the order of evaluation of groups of args in
-      //       f(args1)(args2)(args3)
-      // DONE: reverse the order of function argument evaluation for variadic functions
-      //       we want 1st arg to be the closest to the stack top.
-      // DONE: (args)[index] can be repeated interchangeably indefinitely
-      // DONE: (expr)() & (expr)[]
-      // DONE: [index] can be followed by ++/--, which can be followed by [index] and so on...
-      // DONE: postfix ++/-- & differentiate from prefix ++/--
-
-      if (tok == '(')
-      {
-        int acnt = 0;
-        ins(inspos, '(');
-        for (;;)
-        {
-          int pos2 = sp;
-
-          tok = GetToken();
-          tok = expr(tok, gotUnary, 1);
-
-          // Reverse the order of argument evaluation, which is important for
-          // variadic functions like printf():
-          // we want 1st arg to be the closest to the stack top.
-          // This also reverses the order of evaluation of all groups of
-          // arguments.
-          while (pos2 < sp)
-          {
-            // TBD??? not quite efficient
-            int v, v2;
-            v = pop2(&v2);
-            ins2(inspos + 1, v, v2);
-            pos2++;
-          }
-
-          if (tok == ',')
-          {
-            if (!*gotUnary)
-              //error("exprUnary(): primary expression (fxn argument) expected before ','\n");
-              errorUnexpectedToken(tok);
-            acnt++;
-            ins(inspos + 1, ','); // helper argument separator (hint for expression evaluator)
-            continue; // off to next arg
-          }
-          if (tok == ')')
-          {
-            if (acnt && !*gotUnary)
-              //error("exprUnary(): primary expression (fxn argument) expected between ',' and ')'\n");
-              errorUnexpectedToken(tok);
-            *gotUnary = 1; // don't fail for 0 args in ()
-            break; // end of args
-          }
-          // DONE: think of inserting special arg pseudo tokens for verification purposes
-          //error("exprUnary(): ',' or ')' expected, unexpected token %s\n", GetTokenName(tok));
-          errorUnexpectedToken(tok);
-        } // endof for(;;) for fxn args
-        push(')');
-      }
-      else if (tok == '[')
-      {
-        tok = GetToken();
-        tok = expr(tok, gotUnary, 0);
-        if (!*gotUnary)
-          //error("exprUnary(): primary expression expected in '[]'\n");
-          errorUnexpectedToken(tok);
-        if (tok != ']')
-          //error("exprUnary(): ']' expected, unexpected token %s\n", GetTokenName(tok));
-          errorUnexpectedToken(tok);
-        // TBD??? add implicit casts to size_t of array indicies.
-        // E1[E2] -> *(E1 + E2)
-        // push('[');
-        push('+');
-        push(tokUnaryStar);
-      }
-      // WRONG: DONE: replace postfix ++/-- with (+=1)-1/(-=1)+1
-      else if (tok == tokInc)
-      {
-        push(tokPostInc);
-      }
-      else if (tok == tokDec)
-      {
-        push(tokPostDec);
-      }
-      else if (tok == '.' || tok == tokArrow)
-      {
-        // transform a.b into (&a)->b
-        if (tok == '.')
-          push(tokUnaryAnd);
-        tok = GetToken();
-        if (tok != tokIdent)
-          errorUnexpectedToken(tok);
-        push2(tok, AddIdent(TokenIdentName));
-        // "->" in "a->b" will function as "+" in "*(type_of_b*)((char*)a + offset_of_b_in_a)"
-        push(tokArrow);
-        push(tokUnaryStar);
-      }
-      else
-      {
-        break;
-      }
-      tok = GetToken();
-    } // endof while (*gotUnary)
-  }
-
-  if (tok == ',' && !commaSeparator)
-    tok = tokComma;
-
-  return tok;
-}
-
-STATIC
-int expr(int tok, int* gotUnary, int commaSeparator)
-{
-  *gotUnary = 0;
-  pushop(tokEof);
-
-  tok = exprUnary(tok, gotUnary, commaSeparator, 0);
-
-  while (tok != tokEof && strchr(",;:)]}", tok) == NULL && *gotUnary)
-  {
-    if (isop(tok) && !isunary(tok))
-    {
-      while (precedGEQ(opstacktop(), tok))
-      {
-        int v, v2;
-        v = popop2(&v2);
-        // move ?expr: as a whole to the expression stack as "expr?"
-        if (v == '?')
-        {
-          int cnt = v2;
-          while (cnt--)
-          {
-            v = popop2(&v2);
-            push2(v, v2);
-          }
-          v = '?';
-          v2 = 0;
-        }
-        push2(v, v2);
-      }
-
-      // here: preced(postacktop()) < preced(tok)
-
-      // treat the ternary/conditional operator ?expr: as a pseudo binary operator
-      if (tok == '?')
-      {
-        int ssp = sp;
-        int cnt;
-
-        tok = expr(GetToken(), gotUnary, 0);
-        if (!*gotUnary || tok != ':')
-          errorUnexpectedToken(tok);
-
-        // move ?expr: as a whole to the operator stack
-        // this is beautiful and ugly at the same time
-        cnt = sp - ssp;
-        while (sp > ssp)
-        {
-          int v, v2;
-          v = pop2(&v2);
-          pushop2(v, v2);
-        }
-
-        // remember the length of the expression between ? and :
-        pushop2('?', cnt);
-      }
-      else
-      {
-        pushop(tok);
-      }
-
-      tok = exprUnary(GetToken(), gotUnary, commaSeparator, 0);
-      // DONE: figure out a check to see if exprUnary() fails to add a rhs operand
-      if (!*gotUnary)
-        //error("expr(): primary expression expected after token %s\n", GetTokenName(lastTok));
-        errorUnexpectedToken(tok);
-
-      continue;
-    }
-
-    //error("expr(): Unexpected token %s\n", GetTokenName(tok));
-    errorUnexpectedToken(tok);
-  }
-
-  while (opstacktop() != tokEof)
-  {
-    int v, v2;
-    v = popop2(&v2);
-    // move ?expr: as a whole to the expression stack as "expr?"
-    if (v == '?')
-    {
-      int cnt = v2;
-      while (cnt--)
-      {
-        v = popop2(&v2);
-        push2(v, v2);
-      }
-      v = '?';
-      v2 = 0;
-    }
-    push2(v, v2);
-  }
-
-  popop();
-  return tok;
-}
-
-STATIC
-int isAnyPtr(int ExprTypeSynPtr)
-{
-  if (ExprTypeSynPtr < 0)
-    return 1;
-  switch (SyntaxStack0[ExprTypeSynPtr])
-  {
-  case '*':
-  case '[':
-  case '(':
-    return 1;
-  }
-  return 0;
-}
-
-STATIC
-int derefAnyPtr(int ExprTypeSynPtr)
-{
-  if (ExprTypeSynPtr < 0)
-    return -ExprTypeSynPtr;
-  switch (SyntaxStack0[ExprTypeSynPtr])
-  {
-  case '*':
-    return ExprTypeSynPtr + 1;
-  case '[':
-    return ExprTypeSynPtr + 3;
-  case '(':
-    return ExprTypeSynPtr;
-  }
-  errorInternal(22);
-  return -1;
-}
-
-STATIC
-void decayArray(int* ExprTypeSynPtr, int arithmetic)
-{
-  // Dacay arrays to pointers to their first elements
-  if (*ExprTypeSynPtr >= 0 && SyntaxStack0[*ExprTypeSynPtr] == '[')
-  {
-    (*ExprTypeSynPtr) += 3;
-    // we cannot insert another '*' into the type to make it a pointer
-    // to the first element, so make the index into the type negative
-    *ExprTypeSynPtr = -*ExprTypeSynPtr;
-  }
-
-  // DONE: disallow arithmetic on pointers to void
-  // DONE: disallow function pointers
-  if (arithmetic && isAnyPtr(*ExprTypeSynPtr))
-  {
-    int pointee = derefAnyPtr(*ExprTypeSynPtr);
-    switch (SyntaxStack0[pointee])
-    {
-    case tokVoid:
-      //error("decayArray(): cannot do pointer arithmetic on a pointer to 'void'\n");
-      errorUnexpectedVoid();
-    default:
-      //error("decayArray(): cannot do pointer arithmetic on a pointer to an incomplete type\n");
-      if (!GetDeclSize(pointee, 0))
-      // "fallthrough"
-    case '(':
-        //error("decayArray(): cannot do pointer arithmetic on a pointer to a function\n");
-        errorOpType();
-    }
-  }
-}
-
-STATIC
-void lvalueCheck(int ExprTypeSynPtr, int pos)
-{
-  if (ExprTypeSynPtr >= 0 &&
-      (SyntaxStack0[ExprTypeSynPtr] == '[' || SyntaxStack0[ExprTypeSynPtr] == '('))
-  {
-    // we can have arrays formed by dereference, e.g.
-    //   char (*pac)[1]; // *pac is array of 1 char
-    //                   // ++*pac or (*pac)-- are not allowed
-    // and likewise functions, e.g.
-    //   int (*pf)(int); // *pf is a function taking int and returning int
-    //                   // *pf = 0; is not allowed
-    // and that dereference shouldn't be confused for lvalue,
-    // hence explicitly checking for array and function types
-    //error("exprval(): lvalue expected\n");
-    errorNotLvalue();
-  }
-  // lvalue is a dereferenced address, check for a dereference
-  if (stack[pos][0] != tokUnaryStar)
-    //error("exprval(): lvalue expected\n");
-    errorNotLvalue();
-}
-
-STATIC
-void nonVoidTypeCheck(int ExprTypeSynPtr)
-{
-  if (ExprTypeSynPtr >= 0 && SyntaxStack0[ExprTypeSynPtr] == tokVoid)
-    //error("nonVoidTypeCheck(): unexpected operand type 'void' for operator '%s'\n", GetTokenName(tok));
-    errorUnexpectedVoid();
-}
-
-STATIC
-void scalarTypeCheck(int ExprTypeSynPtr)
-{
-  nonVoidTypeCheck(ExprTypeSynPtr);
-
-  if (ExprTypeSynPtr >= 0 && SyntaxStack0[ExprTypeSynPtr] == tokStructPtr)
-    errorOpType();
-}
-
-STATIC
-void numericTypeCheck(int ExprTypeSynPtr)
-{
-  if (ExprTypeSynPtr >= 0)
-    switch (SyntaxStack0[ExprTypeSynPtr])
-    {
-    case tokChar:
-    case tokSChar:
-    case tokUChar:
-    case tokShort:
-    case tokUShort:
-    case tokInt:
-    case tokUnsigned:
-      return;
-    }
-  //error("numericTypeCheck(): unexpected operand type for operator '%s', numeric type expected\n", GetTokenName(tok));
-  errorOpType();
-}
-
-
-
-STATIC
-void anyIntTypeCheck(int ExprTypeSynPtr)
-{
-  // Check for any integer type
-  numericTypeCheck(ExprTypeSynPtr);
-
-}
-
-
-
-STATIC
-int isUint(int ExprTypeSynPtr)
-{
-  return ExprTypeSynPtr >= 0 && SyntaxStack0[ExprTypeSynPtr] == tokUnsigned;
-}
-
-STATIC
-void compatCheck(int* ExprTypeSynPtr, int TheOtherExprTypeSynPtr, int ConstExpr[2], int lidx, int ridx)
-{
-  int exprTypeSynPtr = *ExprTypeSynPtr;
-  int c = 0;
-  int lptr, rptr, lnum, rnum;
-
-  // (un)decay/convert functions to pointers to functions
-  // and to simplify matters convert all '*' pointers to negative type indices
-  if (exprTypeSynPtr >= 0)
-  {
-    switch (SyntaxStack0[exprTypeSynPtr])
-    {
-    case '*':
-      exprTypeSynPtr++;
-      // fallthrough
-    case '(':
-      exprTypeSynPtr = -exprTypeSynPtr;
-    }
-    *ExprTypeSynPtr = exprTypeSynPtr;
-  }
-  if (TheOtherExprTypeSynPtr >= 0)
-  {
-    switch (SyntaxStack0[TheOtherExprTypeSynPtr])
-    {
-    case '*':
-      TheOtherExprTypeSynPtr++;
-      // fallthrough
-    case '(':
-      TheOtherExprTypeSynPtr = -TheOtherExprTypeSynPtr;
-    }
-  }
-  lptr = exprTypeSynPtr < 0;
-  rptr = TheOtherExprTypeSynPtr < 0;
-  lnum = !lptr && (SyntaxStack0[exprTypeSynPtr] == tokInt ||
-
-                   SyntaxStack0[exprTypeSynPtr] == tokUnsigned);
-  rnum = !rptr && (SyntaxStack0[TheOtherExprTypeSynPtr] == tokInt ||
-
-                   SyntaxStack0[TheOtherExprTypeSynPtr] == tokUnsigned);
-
-  // both operands have arithmetic type
-  // (arithmetic operands have been already promoted):
-  if (lnum && rnum)
-    return;
-
-  // both operands have void type:
-  if (!lptr && SyntaxStack0[exprTypeSynPtr] == tokVoid &&
-      !rptr && SyntaxStack0[TheOtherExprTypeSynPtr] == tokVoid)
-    return;
-
-  // one operand is a pointer and the other is NULL constant
-  // ((void*)0 is also a valid null pointer constant),
-  // the type of the expression is that of the pointer:
-  if (lptr &&
-      ((rnum && ConstExpr[1] && truncInt(stack[ridx][1]) == 0) ||
-       (rptr && SyntaxStack0[-TheOtherExprTypeSynPtr] == tokVoid &&
-        (stack[ridx][0] == tokNumInt || stack[ridx][0] == tokNumUint) &&
-        truncInt(stack[ridx][1]) == 0)))
-    return;
-  if (rptr &&
-      ((lnum && ConstExpr[0] && truncInt(stack[lidx][1]) == 0) ||
-       (lptr && SyntaxStack0[-exprTypeSynPtr] == tokVoid &&
-        (stack[lidx][0] == tokNumInt || stack[lidx][0] == tokNumUint) &&
-        truncInt(stack[lidx][1]) == 0)))
-  {
-    *ExprTypeSynPtr = TheOtherExprTypeSynPtr;
-    return;
-  }
-
-  // not expecting non-pointers beyond this point
-  if (!(lptr && rptr))
-    errorOpType();
-
-  // one operand is a pointer and the other is a pointer to void
-  // (except (void*)0 (AKA NULL), which is different from other pointers to void),
-  // the type of the expression is pointer to void:
-  if (SyntaxStack0[-exprTypeSynPtr] == tokVoid)
-    return;
-  if (SyntaxStack0[-TheOtherExprTypeSynPtr] == tokVoid)
-  {
-    *ExprTypeSynPtr = TheOtherExprTypeSynPtr;
-    return;
-  }
-
-  // both operands are pointers to compatible types:
-
-  if (exprTypeSynPtr == TheOtherExprTypeSynPtr)
-    return;
-
-  exprTypeSynPtr = -exprTypeSynPtr;
-  TheOtherExprTypeSynPtr = -TheOtherExprTypeSynPtr;
-
-  for (;;)
-  {
-    int tok = SyntaxStack0[exprTypeSynPtr];
-    if (tok != SyntaxStack0[TheOtherExprTypeSynPtr])
-      errorOpType();
-
-    if (tok != tokIdent &&
-        SyntaxStack1[exprTypeSynPtr] != SyntaxStack1[TheOtherExprTypeSynPtr])
-      errorOpType();
-
-    c += (tok == '(') - (tok == ')') + (tok == '[') - (tok == ']');
-
-    if (!c)
-    {
-      switch (tok)
-      {
-      case tokVoid:
-      case tokChar: case tokSChar: case tokUChar:
-
-      case tokShort: case tokUShort:
-
-      case tokInt: case tokUnsigned:
-
-      case tokStructPtr:
-        return;
-      }
-    }
-
-    exprTypeSynPtr++;
-    TheOtherExprTypeSynPtr++;
-  }
-}
-
-STATIC
-void shiftCountCheck(int *psr, int idx, int ExprTypeSynPtr)
-{
-  int sr = *psr;
-  // can't shift by a negative count and by a count exceeding
-  // the number of bits in int
-  if ((SyntaxStack0[ExprTypeSynPtr] != tokUnsigned && sr < 0) ||
-      (unsigned)sr >= CHAR_BIT * sizeof(int) ||
-      (unsigned)sr >= 8u * SizeOfWord)
-  {
-    //error("exprval(): Invalid shift count\n");
-    warning("Shift count out of range\n");
-    // truncate the count, so the assembler doesn't get an invalid count
-    sr &= SizeOfWord * 8 - 1;
-    *psr = sr;
-    stack[idx][1] = sr;
-  }
-}
-
-STATIC
-int divCheckAndCalc(int tok, int* psl, int sr, int Unsigned, int ConstExpr[2])
-{
-  int div0 = 0;
-  int sl = *psl;
-
-  if (!ConstExpr[1])
-    return !div0;
-
-  if (Unsigned)
-  {
-    sl = (int)truncUint(sl);
-    sr = (int)truncUint(sr);
-  }
-  else
-  {
-    sl = truncInt(sl);
-    sr = truncInt(sr);
-  }
-
-  if (sr == 0)
-  {
-    div0 = 1;
-  }
-  else if (!ConstExpr[0])
-  {
-    return !div0;
-  }
-  else if (!Unsigned && ((sl == INT_MIN && sr == -1) || division(sl , sr) != truncInt(division(sl , sr))))
-  {
-    div0 = 1;
-  }
-  else
-  {
-    if (Unsigned)
-    {
-      if (tok == '/')
-        sl = (int)((unsigned)division(sl , sr));
-      else
-        sl = (int)((unsigned)modulo(sl , sr));
-    }
-    else
-    {
-      // TBD!!! C89 gives freedom in how exactly division of negative integers
-      // can be implemented w.r.t. rounding and w.r.t. the sign of the remainder.
-      // A stricter, C99-conforming implementation, non-dependent on the
-      // compiler used to compile Smaller C is needed.
-      if (tok == '/')
-        sl = division(sl, sr);
-      else
-        sl = modulo(sl, sr);
-    }
-    *psl = sl;
-  }
-
-  if (div0)
-    warning("Division by 0 or division overflow\n");
-
-  return !div0;
-}
-
-STATIC
-void promoteType(int* ExprTypeSynPtr, int* TheOtherExprTypeSynPtr)
-{
-  // Integer promotion to signed int or unsigned int from smaller types
-  // (all kinds of char and short). Promotion to unsigned int occurs
-  // only if the other operand (of a binary operator) is already an
-  // unsigned int. Effectively, this promotion to unsigned int performs
-  // usual arithmetic conversion for integers.
-  if (*ExprTypeSynPtr >= 0)
-  {
-    // chars must be promoted to ints in expressions as the very first thing
-    switch (SyntaxStack0[*ExprTypeSynPtr])
-    {
-    case tokChar:
-    case tokShort:
-    case tokUShort:
-    case tokSChar:
-    case tokUChar:
-      *ExprTypeSynPtr = SymIntSynPtr;
-    }
-    if (*TheOtherExprTypeSynPtr >= 0)
-    {
-      // ints must be converted to unsigned ints if they are used in binary
-      // operators whose other operand is unsigned int (except <<,>>,<<=,>>=)
-      if (SyntaxStack0[*ExprTypeSynPtr] == tokInt &&
-          SyntaxStack0[*TheOtherExprTypeSynPtr] == tokUnsigned)
-        *ExprTypeSynPtr = SymUintSynPtr;
-    }
-  }
-}
-
-STATIC
-int GetFxnInfo(int ExprTypeSynPtr, int* MinParams, int* MaxParams, int* ReturnExprTypeSynPtr, int* FirstParamSynPtr)
-{
-  *MaxParams = *MinParams = 0;
-
-  if (ExprTypeSynPtr < 0)
-  {
-    ExprTypeSynPtr = -ExprTypeSynPtr;
-  }
-  else
-  {
-    while (SyntaxStack0[ExprTypeSynPtr] == tokIdent || SyntaxStack0[ExprTypeSynPtr] == tokLocalOfs)
-      ExprTypeSynPtr++;
-    if (SyntaxStack0[ExprTypeSynPtr] == '*')
-      ExprTypeSynPtr++;
-  }
-
-  if (SyntaxStack0[ExprTypeSynPtr] != '(')
-    return 0;
-
-  // DONE: return syntax pointer to the function's return type
-
-  // Count params
-
-  ExprTypeSynPtr++;
-
-  if (FirstParamSynPtr)
-    *FirstParamSynPtr = ExprTypeSynPtr;
-
-  if (SyntaxStack0[ExprTypeSynPtr] == ')')
-  {
-    // "fxn()": unspecified parameters, so, there can be any number of them
-    *MaxParams = 32767; // INT_MAX;
-    *ReturnExprTypeSynPtr = ExprTypeSynPtr + 1;
-    return 1;
-  }
-
-  if (SyntaxStack0[ExprTypeSynPtr + 1] == tokVoid)
-  {
-    // "fxn(void)": 0 parameters
-    *ReturnExprTypeSynPtr = ExprTypeSynPtr + 3;
-    return 1;
-  }
-
-  for (;;)
-  {
-    int tok = SyntaxStack0[ExprTypeSynPtr];
-
-    if (tok == tokIdent)
-    {
-      if (SyntaxStack0[ExprTypeSynPtr + 1] != tokEllipsis)
-      {
-        ++*MinParams;
-        ++*MaxParams;
-      }
-      else
-      {
-        *MaxParams = 32767; // INT_MAX;
-      }
-    }
-    else if (tok == '(')
-    {
-      // skip parameters in parameters
-      int c = 1;
-      while (c && ExprTypeSynPtr < SyntaxStackCnt)
-      {
-        tok = SyntaxStack0[++ExprTypeSynPtr];
-        c += (tok == '(') - (tok == ')');
-      }
-    }
-    else if (tok == ')')
-    {
-      ExprTypeSynPtr++;
-      break;
-    }
-
-    ExprTypeSynPtr++;
-  }
-
-  // get the function's return type
-  *ReturnExprTypeSynPtr = ExprTypeSynPtr;
-
-  return 1;
-}
-
-STATIC
-void simplifyConstExpr(int val, int isConst, int* ExprTypeSynPtr, int top, int bottom)
-{
-  // If non-const, nothing to do.
-  // If const and already a number behind the scenes, nothing to do
-  // (val must not differ from the number!).
-  if (!isConst || stack[top][0] == tokNumInt || stack[top][0] == tokNumUint)
-    return;
-
-  // Const, but not a number yet. Reduce to a number equal val.
-  if (SyntaxStack0[*ExprTypeSynPtr] == tokUnsigned)
-    stack[top][0] = tokNumUint;
-  else
-    stack[top][0] = tokNumInt;
-  stack[top][1] = val;
-
-  del(bottom, top - bottom);
-}
-
-STATIC
-int AllocLocal(unsigned size)
-{
-  // Let's calculate variable's relative on-stack location
-  int oldOfs = CurFxnLocalOfs;
-
-  // Note: local vars are word-aligned on the stack
-  CurFxnLocalOfs = (int)((CurFxnLocalOfs - size) & ~(SizeOfWord - 1u));
-  if (CurFxnLocalOfs >= oldOfs ||
-      CurFxnLocalOfs != truncInt(CurFxnLocalOfs) ||
-      CurFxnLocalOfs < -GenMaxLocalsSize())
-    //error("AllocLocal(): Local variables take too much space\n");
-    errorVarSize();
-
-  if (CurFxnMinLocalOfs > CurFxnLocalOfs)
-    CurFxnMinLocalOfs = CurFxnLocalOfs;
-
-  return CurFxnLocalOfs;
-}
-
-// DONE: sizeof(type)
-// DONE: "sizeof expr"
-// DONE: constant expressions
-// DONE: collapse constant subexpressions into constants
-STATIC
-int exprval(int* idx, int* ExprTypeSynPtr, int* ConstExpr)
-{
-  int tok;
-  int s;
-  int RightExprTypeSynPtr;
-  int oldIdxRight;
-  int oldSpRight;
-  int constExpr[3];
-
-  if (*idx < 0)
-    //error("exprval(): idx < 0\n");
-    errorInternal(5);
-
-  tok = stack[*idx][0];
-  s = stack[*idx][1];
-
-  --*idx;
-
-  oldIdxRight = *idx;
-  oldSpRight = sp;
-
-  switch (tok)
-  {
-  // Constants
-  case tokNumInt:
-    // return the constant's type: int
-    *ExprTypeSynPtr = SymIntSynPtr;
-    *ConstExpr = 1;
-    break;
-  case tokNumUint:
-    // return the constant's type: unsigned int
-    *ExprTypeSynPtr = SymUintSynPtr;
-    *ConstExpr = 1;
-    break;
-
-
-
-  // Identifiers
-  case tokIdent:
-    {
-      // DONE: support __func__
-      char* ident = IdentTable + s;
-      int synPtr, type;
-
-      {
-        synPtr = FindSymbol(ident);
-        // "Rename" static vars in function scope
-        if (synPtr >= 0 && synPtr + 1 < SyntaxStackCnt && SyntaxStack0[synPtr + 1] == tokIdent)
-        {
-          s = stack[*idx + 1][1] = SyntaxStack1[++synPtr];
-          ident = IdentTable + s;
-        }
-      }
-
-      if (synPtr < 0)
-      {
-        if ((*idx + 2 >= sp) || stack[*idx + 2][0] != ')')
-          error("Undeclared identifier '%s'\n", ident);
-        else
-        {
-          warning("Call to undeclared function '%s()'\n", ident);
-          // Implicitly declare "extern int ident();"
-          PushSyntax2(tokIdent, s);
-          PushSyntax('(');
-          PushSyntax(')');
-          PushSyntax(tokInt);
-          synPtr = FindSymbol(ident);
-        }
-      }
-
-
-
-      // DONE: this declaration is actually a type cast
-      if (!strncmp(IdentTable + SyntaxStack1[synPtr], "(something", sizeof "(something)" - 1 - 1))
-      {
-
-        int castSize;
-
-        if (SyntaxStack0[++synPtr] == tokLocalOfs) // TBD!!! is this really needed???
-          synPtr++;
-
-        s = exprval(idx, ExprTypeSynPtr, ConstExpr);
-
-        // can't cast void or structure/union to anything (except void)
-        if (*ExprTypeSynPtr >= 0 &&
-            (SyntaxStack0[*ExprTypeSynPtr] == tokVoid ||
-             SyntaxStack0[*ExprTypeSynPtr] == tokStructPtr) &&
-            SyntaxStack0[synPtr] != tokVoid)
-          errorOpType();
-
-        // can't cast to function, array or structure/union
-        if (SyntaxStack0[synPtr] == '(' ||
-            SyntaxStack0[synPtr] == '[' ||
-            SyntaxStack0[synPtr] == tokStructPtr)
-          errorOpType();
-
-
-
-        // will try to propagate constants through casts
-        if (!*ConstExpr &&
-            (stack[oldIdxRight - (oldSpRight - sp)][0] == tokNumInt ||
-             stack[oldIdxRight - (oldSpRight - sp)][0] == tokNumUint))
-        {
-          s = stack[oldIdxRight - (oldSpRight - sp)][1];
-          *ConstExpr = 1;
-        }
-
-        castSize = GetDeclSize(synPtr, 1); // 0 for cast to void
-
-
-
-        // insertion of tokUChar, tokSChar and tokUnaryPlus transforms
-        // lvalues (values formed by dereferences) into rvalues
-        // (by hiding the dereferences), just as casts should do
-        switch (castSize)
-        {
-        case 1:
-          // cast to unsigned char
-          stack[oldIdxRight + 1 - (oldSpRight - sp)][0] = tokUChar;
-          s &= 0xFFu;
-          break;
-        case -1:
-          // cast to signed char
-          stack[oldIdxRight + 1 - (oldSpRight - sp)][0] = tokSChar;
-          if ((s &= 0xFFu) >= 0x80)
-            s -= 0x100;
-          break;
-        default:
-
-          if (castSize && castSize != SizeOfWord)
-          {
-            // cast not to void and not to word-sized type (int/unsigned/pointer/float)
-            if (castSize == 2)
-            {
-              // cast to unsigned short
-              stack[oldIdxRight + 1 - (oldSpRight - sp)][0] = tokUShort;
-              s &= 0xFFFFu;
-            }
-            else
-            {
-              // cast to signed short
-              stack[oldIdxRight + 1 - (oldSpRight - sp)][0] = tokShort;
-              if ((s &= 0xFFFFu) >= 0x8000)
-                s -= 0x10000;
-            }
-          }
-          else // fallthrough
-
-          {
-            // cast to void or word-sized type (int/unsigned/pointer/float)
-
-            if (stack[oldIdxRight - (oldSpRight - sp)][0] == tokUnaryStar)
-              // hide the dereference
-              stack[oldIdxRight + 1 - (oldSpRight - sp)][0] = tokUnaryPlus;
-          }
-          break;
-        }
-
-        if (*ConstExpr)
-          stack[oldIdxRight - (oldSpRight - sp)][1] = s;
-
-        *ExprTypeSynPtr = synPtr;
-        simplifyConstExpr(s, *ConstExpr, ExprTypeSynPtr, oldIdxRight + 1 - (oldSpRight - sp), *idx + 1);
-
-        if (!*ConstExpr && stack[oldIdxRight + 1 - (oldSpRight - sp)][0] == tokIdent)
-          // nothing to hide, remove the cast
-          del(oldIdxRight + 1 - (oldSpRight - sp), 1);
-
-        switch (SyntaxStack0[synPtr])
-        {
-        case tokChar:
-        case tokSChar:
-        case tokUChar:
-        case tokShort:
-        case tokUShort:
-
-        case tokInt:
-        case tokUnsigned:
-
-          break;
-        default:
-          // only numeric types can be const
-          *ConstExpr = 0;
-          break;
-        }
-
-        break;
-      }
-
-      // Finally, not __func__, not enum, not cast.
-
-      type = SymType(synPtr);
-
-      if (type == SymLocalVar || type == SymLocalArr)
-      {
-        // replace local variables/arrays with their local addresses
-        // (global variables/arrays' addresses are their names)
-        stack[*idx + 1][0] = tokLocalOfs;
-        stack[*idx + 1][1] = SyntaxStack1[synPtr + 1];
-      }
-      if (type == SymLocalVar || type == SymGlobalVar)
-      {
-        // add implicit dereferences for local/global variables
-        ins2(*idx + 2, tokUnaryStar, GetDeclSize(synPtr, 1));
-      }
-
-      // return the identifier's type
-      while (SyntaxStack0[synPtr] == tokIdent || SyntaxStack0[synPtr] == tokLocalOfs)
-        synPtr++;
-      *ExprTypeSynPtr = synPtr;
-    }
-    *ConstExpr = 0;
-    break;
-
-  // sizeof operator
-  case tokSizeof:
-    exprval(idx, ExprTypeSynPtr, ConstExpr);
-    s = GetDeclSize(*ExprTypeSynPtr, 0);
-    if (s == 0)
-      error("sizeof of incomplete type\n");
-
-    // replace sizeof with its numeric value
-    stack[oldIdxRight + 1 - (oldSpRight - sp)][0] = tokNumUint;
-    stack[oldIdxRight + 1 - (oldSpRight - sp)][1] = s;
-
-    // remove the sizeof's subexpression
-    del(*idx + 1, oldIdxRight - (oldSpRight - sp) - *idx);
-
-    *ExprTypeSynPtr = SymUintSynPtr;
-    *ConstExpr = 1;
-    break;
-
-  // Address unary operator
-  case tokUnaryAnd:
-    exprval(idx, ExprTypeSynPtr, ConstExpr);
-
-    if (*ExprTypeSynPtr >= 0 &&
-        (SyntaxStack0[*ExprTypeSynPtr] == '[' || SyntaxStack0[*ExprTypeSynPtr] == '('))
-    {
-      // convert an array into a pointer to the array,
-      // convert a function into a pointer to the function,
-      // remove the reference
-      del(oldIdxRight + 1 - (oldSpRight - sp), 1);
-    }
-    else if (*ExprTypeSynPtr >= 0 &&
-             stack[oldIdxRight - (oldSpRight - sp)][0] == tokUnaryStar)
-    {
-      // it's an lvalue (with implicit or explicit dereference),
-      // convert it into its address by
-      // collapsing/removing the reference and the dereference
-      del(oldIdxRight - (oldSpRight - sp), 2);
-    }
-    else
-      //error("exprval(): lvalue expected after '&'\n");
-      errorNotLvalue();
-
-    // we cannot insert another '*' into the type to make it a pointer
-    // to an array/function/etc, so make the index into the type negative
-    *ExprTypeSynPtr = -*ExprTypeSynPtr;
-
-    *ConstExpr = 0;
-    break;
-
-  // Indirection unary operator
-  case tokUnaryStar:
-    exprval(idx, ExprTypeSynPtr, ConstExpr);
-
-    if (*ExprTypeSynPtr < 0 || SyntaxStack0[*ExprTypeSynPtr] == '*')
-    {
-      // type is a pointer to something,
-      // transform it into that something
-      if (*ExprTypeSynPtr < 0)
-        *ExprTypeSynPtr = -*ExprTypeSynPtr;
-      else
-        ++*ExprTypeSynPtr;
-      nonVoidTypeCheck(*ExprTypeSynPtr);
-      if (SyntaxStack0[*ExprTypeSynPtr] == tokStructPtr && !GetDeclSize(*ExprTypeSynPtr, 0))
-        // incomplete structure/union type
-        errorOpType();
-      // remove the dereference if that something is an array or a function
-      if (SyntaxStack0[*ExprTypeSynPtr] == '[' ||
-          SyntaxStack0[*ExprTypeSynPtr] == '(')
-        del(oldIdxRight + 1 - (oldSpRight - sp), 1);
-      // else attach dereference size in bytes
-      else
-        stack[oldIdxRight + 1 - (oldSpRight - sp)][1] = GetDeclSize(*ExprTypeSynPtr, 1);
-    }
-    else if (SyntaxStack0[*ExprTypeSynPtr] == '[')
-    {
-      // type is an array,
-      // transform it into the array's first element
-      // (a subarray, if type is a multidimensional array)
-      (*ExprTypeSynPtr) += 3;
-      // remove the dereference if that element is an array
-      if (SyntaxStack0[*ExprTypeSynPtr] == '[')
-        del(oldIdxRight + 1 - (oldSpRight - sp), 1);
-      // else attach dereference size in bytes
-      else
-        stack[oldIdxRight + 1 - (oldSpRight - sp)][1] = GetDeclSize(*ExprTypeSynPtr, 1);
-    }
-    else
-      //error("exprval(): pointer/array expected after '*' / before '[]'\n");
-      errorOpType();
-
-    *ConstExpr = 0;
-    break;
-
-  // Additive binary operators
-  case '+':
-  case '-':
-  // WRONGISH: DONE: replace prefix ++/-- with +=1/-=1
-  // WRONG: DONE: replace postfix ++/-- with (+=1)-1/(-=1)+1
-    {
-      int ptrmask;
-
-      int oldIdxLeft, oldSpLeft;
-      int sl, sr;
-      int incSize;
-      sr = exprval(idx, &RightExprTypeSynPtr, &constExpr[1]);
-      oldIdxLeft = *idx;
-      oldSpLeft = sp;
-      sl = exprval(idx, ExprTypeSynPtr, &constExpr[0]);
-
-      // Decay arrays to pointers to their first elements
-      // and ensure that the pointers are suitable for pointer arithmetic
-      // (not pointers to functions, sizes of pointees are known and non-zero)
-      decayArray(&RightExprTypeSynPtr, 1);
-      decayArray(ExprTypeSynPtr, 1);
-
-      // Bar void and struct/union
-      scalarTypeCheck(RightExprTypeSynPtr);
-      scalarTypeCheck(*ExprTypeSynPtr);
-
-      ptrmask = isAnyPtr(RightExprTypeSynPtr) + isAnyPtr(*ExprTypeSynPtr) * 2;
-
-
-      // DONE: index/subscript scaling
-      if (ptrmask == 1 && tok == '+') // pointer in right-hand expression
-      {
-        incSize = GetDeclSize(derefAnyPtr(RightExprTypeSynPtr), 0);
-
-        if (constExpr[0]) // integer constant in left-hand expression
-        {
-          s = (int)((unsigned)sl * incSize);
-          stack[oldIdxLeft - (oldSpLeft - sp)][1] = s;
-          // optimize a little if possible
-          {
-            int i = oldIdxRight - (oldSpRight - sp);
-            // Skip any type cast markers
-            while (stack[i][0] == tokUnaryPlus || stack[i][0] == '+')
-              i--;
-            // See if the pointer is an integer constant or a local variable offset
-            // and if it is, adjust it here instead of generating code for
-            // addition/subtraction
-            if (stack[i][0] == tokNumInt || stack[i][0] == tokNumUint || stack[i][0] == tokLocalOfs)
-            {
-              s = (int)((unsigned)stack[i][1] + s);
-              stack[i][1] = s; // TBD!!! need extra truncation?
-              del(oldIdxLeft - (oldSpLeft - sp), 1);
-              del(oldIdxRight - (oldSpRight - sp) + 1, 1);
-            }
-          }
-        }
-        else if (incSize != 1)
-        {
-          ins2(oldIdxLeft + 1 - (oldSpLeft - sp), tokNumInt, incSize);
-          ins(oldIdxLeft + 1 - (oldSpLeft - sp), '*');
-        }
-
-        *ExprTypeSynPtr = RightExprTypeSynPtr;
-      }
-      else if (ptrmask == 2) // pointer in left-hand expression
-      {
-        incSize = GetDeclSize(derefAnyPtr(*ExprTypeSynPtr), 0);
-        if (constExpr[1]) // integer constant in right-hand expression
-        {
-          s = (int)((unsigned)sr * incSize);
-          stack[oldIdxRight - (oldSpRight - sp)][1] = s;
-          // optimize a little if possible
-          {
-            int i = oldIdxLeft - (oldSpLeft - sp);
-            // Skip any type cast markers
-            while (stack[i][0] == tokUnaryPlus || stack[i][0] == '+')
-              i--;
-            // See if the pointer is an integer constant or a local variable offset
-            // and if it is, adjust it here instead of generating code for
-            // addition/subtraction
-            if (stack[i][0] == tokNumInt || stack[i][0] == tokNumUint || stack[i][0] == tokLocalOfs)
-            {
-              if (tok == '-')
-                s = (int)~(s - 1u);
-              s = (int)((unsigned)stack[i][1] + s);
-              stack[i][1] = s; // TBD!!! need extra truncation?
-              del(oldIdxRight - (oldSpRight - sp), 2);
-            }
-          }
-        }
-        else if (incSize != 1)
-        {
-          ins2(oldIdxRight + 1 - (oldSpRight - sp), tokNumInt, incSize);
-          ins(oldIdxRight + 1 - (oldSpRight - sp), '*');
-        }
-      }
-      else if (ptrmask == 3 && tok == '-') // pointers in both expressions
-      {
-        incSize = GetDeclSize(derefAnyPtr(*ExprTypeSynPtr), 0);
-        // TBD!!! "ptr1-ptr2": better pointer type compatibility test needed, like compatCheck()?
-        if (incSize != GetDeclSize(derefAnyPtr(RightExprTypeSynPtr), 0))
-          //error("exprval(): incompatible pointers\n");
-          errorOpType();
-        if (incSize != 1)
-        {
-          ins2(oldIdxRight + 2 - (oldSpRight - sp), tokNumInt, incSize);
-          ins(oldIdxRight + 2 - (oldSpRight - sp), '/');
-        }
-        *ExprTypeSynPtr = SymIntSynPtr;
-      }
-      else if (ptrmask)
-        //error("exprval(): invalid combination of operands for '+' or '-'\n");
-        errorOpType();
-
-      // Promote the result from char to int (and from int to unsigned) if necessary
-      promoteType(ExprTypeSynPtr, &RightExprTypeSynPtr);
-
-      *ConstExpr = constExpr[0] && constExpr[1];
-
-
-      {
-        if (tok == '+')
-          s = (int)((unsigned)sl + sr);
-        else
-          s = (int)((unsigned)sl - sr);
-      }
-
-      simplifyConstExpr(s, *ConstExpr, ExprTypeSynPtr, oldIdxRight + 1 - (oldSpRight - sp), *idx + 1);
-    }
-    break;
-
-  // Prefix/postfix increment/decrement unary operators
-  case tokInc:
-  case tokDec:
-  case tokPostInc:
-  case tokPostDec:
-    {
-      int incSize = 1;
-      int inc = tok == tokInc || tok == tokPostInc;
-      int post = tok == tokPostInc || tok == tokPostDec;
-      int opSize;
-
-      exprval(idx, ExprTypeSynPtr, ConstExpr);
-
-      lvalueCheck(*ExprTypeSynPtr, oldIdxRight - (oldSpRight - sp));
-
-      // if it's a pointer, ensure that it's suitable for pointer arithmetic
-      // (not pointer to function, pointee size is known and non-zero)
-      decayArray(ExprTypeSynPtr, 1); // no actual decay here, just a type check
-
-      // Bar void and struct/union
-      scalarTypeCheck(*ExprTypeSynPtr);
-
-
-
-      // "remove" the lvalue dereference as we don't need
-      // to read the value while forgetting its location.
-      // We need to keep the lvalue location.
-      // Remember the operand size.
-      opSize = stack[oldIdxRight - (oldSpRight - sp)][1];
-      del(oldIdxRight - (oldSpRight - sp), 1);
-
-      if (isAnyPtr(*ExprTypeSynPtr))
-        incSize = GetDeclSize(derefAnyPtr(*ExprTypeSynPtr), 0);
-
-      if (incSize == 1)
-      {
-        // store the operand size in the operator
-        stack[oldIdxRight + 1 - (oldSpRight - sp)][1] = opSize;
-      }
-      else
-      {
-        // replace ++/-- with "postfix" +=/-= incSize when incSize != 1
-        stack[oldIdxRight + 1 - (oldSpRight - sp)][0] =
-          inc ? (post ? tokPostAdd : tokAssignAdd) :
-                (post ? tokPostSub : tokAssignSub);
-        // store the operand size in the operator
-        stack[oldIdxRight + 1 - (oldSpRight - sp)][1] = opSize;
-        ins2(oldIdxRight + 1 - (oldSpRight - sp), tokNumInt, incSize);
-      }
-
-      *ConstExpr = 0;
-    }
-    break;
-
-  // Simple assignment binary operator
-  case '=':
-    {
-      int oldIdxLeft, oldSpLeft;
-      int opSize;
-      int structs;
-
-        exprval(idx, &RightExprTypeSynPtr, &constExpr[1]);
-      oldIdxLeft = *idx;
-      oldSpLeft = sp;
-      exprval(idx, ExprTypeSynPtr, &constExpr[0]);
-
-      lvalueCheck(*ExprTypeSynPtr, oldIdxLeft - (oldSpLeft - sp));
-
-      nonVoidTypeCheck(RightExprTypeSynPtr);
-      nonVoidTypeCheck(*ExprTypeSynPtr);
-
-      structs = (*ExprTypeSynPtr >= 0 && SyntaxStack0[*ExprTypeSynPtr] == tokStructPtr) * 2 +
-                (RightExprTypeSynPtr >= 0 && SyntaxStack0[RightExprTypeSynPtr] == tokStructPtr);
-
-
-      if (structs)
-      {
-        int sz;
-
-        if (structs != 3 ||
-            SyntaxStack1[RightExprTypeSynPtr] != SyntaxStack1[*ExprTypeSynPtr])
-          errorOpType();
-
-        // TBD??? (a = b) should be an rvalue and so &(a = b) and (&(a = b))->c shouldn't be
-        // allowed, while (a = b).c should be allowed.
-
-        // transform "*psleft = *psright" into "*fxn(sizeof *psright, psright, psleft)"
-/*
-        if (stack[oldIdxLeft - (oldSpLeft - sp)][0] != tokUnaryStar ||
-            stack[oldIdxRight - (oldSpRight - sp)][0] != tokUnaryStar)
-          errorInternal(18);
-*/
-        stack[oldIdxLeft - (oldSpLeft - sp)][0] = ','; // replace '*' with ','
-        stack[oldIdxRight - (oldSpRight - sp)][0] = ','; // replace '*' with ','
-
-        sz = GetDeclSize(RightExprTypeSynPtr, 0);
-
-        stack[oldIdxRight + 1 - (oldSpRight - sp)][0] = tokNumUint; // replace '=' with "sizeof *psright"
-        stack[oldIdxRight + 1 - (oldSpRight - sp)][1] = sz;
-
-        ins(oldIdxRight + 2 - (oldSpRight - sp), ',');
-
-        if (!StructCpyLabel)
-          StructCpyLabel = LabelCnt++;
-        ins2(oldIdxRight + 2 - (oldSpRight - sp), tokIdent, AddNumericIdent(StructCpyLabel));
-
-        ins2(oldIdxRight + 2 - (oldSpRight - sp), ')', SizeOfWord * 3);
-        ins2(oldIdxRight + 2 - (oldSpRight - sp), tokUnaryStar, 0); // use 0 deref size to drop meaningless dereferences
-
-        ins2(*idx + 1, '(', SizeOfWord * 3);
-      }
-      else
-      {
-
-        // "remove" the lvalue dereference as we don't need
-        // to read the value while forgetting its location.
-        // We need to keep the lvalue location.
-        // Remember the operand size.
-        opSize = stack[oldIdxLeft - (oldSpLeft - sp)][1];
-        // store the operand size in the operator
-        stack[oldIdxRight + 1 - (oldSpRight - sp)][1] = opSize;
-        del(oldIdxLeft - (oldSpLeft - sp), 1);
-      }
-
-      *ConstExpr = 0;
-    }
-    break;
-
-  // DONE: other assignment operators
-
-  // Arithmetic and bitwise unary operators
-  case '~':
-  case tokUnaryPlus:
-  case tokUnaryMinus:
-    s = exprval(idx, ExprTypeSynPtr, ConstExpr);
-    numericTypeCheck(*ExprTypeSynPtr);
-    promoteType(ExprTypeSynPtr, ExprTypeSynPtr);
-    switch (tok)
-    {
-    case '~':
-
-      s = ~s;
-      break;
-    case tokUnaryPlus:
-      break;
-    case tokUnaryMinus:
-
-      {
-        s = (int)~(s - 1u);
-      }
-      break;
-    }
-    simplifyConstExpr(s, *ConstExpr, ExprTypeSynPtr, oldIdxRight + 1 - (oldSpRight - sp), *idx + 1);
-    break;
-
-  // Arithmetic and bitwise binary operators
-  case '*':
-  case '/':
-  case '%':
-  case tokLShift:
-  case tokRShift:
-  case '&':
-  case '^':
-  case '|':
-    {
-
-      int sr, sl;
-      int Unsigned;
-      sr = exprval(idx, &RightExprTypeSynPtr, &constExpr[1]);
-
-      sl = exprval(idx, ExprTypeSynPtr, &constExpr[0]);
-
-      numericTypeCheck(RightExprTypeSynPtr);
-      numericTypeCheck(*ExprTypeSynPtr);
-
-
-      *ConstExpr = constExpr[0] && constExpr[1];
-
-      Unsigned = SyntaxStack0[*ExprTypeSynPtr] == tokUnsigned || SyntaxStack0[RightExprTypeSynPtr] == tokUnsigned;
-
-
-      {
-        switch (tok)
-        {
-        // DONE: check for division overflows
-        case '/':
-        case '%':
-          *ConstExpr &= divCheckAndCalc(tok, &sl, sr, Unsigned, constExpr);
-
-          if (Unsigned)
-          {
-            if (tok == '/')
-              stack[oldIdxRight + 1 - (oldSpRight - sp)][0] = tokUDiv;
-            else
-              stack[oldIdxRight + 1 - (oldSpRight - sp)][0] = tokUMod;
-          }
-          break;
-
-        case '*':
-          sl = (int)((unsigned)sl * sr);
-          break;
-
-        case tokLShift:
-        case tokRShift:
-          if (constExpr[1])
-          {
-            if (SyntaxStack0[RightExprTypeSynPtr] != tokUnsigned)
-              sr = truncInt(sr);
-            else
-              sr = (int)truncUint(sr);
-            shiftCountCheck(&sr, oldIdxRight - (oldSpRight - sp), RightExprTypeSynPtr);
-          }
-          if (*ConstExpr)
-          {
-            if (tok == tokLShift)
-            {
-              // left shift is the same for signed and unsigned ints
-              sl = (int)((unsigned)sl << sr);
-            }
-            else
-            {
-              if (SyntaxStack0[*ExprTypeSynPtr] == tokUnsigned)
-              {
-                // right shift for unsigned ints
-                sl = (int)(truncUint(sl) >> sr);
-              }
-              else if (sr)
-              {
-                // right shift for signed ints is arithmetic, sign-bit-preserving
-                // don't depend on the compiler's implementation, do it "manually"
-                sl = truncInt(sl);
-                sl = (int)((truncUint(sl) >> sr) |
-                           ((sl < 0) * (~0u << (8 * SizeOfWord - sr))));
-              }
-            }
-          }
-
-          if (SyntaxStack0[*ExprTypeSynPtr] == tokUnsigned && tok == tokRShift)
-            stack[oldIdxRight + 1 - (oldSpRight - sp)][0] = tokURShift;
-
-          // ignore RightExprTypeSynPtr for the purpose of promotion/conversion of the result of <</>>
-          RightExprTypeSynPtr = SymIntSynPtr;
-          break;
-
-        case '&': sl &= sr; break;
-        case '^': sl ^= sr; break;
-        case '|': sl |= sr; break;
-        }
-        s = sl;
-      }
-      promoteType(ExprTypeSynPtr, &RightExprTypeSynPtr);
-      simplifyConstExpr(s, *ConstExpr, ExprTypeSynPtr, oldIdxRight + 1 - (oldSpRight - sp), *idx + 1);
-    }
-    break;
-
-  // Relational and equality binary operators
-  // DONE: add (sub)tokens for unsigned >, >=, <, <= for pointers
-  case '<':
-  case '>':
-  case tokLEQ:
-  case tokGEQ:
-  case tokEQ:
-  case tokNEQ:
-    {
-      int ptrmask;
-
-      int sr, sl;
-      sr = exprval(idx, &RightExprTypeSynPtr, &constExpr[1]);
-
-      sl = exprval(idx, ExprTypeSynPtr, &constExpr[0]);
-
-      // Bar void and struct/union
-      scalarTypeCheck(RightExprTypeSynPtr);
-      scalarTypeCheck(*ExprTypeSynPtr);
-
-      ptrmask = isAnyPtr(RightExprTypeSynPtr) + isAnyPtr(*ExprTypeSynPtr) * 2;
-
-
-      // TBD??? stricter type checks???
-      if (tok != tokEQ && tok != tokNEQ)
-      {
-        // Disallow >, <, >=, <= between a pointer and a number
-        if (ptrmask == 1 || ptrmask == 2)
-          //error("exprval(): Invalid/unsupported combination of compared operands\n");
-          errorOpType();
-        // Disallow >, <, >=, <= with pointers to functions
-        if (((ptrmask & 1) && SyntaxStack0[derefAnyPtr(RightExprTypeSynPtr)] == '(') ||
-            ((ptrmask & 2) && SyntaxStack0[derefAnyPtr(*ExprTypeSynPtr)] == '('))
-          errorOpType();
-      }
-      else
-      {
-        // Disallow == and != between a pointer and a number other than constant 0 (AKA NULL)
-        if ((ptrmask == 1 && !(constExpr[0] && !truncInt(sl))) ||
-            (ptrmask == 2 && !(constExpr[1] && !truncInt(sr))))
-          errorOpType();
-      }
-
-      *ConstExpr = constExpr[0] && constExpr[1];
-
-
-      {
-        int Unsigned = isUint(*ExprTypeSynPtr) || isUint(RightExprTypeSynPtr);
-
-        if (*ConstExpr)
-        {
-          if (!Unsigned)
-          {
-            sl = truncInt(sl);
-            sr = truncInt(sr);
-            switch (tok)
-            {
-            case '<':    sl = sl <  sr; break;
-            case '>':    sl = sl >  sr; break;
-            case tokLEQ: sl = sl <= sr; break;
-            case tokGEQ: sl = sl >= sr; break;
-            case tokEQ:  sl = sl == sr; break;
-            case tokNEQ: sl = sl != sr; break;
-            }
-          }
-          else
-          {
-            sl = (int)truncUint(sl);
-            sr = (int)truncUint(sr);
-            switch (tok)
-            {
-            case '<':    sl = (unsigned)sl <  (unsigned)sr; break;
-            case '>':    sl = (unsigned)sl >  (unsigned)sr; break;
-            case tokLEQ: sl = (unsigned)sl <= (unsigned)sr; break;
-            case tokGEQ: sl = (unsigned)sl >= (unsigned)sr; break;
-            case tokEQ:  sl = sl == sr; break;
-            case tokNEQ: sl = sl != sr; break;
-            }
-          }
-        }
-
-        if (ptrmask || Unsigned)
-        {
-          // Pointer comparison should be unsigned
-          int t = tok;
-          switch (tok)
-          {
-          case '<': t = tokULess; break;
-          case '>': t = tokUGreater; break;
-          case tokLEQ: t = tokULEQ; break;
-          case tokGEQ: t = tokUGEQ; break;
-          }
-          stack[oldIdxRight + 1 - (oldSpRight - sp)][0] = t;
-        }
-      }
-
-      s = sl;
-      *ExprTypeSynPtr = SymIntSynPtr;
-      simplifyConstExpr(s, *ConstExpr, ExprTypeSynPtr, oldIdxRight + 1 - (oldSpRight - sp), *idx + 1);
-    }
-    break;
-
-  // implicit pseudo-conversion to _Bool of operands of && and ||
-  case tok_Bool:
-    s = exprval(idx, ExprTypeSynPtr, ConstExpr);
-    // Bar void and struct/union
-    scalarTypeCheck(*ExprTypeSynPtr);
-
-    {
-      s = truncInt(s) != 0;
-    }
-    *ExprTypeSynPtr = SymIntSynPtr;
-    simplifyConstExpr(s, *ConstExpr, ExprTypeSynPtr, oldIdxRight + 1 - (oldSpRight - sp), *idx + 1);
-    break;
-
-  // Logical binary operators
-  case tokLogAnd: // DONE: short-circuit
-  case tokLogOr: // DONE: short-circuit
-    {
-      int sr, sl;
-
-      // DONE: think of pushing a special short-circuit (jump-to) token
-      // to skip the rhs operand evaluation in && and ||
-      // DONE: add implicit "casts to _Bool" of && and || operands,
-      // do the same for control statements of if() while() and for(;;).
-
-      int sc = LabelCnt++;
-      // tag the logical operator as a numbered short-circuit jump target
-      stack[*idx + 1][1] = sc;
-
-      // insert "!= 0" for right-hand operand
-      switch (stack[*idx][0])
-      {
-      case '<':
-      case tokULess:
-      case '>':
-      case tokUGreater:
-      case tokLEQ:
-      case tokULEQ:
-      case tokGEQ:
-      case tokUGEQ:
-      case tokEQ:
-      case tokNEQ:
-        break;
-      default:
-        ins(++*idx, tok_Bool);
-        break;
-      }
-
-      sr = exprval(idx, &RightExprTypeSynPtr, &constExpr[1]);
-
-      // insert a reference to the short-circuit jump target
-      if (tok == tokLogAnd)
-        ins2(++*idx, tokShortCirc, sc);
-      else
-        ins2(++*idx, tokShortCirc, -sc);
-      // insert "!= 0" for left-hand operand
-      switch (stack[*idx - 1][0])
-      {
-      case '<':
-      case tokULess:
-      case '>':
-      case tokUGreater:
-      case tokLEQ:
-      case tokULEQ:
-      case tokGEQ:
-      case tokUGEQ:
-      case tokEQ:
-      case tokNEQ:
-        --*idx;
-        break;
-      default:
-        ins(*idx, tok_Bool);
-        break;
-      }
-
-      sl = exprval(idx, ExprTypeSynPtr, &constExpr[0]);
-
-      if (tok == tokLogAnd)
-        s = sl && sr;
-      else
-        s = sl || sr;
-
-      *ExprTypeSynPtr = SymIntSynPtr;
-      *ConstExpr = constExpr[0] && constExpr[1];
-      if (constExpr[0])
-      {
-        if (tok == tokLogAnd)
-        {
-          if (!sl)
-            *ConstExpr = 1, s = 0;
-          // TBD??? else can drop LHS expression
-        }
-        else
-        {
-          if (sl)
-            *ConstExpr = s = 1;
-          // TBD??? else can drop LHS expression
-        }
-      }
-      simplifyConstExpr(s, *ConstExpr, ExprTypeSynPtr, oldIdxRight + 1 - (oldSpRight - sp), *idx + 1);
-    }
-    break;
-
-  // Function call
-  case ')':
-    {
-      int tmpSynPtr, c;
-      int minParams, maxParams;
-      int firstParamSynPtr;
-      int oldIdx, oldSp;
-
-      exprval(idx, ExprTypeSynPtr, ConstExpr);
-
-      if (!GetFxnInfo(*ExprTypeSynPtr, &minParams, &maxParams, ExprTypeSynPtr, &firstParamSynPtr))
-        //error("exprval(): function or function pointer expected\n");
-        errorOpType();
-
-      // DONE: validate the number of function arguments
-      // DONE: warnings on int<->pointer substitution in params/args
-
-
-
-      // evaluate function arguments
-      c = 0;
-      while (stack[*idx][0] != '(')
-      {
-
-        int ptrmask;
-
-
-        // add a comma after the first (last to be pushed) argument,
-        // so all arguments can be pushed whenever a comma is encountered
-        if (!c)
-          ins(*idx + 1, ',');
-
-        oldIdx = *idx;
-        oldSp = sp;
-        (void)oldIdx;
-        (void)oldSp;
-
-        exprval(idx, &tmpSynPtr, ConstExpr);
-        //error("exprval(): function arguments cannot be of type 'void'\n");
-
-        if (c >= maxParams)
-          error("Too many function arguments\n");
-
-        // Find the type of the formal parameter in the function declaration
-        if (c < minParams)
-        {
-          int t;
-          while ((t = SyntaxStack0[firstParamSynPtr]) != tokIdent)
-          {
-            if (t == '(')
-            {
-              // skip parameters in parameters
-              int c = 1;
-              while (c)
-              {
-                t = SyntaxStack0[++firstParamSynPtr];
-                c += (t == '(') - (t == ')');
-              }
-            }
-            firstParamSynPtr++;
-          }
-          firstParamSynPtr++;
-        }
-        else
-        {
-          firstParamSynPtr = SymVoidSynPtr;
-        }
-
-        ptrmask = isAnyPtr(firstParamSynPtr) * 2 + isAnyPtr(tmpSynPtr);
-        (void)ptrmask;
-
-        // Bar void and struct/union
-        scalarTypeCheck(tmpSynPtr);
-
-        // if there's a formal parameter for this argument, check the types
-        if (c < minParams)
-        {
-
-
-
-        }
-
-
-
-
-
-        c++;
-
-        if (stack[*idx][0] == ',')
-          --*idx;
-      }
-      --*idx;
-
-      if (c < minParams)
-        error("Too few function arguments\n");
-
-      // store the cumulative argument size in the function call operators
-      {
-        int i = oldIdxRight + 1 - (oldSpRight - sp);
-
-        stack[1 + *idx][1] = stack[i][1] = c * SizeOfWord;
-
-      }
-
-      *ConstExpr = 0;
-    }
-    break;
-
-  // Binary comma operator
-  case tokComma:
-    {
-      int oldIdxLeft, oldSpLeft;
-      int retStruct = 0;
-      s = exprval(idx, &RightExprTypeSynPtr, &constExpr[1]);
-      oldIdxLeft = *idx;
-      oldSpLeft = sp;
-
-      // Signify uselessness of the result of the left operand's value
-      ins(*idx + 1, tokVoid);
-
-      exprval(idx, ExprTypeSynPtr, &constExpr[0]);
-      *ConstExpr = constExpr[0] && constExpr[1];
-      *ExprTypeSynPtr = RightExprTypeSynPtr;
-      retStruct = RightExprTypeSynPtr >= 0 && SyntaxStack0[RightExprTypeSynPtr] == tokStructPtr;
-
-      if (*ConstExpr)
-      {
-        // both subexprs are const, remove both and comma
-        simplifyConstExpr(s, *ConstExpr, ExprTypeSynPtr, oldIdxRight + 1 - (oldSpRight - sp), *idx + 1);
-      }
-      else if (constExpr[0])
-      {
-        // only left subexpr is const, remove it
-        del(*idx + 1, oldIdxLeft - (oldSpLeft - sp) - *idx);
-
-        if (!retStruct)
-          // Ensure non-lvalue-ness of the result by changing comma to unary plus
-          // and thus hiding dereference, if any
-          stack[oldIdxRight + 1 - (oldSpRight - sp)][0] = tokUnaryPlus;
-        else
-          // However, (something, struct).member should still be allowed,
-          // so, comma needs to produce lvalue
-          del(oldIdxRight + 1 - (oldSpRight - sp), 1);
-      }
-      else if (retStruct)
-      {
-        // However, (something, struct).member should still be allowed,
-        // so, comma needs to produce lvalue. Swap comma and structure dereference.
-        int i = oldIdxRight + 1 - (oldSpRight - sp);
-        stack[i][0] = tokUnaryStar;
-        stack[i][1] = stack[i - 1][1];
-        stack[i - 1][0] = tokComma;
-      }
-    }
-    break;
-
-  // Compound assignment operators
-  case tokAssignMul: case tokAssignDiv: case tokAssignMod:
-  case tokAssignAdd: case tokAssignSub:
-  case tokAssignLSh: case tokAssignRSh:
-  case tokAssignAnd: case tokAssignXor: case tokAssignOr:
-    {
-      int ptrmask;
-      int oldIdxLeft, oldSpLeft;
-      int incSize;
-      int opSize;
-      int Unsigned;
-      int sr = exprval(idx, &RightExprTypeSynPtr, &constExpr[1]);
-      oldIdxLeft = *idx;
-      oldSpLeft = sp;
-      exprval(idx, ExprTypeSynPtr, &constExpr[0]);
-
-      lvalueCheck(*ExprTypeSynPtr, oldIdxLeft - (oldSpLeft - sp));
-
-      // if it's a pointer, ensure that it's suitable for pointer arithmetic
-      // (not pointer to function, pointee size is known and non-zero)
-      decayArray(ExprTypeSynPtr, 1); // no actual decay here, just a type check
-
-      // Bar void and struct/union
-      scalarTypeCheck(RightExprTypeSynPtr);
-      scalarTypeCheck(*ExprTypeSynPtr);
-
-
-
-      // "remove" the lvalue dereference as we don't need
-      // to read the value while forgetting its location.
-      // We need to keep the lvalue location.
-      // Remember the operand size.
-      opSize = stack[oldIdxLeft - (oldSpLeft - sp)][1];
-      // store the operand size in the operator
-      stack[oldIdxRight + 1 - (oldSpRight - sp)][1] = opSize;
-      del(oldIdxLeft - (oldSpLeft - sp), 1);
-
-      ptrmask = isAnyPtr(*ExprTypeSynPtr) * 2 + isAnyPtr(RightExprTypeSynPtr);
-
-      Unsigned = isUint(*ExprTypeSynPtr) * 2 + isUint(RightExprTypeSynPtr);
-
-      if (tok != tokAssignAdd && tok != tokAssignSub)
-      {
-        if (ptrmask)
-          //error("exprval(): invalid combination of operands for %s\n", GetTokenName(tok));
-          errorOpType();
-      }
-      else
-      {
-        // No pointer to the right of += and -=
-        if (ptrmask & 1)
-          //error("exprval(): invalid combination of operands for %s\n", GetTokenName(tok));
-          errorOpType();
-      }
-
-      if (tok == tokAssignLSh || tok == tokAssignRSh)
-      {
-        if (constExpr[1])
-        {
-          if (Unsigned & 1)
-            sr = (int)truncUint(sr);
-          else
-            sr = truncInt(sr);
-          shiftCountCheck(&sr, oldIdxRight - (oldSpRight - sp), RightExprTypeSynPtr);
-        }
-      }
-
-      if (tok == tokAssignDiv || tok == tokAssignMod)
-      {
-        int t, sl = 0;
-        if (tok == tokAssignDiv)
-          t = '/';
-        else
-          t = '%';
-        divCheckAndCalc(t, &sl, sr, 1, constExpr);
-      }
-
-      // TBD??? replace +=/-= with prefix ++/-- if incSize == 1
-      if (ptrmask == 2) // left-hand expression
-      {
-        incSize = GetDeclSize(derefAnyPtr(*ExprTypeSynPtr), 0);
-        if (constExpr[1])
-        {
-          int t = (int)(stack[oldIdxRight - (oldSpRight - sp)][1] * (unsigned)incSize);
-          stack[oldIdxRight - (oldSpRight - sp)][1] = t;
-        }
-        else if (incSize != 1)
-        {
-          ins2(oldIdxRight + 1 - (oldSpRight - sp), tokNumInt, incSize);
-          ins(oldIdxRight + 1 - (oldSpRight - sp), '*');
-        }
-      }
-      else if (Unsigned)
-      {
-        int t = tok;
-        switch (tok)
-        {
-        case tokAssignDiv: t = tokAssignUDiv; break;
-        case tokAssignMod: t = tokAssignUMod; break;
-        case tokAssignRSh:
-          if (Unsigned & 2)
-            t = tokAssignURSh;
-          break;
-        }
-        stack[oldIdxRight + 1 - (oldSpRight - sp)][0] = t;
-      }
-
-      *ConstExpr = 0;
-    }
-    break;
-
-  // Ternary/conditional operator
-  case '?':
-    {
-      int oldIdxLeft, oldSpLeft;
-      int oldIdxCond, oldSpCond;
-      int sr, sl, smid;
-      int condTypeSynPtr;
-      int sc = (LabelCnt += 2) - 2;
-      int structs;
-
-      // "exprL ? exprMID : exprR" appears on the stack as
-      // "exprL exprR exprMID ?"
-
-      // label at the end of ?:
-      stack[*idx + 1][0] = tokLogAnd; // piggyback on && for CG (ugly, but simple)
-      stack[*idx + 1][1] = sc + 1;
-
-      smid = exprval(idx, ExprTypeSynPtr, &constExpr[1]);
-
-      oldIdxLeft = *idx;
-      oldSpLeft = sp;
-      sr = exprval(idx, &RightExprTypeSynPtr, &constExpr[2]);
-
-      decayArray(&RightExprTypeSynPtr, 0);
-      decayArray(ExprTypeSynPtr, 0);
-      promoteType(&RightExprTypeSynPtr, ExprTypeSynPtr);
-      promoteType(ExprTypeSynPtr, &RightExprTypeSynPtr);
-
-      structs = (*ExprTypeSynPtr >= 0 && SyntaxStack0[*ExprTypeSynPtr] == tokStructPtr) * 2 +
-                (RightExprTypeSynPtr >= 0 && SyntaxStack0[RightExprTypeSynPtr] == tokStructPtr);
-
-
-      // TBD??? move struct/union-related checks into compatChecks()
-
-      if (structs)
-      {
-        if (structs != 3 ||
-            SyntaxStack1[RightExprTypeSynPtr] != SyntaxStack1[*ExprTypeSynPtr])
-          errorOpType();
-
-        // transform "cond ? a : b" into "*(cond ? &a : &b)"
-/*
-        if (stack[oldIdxLeft - (oldSpLeft - sp)][0] != tokUnaryStar ||
-            stack[oldIdxRight - (oldSpRight - sp)][0] != tokUnaryStar)
-          errorInternal(19);
-*/
-        del(oldIdxLeft - (oldSpLeft - sp), 1); // delete '*'
-        del(oldIdxRight - (oldSpRight - sp), 1); // delete '*'
-        oldSpLeft--;
-        // '*' will be inserted at the end
-      }
-      else
-      {
-        compatCheck(ExprTypeSynPtr,
-                    RightExprTypeSynPtr,
-                    &constExpr[1],
-                    oldIdxRight - (oldSpRight - sp),
-                    oldIdxLeft - (oldSpLeft - sp));
-      }
-
-      // label at the start of exprMID
-      ins2(oldIdxLeft + 1 - (oldSpLeft - sp), tokLogAnd, sc); // piggyback on && for CG (ugly, but simple)
-      // jump from the end of exprR over exprMID to the end of ?:
-      ins2(oldIdxLeft - (oldSpLeft - sp), tokGoto, sc + 1);
-      // jump to exprMID if exprL is non-zero
-      ins2(*idx + 1, tokShortCirc, -sc);
-
-      oldIdxCond = *idx;
-      oldSpCond = sp;
-      sl = exprval(idx, &condTypeSynPtr, &constExpr[0]);
-
-      // Bar void and struct/union
-      scalarTypeCheck(condTypeSynPtr);
-
-
-
-      *ConstExpr = s = 0;
-
-      if (constExpr[0])
-      {
-        int c1 = 0, c2 = 0;
-        // Stack now: exprL tokShortCirc exprR tokGoto tokLogAnd exprMID ?/tokLogAnd
-        if (
-
-              (truncUint(sl) != 0))
-        {
-          if (constExpr[1])
-          {
-            *ConstExpr = 1, s = smid;
-          }
-          else
-          {
-            // Drop exprL and exprR subexpressions
-            c1 = oldIdxLeft - (oldSpLeft - sp) - *idx; // includes tokShortCirc, tokGoto, tokLogAnd
-            c2 = 1; // include '?'/tokLogAnd
-          }
-        }
-        else
-        {
-          if (constExpr[2])
-          {
-            *ConstExpr = 1, s = sr;
-          }
-          else
-          {
-            // Drop exprL and exprMID subexpressions
-            c1 = oldIdxCond - (oldSpCond - sp) - *idx + 1; // includes tokShortCirc
-            c2 = (oldIdxRight - (oldSpRight - sp)) -
-                 (oldIdxLeft - (oldSpLeft - sp)) + 3; // includes tokGoto, tokLogAnd, '?'/tokLogAnd
-          }
-        }
-        if (c1)
-        {
-          int pos = oldIdxRight - (oldSpRight - sp) + 2 - c2;
-          if (!structs && stack[pos - 1][0] == tokUnaryStar)
-            stack[pos++][0] = tokUnaryPlus, c2--; // ensure non-lvalue-ness by hiding the dereference
-          del(pos, c2);
-          del(*idx + 1, c1);
-        }
-      }
-      // finish transforming "cond ? a : b" into "*(cond ? &a : &b)", insert '*'
-      if (structs)
-        ins2(oldIdxRight + 2 - (oldSpRight - sp), tokUnaryStar, 0); // use 0 deref size to drop meaningless dereferences
-      simplifyConstExpr(s, *ConstExpr, ExprTypeSynPtr, oldIdxRight + 1 - (oldSpRight - sp), *idx + 1);
-    }
-    break;
-
-  // Postfix indirect structure/union member selection operator
-  case tokArrow:
-    {
-      int member, i = 0, j = 0, c = 1, ofs = 0;
-
-      stack[*idx + 1][0] = '+'; // replace -> with +
-      member = stack[*idx][1]; // keep the member name, it will be replaced with member offset
-      stack[*idx][0] = tokNumInt;
-
-      --*idx;
-      exprval(idx, ExprTypeSynPtr, ConstExpr);
-
-      if (!isAnyPtr(*ExprTypeSynPtr) ||
-          SyntaxStack0[i = derefAnyPtr(*ExprTypeSynPtr)] != tokStructPtr)
-        error("Pointer to or structure or union expected\n");
-
-      i = SyntaxStack1[i];
-      if (i + 2 > SyntaxStackCnt ||
-          (SyntaxStack0[i] != tokStruct && SyntaxStack0[i] != tokUnion) ||
-          SyntaxStack0[i + 1] != tokTag)
-        errorInternal(20);
-
-      if (!GetDeclSize(i, 0))
-        // incomplete structure/union type
-        errorOpType();
-
-      i += 5; // step inside the {} body of the struct/union
-      while (c)
-      {
-        int t = SyntaxStack0[i];
-        c += (t == '(') - (t == ')') + (t == '{') - (t == '}');
-        if (c == 1 &&
-            t == tokMemberIdent && SyntaxStack1[i] == member &&
-            SyntaxStack0[i + 1] == tokLocalOfs)
-        {
-          j = i;
-          ofs = SyntaxStack1[i + 1];
-          break;
-        }
-        i++;
-      }
-      if (!j)
-        error("Undefined structure or union member '%s'\n", IdentTable + member);
-
-      j += 2;
-      // we cannot insert another '*' into the type to make it a pointer,
-      // so make the index into the type negative
-      *ExprTypeSynPtr = -j; // type: pointer to member's type
-
-      stack[oldIdxRight - (oldSpRight - sp)][1] = ofs; // member offset within structure/union
-
-      // optimize a little, if possible
-      {
-        int i = oldIdxRight - (oldSpRight - sp) - 1;
-        // Skip any type cast markers
-        while (stack[i][0] == tokUnaryPlus)
-          i--;
-        // See if the pointer is an integer constant or a local variable offset
-        // and if it is, adjust it here instead of generating code for
-        // addition/subtraction
-        if (stack[i][0] == tokNumInt || stack[i][0] == tokNumUint || stack[i][0] == tokLocalOfs)
-        {
-          stack[i][1] = (int)((unsigned)stack[i][1] + ofs); // TBD!!! need extra truncation?
-          del(oldIdxRight - (oldSpRight - sp), 2);
-        }
-      }
-
-      *ConstExpr = 0;
-    }
-    break;
-
-  default:
-    //error("exprval(): Unexpected token %s\n", GetTokenName(tok));
-    errorInternal(21);
-  }
-
-  return s;
-}
-
-STATIC
-int ParseExpr(int tok, int* GotUnary, int* ExprTypeSynPtr, int* ConstExpr, int* ConstVal, int option, int option2)
-{
-  int identFirst = tok == tokIdent;
-
-  *ConstVal = *ConstExpr = 0;
-  *ExprTypeSynPtr = SymVoidSynPtr;
-
-  if (!ExprLevel++)
-  {
-    opsp = sp = 0;
-  }
-
-  if (option == '=')
-    push2(tokIdent, option2);
-
-  tok = expr(tok, GotUnary, option == ',' || option == '=');
-
-  if (tok == tokEof || strchr(",;:)]}", tok) == NULL)
-    //error("ParseExpr(): Unexpected token %s\n", GetTokenName(tok));
-    errorUnexpectedToken(tok);
-
-  if (option == '=')
-  {
-    push('=');
-  }
-  else if (option == tokGotoLabel && identFirst && tok == ':' && *GotUnary && sp == 1 && stack[sp - 1][0] == tokIdent)
-  {
-    // This is a label.
-    ExprLevel--;
-    return tokGotoLabel;
-  }
-
-  if (*GotUnary)
-  {
-    int j;
-    // Do this twice so we can see the stack before
-    // and after manipulations
-    for (j = 0; j < 2; j++)
-    {
-
-      int i;
-      GenStartCommentLine();
-      if (j) printf2("Expanded");
-      else printf2("RPN'ized");
-      printf2(" expression: \"");
-      for (i = 0; i < sp; i++)
-      {
-        int tok = stack[i][0];
-        switch (tok)
-        {
-        case tokNumInt:
-          printf2("%d", truncInt(stack[i][1]));
-          break;
-        case tokNumUint:
-          printf2("%uu", truncUint(stack[i][1]));
-          break;
-
-        case tokIdent:
-          {
-            char* p = IdentTable + stack[i][1];
-            if (isdigit(*p))
-              printf2("L");
-            printf2("%s", p);
-          }
-          break;
-        case tokShortCirc:
-          if (stack[i][1] >= 0)
-            printf2("[sh&&->%d]", stack[i][1]);
-          else
-            printf2("[sh||->%d]", -stack[i][1]);
-          break;
-        case tokLocalOfs:
-          printf2("(@%d)", truncInt(stack[i][1]));
-          break;
-        case tokUnaryStar:
-          if (j) printf2("*(%d)", stack[i][1]);
-          else printf2("*u");
-          break;
-        case '(': case ',':
-          if (!j) printf2("%c", tok);
-          // else printf2("\b");
-          break;
-        case ')':
-          if (j) printf2("(");
-          printf2("%c", tok);
-          if (j) printf2("%d", stack[i][1]);
-          break;
-        default:
-          printf2("%s", GetTokenName(tok));
-          if (j)
-          {
-            switch (tok)
-            {
-            case tokLogOr: case tokLogAnd:
-              printf2("[%d]", stack[i][1]);
-              break;
-            case '=':
-            case tokInc: case tokDec:
-            case tokPostInc: case tokPostDec:
-            case tokAssignAdd: case tokAssignSub:
-            case tokPostAdd: case tokPostSub:
-            case tokAssignMul:
-            case tokAssignDiv: case tokAssignMod:
-            case tokAssignUDiv: case tokAssignUMod:
-            case tokAssignLSh: case tokAssignRSh: case tokAssignURSh:
-            case tokAssignAnd: case tokAssignXor: case tokAssignOr:
-              printf2("(%d)", stack[i][1]);
-              break;
-            }
-          }
-          break;
-        }
-        printf2(" ");
-      }
-      printf2("\"\n");
-
-      if (!j)
-      {
-        int idx = sp - 1;
-        *ConstVal = exprval(&idx, ExprTypeSynPtr, ConstExpr);
-        // remove the unneeded unary +'s that have served their cast-substitute purpose
-        // also remove dereferences of size 0 (dereferences of pointers to structures)
-        for (idx = sp - 1; idx >= 0; idx--)
-          if (stack[idx][0] == tokUnaryPlus ||
-              (stack[idx][0] == tokUnaryStar && !stack[idx][1]))
-            del(idx, 1);
-      }
-      else if (*ConstExpr)
-      {
-        GenStartCommentLine();
-
-        switch (SyntaxStack0[*ExprTypeSynPtr])
-        {
-        case tokChar:
-        case tokSChar:
-        case tokUChar:
-        case tokShort:
-        case tokUShort:
-        case tokInt:
-          printf2("Expression value: %d\n", truncInt(*ConstVal));
-          break;
-
-        default:
-        case tokUnsigned:
-          printf2("Expression value: %uu\n", truncUint(*ConstVal));
-          break;
-        }
-      }
-
-    }
-  }
-
-  ExprLevel--;
-
-
-  return tok;
-}
-
-// smc.c code
-
-
-// Equivalent to puts() but outputs to OutFile.
-STATIC
-int puts2(char* s)
-{
-  int res;
-  if (!OutFile)
-    return 0;
-  // Turbo C++ 1.01's fputs() returns EOF if s is empty, which is wrong.
-  // Hence the workaround.
-  if (*s == '\0' || (res = fputs(s, OutFile)) >= 0)
-  {
-    // unlike puts(), fputs() doesn't append '\n', append it manually
-    res = fputc('\n', OutFile);
-  }
-  return res;
-}
-
-// Equivalent to printf() but outputs to OutFile.
-STATIC
-int printf2(char* format, ...)
-{
-  int res;
-
-
-  void* vl = &format + 1;
-
-  if (!OutFile)
-    return 0;
-
-  // TBD!!! This is not good. Really need the va_something macros.
-  {
-    // va_list is a pointer
-    res = vfprintf(OutFile, format, vl);
-  }
-
-
-  return res;
-}
-
-STATIC
-void error(char* format, ...)
-{
-  int i, fidx = FileCnt - 1 + !FileCnt;
-  void* vl = &format + 1;
-
-  for (i = 0; i < FileCnt; i++)
-    if (Files[i])
-      fclose(Files[i]);
-
-  puts2("");
-
-  DumpSynDecls();
-  DumpMacroTable();
-  DumpIdentTable();
-
-  // using stdout implicitly instead of stderr explicitly because:
-  // - stderr can be a macro and it's unknown if standard headers
-  //   aren't included (which is the case when SmallerC is compiled
-  //   with itself and linked with some other compiler's standard
-  //   libraries)
-  // - output to stderr can interfere/overlap with buffered
-  //   output to stdout and the result may literally look ugly
-
-  GenStartCommentLine(); printf2("Compilation failed.\n");
-
-  if (OutFile)
-    fclose(OutFile);
-
-  printf("Error in \"%s\" (%d:%d)\n", FileNames[fidx], LineNo, LinePos);
-
-
-  // TBD!!! This is not good. Really need the va_something macros.
-  {
-    // va_list is a pointer
-    vprintf(format, vl);
-  }
-
-  va_end(vl);
-
-  exit(EXIT_FAILURE);
-}
-
-STATIC
-void warning(char* format, ...)
-{
-  int fidx = FileCnt - 1 + !FileCnt;
-  void* vl = &format + 1;
-
-  warnCnt++;
-
-  if (!warnings)
-    return;
-
-  printf("Warning in \"%s\" (%d:%d)\n", FileNames[fidx], LineNo, LinePos);
-
-  // TBD!!! This is not good. Really need the va_something macros.
-  {
-    // va_list is a pointer
-    vprintf(format, vl);
-  }
-
-}
-
-STATIC
-void errorFile(char* n)
-{
-  error("Unable to open, read, write or close file \"%s\"\n", n);
-}
-
-STATIC
-void errorFileName(void)
-{
-  error("Invalid or too long file name or path name\n");
-}
-
-STATIC
-void errorInternal(int n)
-{
-  error("%d (internal)\n", n);
-}
-
-STATIC
-void errorChrStr(void)
-{
-  error("Invalid or unsupported character constant or string literal\n");
-}
-
-
-STATIC
-void errorStrLen(void)
-{
-  error("String literal too long\n");
-}
-
-STATIC
-void errorUnexpectedToken(int tok)
-{
-  error("Unexpected token %s\n", (tok == tokIdent) ? TokenIdentName : GetTokenName(tok));
-}
-
-STATIC
-void errorDirective(void)
-{
-  error("Invalid or unsupported preprocessor directive\n");
-}
-
-STATIC
-void errorCtrlOutOfScope(void)
-{
-  error("break, continue, case or default in wrong scope\n");
-}
-
-STATIC
-void errorDecl(void)
-{
-  error("Invalid or unsupported declaration\n");
-}
-
-STATIC
-void errorTagRedef(int ident)
-{
-  error("Redefinition of type tagged '%s'\n", IdentTable + ident);
-}
-
-STATIC
-void errorVarSize(void)
-{
-  error("Variable(s) take(s) too much space\n");
-}
-
-STATIC
-void errorInit(void)
-{
-  error("Invalid or unsupported initialization\n");
-}
-
-STATIC
-void errorUnexpectedVoid(void)
-{
-  error("Unexpected declaration or expression of type void\n");
-}
-
-STATIC
-void errorOpType(void)
-{
-  error("Unexpected operand type\n");
-}
-
-STATIC
-void errorNotLvalue(void)
-{
-  error("lvalue expected\n");
-}
-
-STATIC
-void errorNotConst(void)
-{
-  error("Non-constant expression\n");
-}
-
-STATIC
-void errorLongExpr(void)
-{
-  error("Expression too long\n");
-}
-
-
-int tsd[] =
-{
-  tokVoid, tokChar, tokInt,
-  tokSigned, tokUnsigned, tokShort,
-  tokStruct, tokUnion,
-};
-
-STATIC
-int TokenStartsDeclaration(int t, int params)
-{
-  unsigned i;
-
-  for (i = 0; i < division(sizeof tsd, sizeof tsd[0]); i++)
-    if (tsd[i] == t)
-      return 1;
-
-  return
-         (SizeOfWord != 2 && t == tokLong) ||
-         (!params && (t == tokExtern ||
-                      t == tokStatic));
-}
-
-STATIC
-void PushSyntax2(int t, int v)
-{
-  if (SyntaxStackCnt >= SYNTAX_STACK_MAX)
-    error("Symbol table exhausted\n");
-  SyntaxStack0[SyntaxStackCnt] = t;
-  SyntaxStack1[SyntaxStackCnt++] = v;
-}
-
-STATIC
-void PushSyntax(int t)
-{
-  PushSyntax2(t, 0);
-}
-
-STATIC
-void InsertSyntax2(int pos, int t, int v)
-{
-  if (SyntaxStackCnt >= SYNTAX_STACK_MAX)
-    error("Symbol table exhausted\n");
-  memmove(&SyntaxStack0[pos + 1],
-          &SyntaxStack0[pos],
-          sizeof(SyntaxStack0[0]) * (SyntaxStackCnt - pos));
-  memmove(&SyntaxStack1[pos + 1],
-          &SyntaxStack1[pos],
-          sizeof(SyntaxStack1[0]) * (SyntaxStackCnt - pos));
-  SyntaxStack0[pos] = t;
-  SyntaxStack1[pos] = v;
-  SyntaxStackCnt++;
-}
-
-STATIC
-void InsertSyntax(int pos, int t)
-{
-  InsertSyntax2(pos, t, 0);
-}
-
-STATIC
-void DeleteSyntax(int pos, int cnt)
-{
-  memmove(&SyntaxStack0[pos],
-          &SyntaxStack0[pos + cnt],
-          sizeof(SyntaxStack0[0]) * (SyntaxStackCnt - (pos + cnt)));
-  memmove(&SyntaxStack1[pos],
-          &SyntaxStack1[pos + cnt],
-          sizeof(SyntaxStack1[0]) * (SyntaxStackCnt - (pos + cnt)));
-  SyntaxStackCnt -= cnt;
-}
-
-STATIC
-int FindSymbol(char* s)
-{
-  int i;
-
-  // TBD!!! return declaration scope number so
-  // redeclarations can be reported if occur in the same scope.
-
-  // TBD??? Also, I could first use FindIdent() and then just look for the
-  // index into IdentTable[] instead of doing strcmp()
-
-  for (i = SyntaxStackCnt - 1; i >= 0; i--)
-  {
-    int t = SyntaxStack0[i];
-    if (t == tokIdent &&
-        !strcmp(IdentTable + SyntaxStack1[i], s))
-    {
-      return i;
-    }
-
-    if (t == ')')
-    {
-      // Skip over the function params
-      int c = -1;
-      while (c)
-      {
-        t = SyntaxStack0[--i];
-        c += (t == '(') - (t == ')');
-      }
-    }
-  }
-
-  return -1;
-}
-
-STATIC
-int SymType(int SynPtr)
-{
-  int local = 0;
-
-  if (SyntaxStack0[SynPtr] == tokIdent)
-    SynPtr++;
-
-  if ((local = SyntaxStack0[SynPtr] == tokLocalOfs) != 0)
-    SynPtr++;
-
-  switch (SyntaxStack0[SynPtr])
-  {
-  case '(':
-    return SymFxn;
-
-  case '[':
-    if (local)
-      return SymLocalArr;
-    return SymGlobalArr;
-
-  default:
-    if (local)
-      return SymLocalVar;
-    return SymGlobalVar;
-  }
-}
-
-STATIC
-int FindTaggedDecl(char* s, int start, int* CurScope)
-{
-  int i;
-
-  *CurScope = 1;
-
-  for (i = start; i >= 0; i--)
-  {
-    int t = SyntaxStack0[i];
-    if (t == tokTag &&
-        !strcmp(IdentTable + SyntaxStack1[i], s))
-    {
-      return i - 1;
-    }
-    else if (t == ')')
-    {
-      // Skip over the function params
-      int c = -1;
-      while (c)
-      {
-        t = SyntaxStack0[--i];
-        c += (t == '(') - (t == ')');
-      }
-    }
-    else if (t == '#')
-    {
-      // the scope has changed to the outer scope
-      *CurScope = 0;
-    }
-  }
-
-  return -1;
-}
-
-
-STATIC
-int GetDeclSize(int SyntaxPtr, int SizeForDeref)
-{
-  int i;
-  unsigned size = 1;
-  int arr = 0;
-
-  if (SyntaxPtr < 0) // pointer?
-    return SizeOfWord;
-
-  for (i = SyntaxPtr; i < SyntaxStackCnt; i++)
-  {
-    int tok = SyntaxStack0[i];
-    switch (tok)
-    {
-    case tokIdent: // skip leading identifiers, if any
-    case tokLocalOfs: // skip local var offset, too
-      break;
-    case tokChar:
-    case tokSChar:
-      if (!arr && ((tok == tokSChar) || CharIsSigned) && SizeForDeref)
-        return -1; // 1 byte, needing sign extension when converted to int/unsigned int
-      // fallthrough
-    case tokUChar:
-      return (int)size;
-    case tokShort:
-      if (!arr && SizeForDeref)
-        return -2; // 2 bytes, needing sign extension when converted to int/unsigned int
-      // fallthrough
-    case tokUShort:
-      //if (size * 2 / 2 != size)
-        //error("Variable too big\n");
-      //  errorVarSize();
-      size *= 2;
-      if (size != truncUint(size))
-        //error("Variable too big\n");
-        errorVarSize();
-      return (int)size;
-    case tokInt:
-    case tokUnsigned:
-    case '*':
-    case '(': // size of fxn = size of ptr for now
-      //if (size * SizeOfWord / SizeOfWord != size)
-        //error("Variable too big\n");
-        //errorVarSize();
-      size *= SizeOfWord;
-      if (size != truncUint(size))
-        //error("Variable too big\n");
-        errorVarSize();
-      return (int)size;
-    case '[':
-      if (SyntaxStack0[i + 1] != tokNumInt && SyntaxStack0[i + 1] != tokNumUint)
-        errorInternal(11);
-      //if (SyntaxStack1[i + 1] &&
-          //size * SyntaxStack1[i + 1] / SyntaxStack1[i + 1] != size)
-        //error("Variable too big\n");
-        //errorVarSize();
-      size *= SyntaxStack1[i + 1];
-      if (size != truncUint(size))
-        //error("Variable too big\n");
-        errorVarSize();
-      i += 2;
-      arr = 1;
-      break;
-    case tokStructPtr:
-      // follow the "type pointer"
-      i = SyntaxStack1[i] - 1;
-      break;
-    case tokStruct:
-    case tokUnion:
-      if (i + 2 < SyntaxStackCnt && SyntaxStack0[i + 2] == tokSizeof && !SizeForDeref)
-      {
-        unsigned s = SyntaxStack1[i + 2];
-        //if (s && size * s / s != size)
-        //  errorVarSize();
-        size *= s;
-        if (size != truncUint(size))
-          errorVarSize();
-        return (int)size;
-      }
-      return 0;
-    case tokVoid:
-      return 0;
-    default:
-      errorInternal(12);
-    }
-  }
-
-  errorInternal(13);
-  return 0;
-}
-
-STATIC
-int GetDeclAlignment(int SyntaxPtr)
-{
-  int i;
-
-  if (SyntaxPtr < 0) // pointer?
-    return SizeOfWord;
-
-  for (i = SyntaxPtr; i < SyntaxStackCnt; i++)
-  {
-    int tok = SyntaxStack0[i];
-    switch (tok)
-    {
-    case tokIdent: // skip leading identifiers, if any
-    case tokLocalOfs: // skip local var offset, too
-      break;
-    case tokChar:
-    case tokSChar:
-    case tokUChar:
-      return 1;
-
-    case tokShort:
-    case tokUShort:
-      return 2;
-
-    case tokInt:
-    case tokUnsigned:
-    case '*':
-    case '(':
-      return SizeOfWord;
-    case '[':
-      if (SyntaxStack0[i + 1] != tokNumInt && SyntaxStack0[i + 1] != tokNumUint)
-        errorInternal(15);
-      i += 2;
-      break;
-    case tokStructPtr:
-      // follow the "type pointer"
-      i = SyntaxStack1[i] - 1;
-      break;
-    case tokStruct:
-    case tokUnion:
-      if (i + 3 < SyntaxStackCnt && SyntaxStack0[i + 2] == tokSizeof)
-      {
-        return SyntaxStack1[i + 3];
-      }
-      return 1;
-    case tokVoid:
-      return 1;
-    default:
-      errorInternal(16);
-    }
-  }
-
-  errorInternal(17);
-  return 0;
-}
-
-
-STATIC
-void DumpDecl(int SyntaxPtr, int IsParam)
-{
-  int i;
-  int icnt = 0;
-
-  if (SyntaxPtr < 0)
-    return;
-
-  for (i = SyntaxPtr; i < SyntaxStackCnt; i++)
-  {
-    int tok = SyntaxStack0[i];
-    int v = SyntaxStack1[i];
-    switch (tok)
-    {
-    case tokLocalOfs:
-      printf2("(@%d) : ", truncInt(v));
-      break;
-
-    case tokIdent:
-      if (++icnt > 1 && !IsParam) // show at most one declaration, except params
-        return;
-
-      GenStartCommentLine();
-
-      if (ParseLevel == 0)
-        printf2("glb ");
-      else if (IsParam)
-        printf2("prm ");
-      else
-        printf2("loc ");
-
-      {
-        int j;
-        for (j = 0; j < ParseLevel * 4; j++)
-          printf2(" ");
-      }
-
-      if (IsParam && !strcmp(IdentTable + v, "<something>") && (i + 1 < SyntaxStackCnt))
-      {
-        if (SyntaxStack0[i + 1] == tokEllipsis)
-          continue;
-      }
-
-      printf2("%s : ", IdentTable + v);
-      if (!IsParam && (i + 1 < SyntaxStackCnt) && SyntaxStack0[i + 1] == tokIdent)
-      {
-        // renamed local static variable
-        GenPrintLabel(IdentTable + SyntaxStack1[++i]);
-        printf2(" : ");
-      }
-      break;
-
-    case '[':
-      printf2("[");
-      break;
-
-    case tokNumInt:
-      printf2("%d", truncInt(v));
-      break;
-    case tokNumUint:
-      printf2("%uu", truncUint(v));
-      break;
-
-    case ']':
-      printf2("] ");
-      break;
-
-    case '(':
-      {
-        int noparams;
-        // Skip over the params to the base type
-        int j = ++i, c = 1;
-        while (c)
-        {
-          int t = SyntaxStack0[j++];
-          c += (t == '(') - (t == ')');
-        }
-
-        noparams = (i + 1 == j) || (SyntaxStack0[i + 1] == tokVoid);
-
-        printf2("(");
-
-        // Print the params (recursively)
-        if (noparams)
-        {
-          // Don't recurse if it's "fxn()" or "fxn(void)"
-          if (i + 1 != j)
-            printf2("void");
-        }
-        else
-        {
-          puts2("");
-          ParseLevel++;
-          DumpDecl(i, 1);
-          ParseLevel--;
-        }
-
-        // Continue normally
-        i = j - 1;
-        if (!noparams)
-        {
-          GenStartCommentLine();
-          printf2("    ");
-          {
-            int j;
-            for (j = 0; j < ParseLevel * 4; j++)
-              printf2(" ");
-          }
-        }
-
-        printf2(") ");
-      }
-      break;
-
-    case ')': // end of param list
-      return;
-
-    case tokStructPtr:
-      DumpDecl(v, 0);
-      break;
-
-    default:
-      switch (tok)
-      {
-      case tokVoid:
-      case tokChar:
-      case tokSChar:
-      case tokUChar:
-      case tokShort:
-      case tokUShort:
-      case tokInt:
-      case tokUnsigned:
-      case tokEllipsis:
-        printf2("%s\n", GetTokenName(tok));
-        break;
-      default:
-        printf2("%s ", GetTokenName(tok));
-        break;
-      case tokTag:
-        printf2("%s\n", IdentTable + v);
-        return;
-      }
-      break;
-    }
-  }
-}
-
-STATIC
-void DumpSynDecls(void)
-{
-  int used = SyntaxStackCnt * (sizeof SyntaxStack0[0] + sizeof SyntaxStack1[0]);
-  int total = SYNTAX_STACK_MAX * (sizeof SyntaxStack0[0] + sizeof SyntaxStack1[0]);
-  puts2("");
-  GenStartCommentLine(); printf2("Syntax/declaration table/stack:\n");
-  GenStartCommentLine(); printf2("Bytes used: %d/%d\n\n", used, total);
-}
-
-
-STATIC
-int ParseArrayDimension(int AllowEmptyDimension)
-{
-  int tok;
-  int gotUnary, synPtr, constExpr, exprVal;
-  unsigned exprValU;
-  int oldssp, oldesp, undoIdents;
-
-  tok = GetToken();
-  // DONE: support arbitrary constant expressions
-  oldssp = SyntaxStackCnt;
-  oldesp = sp;
-  undoIdents = IdentTableLen;
-  tok = ParseExpr(tok, &gotUnary, &synPtr, &constExpr, &exprVal, 0, 0);
-  IdentTableLen = undoIdents; // remove all temporary identifier names from e.g. "sizeof"
-  SyntaxStackCnt = oldssp; // undo any temporary declarations from e.g. "sizeof" in the expression
-  sp = oldesp;
-
-  if (tok != ']')
-    //error("ParseArrayDimension(): Unsupported or invalid array dimension (token %s)\n", GetTokenName(tok));
-    errorUnexpectedToken(tok);
-
-  if (!gotUnary)
-  {
-    if (!AllowEmptyDimension)
-      //error("ParseArrayDimension(): missing array dimension\n");
-      errorUnexpectedToken(tok);
-    // Empty dimension is dimension of 0
-    exprVal = 0;
-  }
-  else
-  {
-    if (!constExpr)
-      //error("ParseArrayDimension(): non-constant array dimension\n");
-      errorNotConst();
-
-    exprValU = truncUint(exprVal);
-    exprVal = truncInt(exprVal);
-
-    promoteType(&synPtr, &synPtr);
-    anyIntTypeCheck(synPtr);
-    if ((SyntaxStack0[synPtr] == tokInt && exprVal < 1) || (SyntaxStack0[synPtr] == tokUnsigned && exprValU < 1))
-      error("Array dimension less than 1\n");
-
-    exprVal = (int)exprValU;
-  }
-
-  PushSyntax2(tokNumUint, exprVal);
-  return tok;
-}
-
-STATIC
-void ParseFxnParams(int tok);
-static int BrkCntTargetFxn[2];
-STATIC
-int ParseBlock(int BrkCntTarget[2], int casesIdx);
-STATIC
-void AddFxnParamSymbols(int SyntaxPtr);
-STATIC
-void CheckRedecl(int lastSyntaxPtr);
-
-STATIC
-int ParseBase(int tok, int base[2])
-{
-  int valid = 1;
-  base[1] = 0;
-
-  switch (tok)
-  {
-  case tokVoid:
-    *base = tok;
-    tok = GetToken();
-    break;
-
-  case tokChar:
-  case tokInt:
-  case tokShort:
-  case tokLong:
-  case tokSigned:
-  case tokUnsigned:
-  {
-    int allowedMask = 0x7F; // double:0x40 unsigned:0x20 signed:0x10 long:0x08 int:0x04 short:0x02 char:0x01
-    int typeMask = 0;
-    int tokMask, disallowedMask;
-
-lcont:
-    switch (tok)
-    {
-    case tokChar:
-      tokMask = 0x01; disallowedMask = 0x4E; break; // disallows double, long, int, short
-    case tokShort:
-      tokMask = 0x02; disallowedMask = 0x49; break; // disallows double, long, char
-    case tokInt:
-      tokMask = 0x04; disallowedMask = 0x41; break; // disallows double, char
-    case tokLong:
-      tokMask = 0x08; disallowedMask = 0x03; break; // disallows short, char
-    case tokSigned:
-      tokMask = 0x10; disallowedMask = 0x60; break; // disallows double, unsigned
-    case tokUnsigned:
-      tokMask = 0x20; disallowedMask = 0x50; break; // disallows double, signed
-    default:
-      tokMask = disallowedMask = 0; break;
-    }
-
-    if (allowedMask & tokMask)
-    {
-      typeMask |= tokMask;
-      allowedMask &= ~(disallowedMask | tokMask);
-      tok = GetToken();
-      goto lcont;
-    }
-
-    switch (typeMask)
-    {
-    case 0x01: typeMask = tokChar; break;
-    case 0x11: typeMask = tokSChar; break;
-    case 0x21: typeMask = tokUChar; break;
-    case 0x02: case 0x12: case 0x06: case 0x16: typeMask = tokShort; break;
-    case 0x22: case 0x26: typeMask = tokUShort; break;
-    case 0x04: case 0x10: case 0x14: typeMask = tokInt; break;
-    case 0x20: case 0x24: typeMask = tokUnsigned; break;
-    case 0x08: case 0x18: case 0x0C: case 0x1C: typeMask = tokLong; break;
-    case 0x28: case 0x2C: typeMask = tokULong; break;
-
-    default:
-      errorDecl();
-    }
-    *base = typeMask;
-  }
-    break;
-
-  case tokStruct:
-  case tokUnion:
-  {
-    int structType = tok;
-    int empty = 1;
-    int typePtr = SyntaxStackCnt;
-    int gotTag = 0, tagIdent = 0, declPtr = -1, curScope = 0;
-
-    tok = GetToken();
-
-    if (tok == tokIdent)
-    {
-      // this is a structure/union/enum tag
-      gotTag = 1;
-      declPtr = FindTaggedDecl(TokenIdentName, SyntaxStackCnt - 1, &curScope);
-      tagIdent = AddIdent(TokenIdentName);
-
-      if (declPtr >= 0)
-      {
-        // Within the same scope we can't declare more than one union, structure or enum
-        // with the same tag.
-        // There's one common tag namespace for structures, unions and enumerations.
-        if (curScope && SyntaxStack0[declPtr] != structType)
-          errorTagRedef(tagIdent);
-      }
-      else if (ParamLevel)
-      {
-        // new structure/union/enum declarations aren't supported in function parameters
-        errorDecl();
-      }
-
-      tok = GetToken();
-    }
-    else
-    {
-      // structure/union/enum declarations aren't supported in expressions
-      if (ExprLevel)
-        errorDecl();
-      PushSyntax(structType);
-      PushSyntax2(tokTag, AddIdent("<something>"));
-    }
-
-    if (tok == '{')
-    {
-      unsigned structInfo[4], sz, alignment, tmp;
-
-      // new structure/union/enum declarations aren't supported in expressions and function parameters
-      if (ExprLevel || ParamLevel)
-        errorDecl();
-
-      if (gotTag)
-      {
-        // Cannot redefine a tagged structure/union/enum within the same scope
-        if (declPtr >= 0 &&
-            curScope &&
-            ((declPtr + 2 < SyntaxStackCnt && SyntaxStack0[declPtr + 2] == tokSizeof)
-
-            ))
-          errorTagRedef(tagIdent);
-
-        PushSyntax(structType);
-        PushSyntax2(tokTag, tagIdent);
-      }
-
-
-      {
-        structInfo[0] = structType;
-        structInfo[1] = 1; // initial member alignment
-        structInfo[2] = 0; // initial member offset
-        structInfo[3] = 0; // initial max member size (for unions)
-
-        PushSyntax(tokSizeof); // 0 = initial structure/union size, to be updated
-        PushSyntax2(tokSizeof, 1); // 1 = initial structure/union alignment, to be updated
-
-        PushSyntax('{');
-
-        tok = GetToken();
-        while (tok != '}')
-        {
-          if (!TokenStartsDeclaration(tok, 1))
-            errorUnexpectedToken(tok);
-          tok = ParseDecl(tok, structInfo, 0, 0);
-          empty = 0;
-        }
-
-        if (empty)
-          errorUnexpectedToken('}');
-
-        PushSyntax('}');
-
-        // Update structure/union alignment
-        alignment = structInfo[1];
-        SyntaxStack1[typePtr + 3] = alignment;
-
-        // Update structure/union size and include trailing padding if needed
-        sz = structInfo[2] + structInfo[3];
-        tmp = sz;
-        sz = (sz + alignment - 1) & ~(alignment - 1);
-        if (sz < tmp || sz != truncUint(sz))
-          errorVarSize();
-        SyntaxStack1[typePtr + 2] = (int)sz;
-
-        tok = GetToken();
-      }
-    }
-    else
-    {
-
-
-      if (gotTag)
-      {
-        if (declPtr >= 0 &&
-            SyntaxStack0[declPtr] == structType)
-        {
-          base[0] = tokStructPtr;
-          base[1] = declPtr;
-          return tok;
-        }
-
-        PushSyntax(structType);
-        PushSyntax2(tokTag, tagIdent);
-
-        empty = 0;
-      }
-    }
-
-    if (empty)
-      errorDecl();
-
-    base[0] = tokStructPtr;
-    base[1] = typePtr;
-
-    // If we've just defined a structure/union and there are
-    // preceding references to this tag within this scope,
-    // IOW references to an incomplete type, complete the
-    // type in the references
-    if (gotTag && SyntaxStack0[SyntaxStackCnt - 1] == '}')
-    {
-      int i;
-      for (i = SyntaxStackCnt - 1; i >= 0; i--)
-        if (SyntaxStack0[i] == tokStructPtr)
-        {
-          int j = SyntaxStack1[i];
-          if (SyntaxStack1[j + 1] == tagIdent && !GetDeclSize(i, 0))
-            SyntaxStack1[i] = typePtr;
-        }
-        else if (SyntaxStack0[i] == '#')
-        {
-          // reached the beginning of the current scope
-          break;
-        }
-    }
-  }
-    break;
-
-
-
-  default:
-    valid = 0;
-    break;
-  }
-
-
-  if (SizeOfWord == 2 &&
-      (*base == tokLong || *base == tokULong))
-    valid = 0;
-  // to simplify matters, treat long and unsigned long as aliases for int and unsigned int
-  // in 32-bit and huge mode(l)s
-  if (*base == tokLong)
-    *base = tokInt;
-  if (*base == tokULong)
-    *base = tokUnsigned;
-
-
-  if (SizeOfWord == 2)
-  {
-    // to simplify matters, treat short and unsigned short as aliases for int and unsigned int
-    // in 16-bit mode
-    if (*base == tokShort)
-      *base = tokInt;
-    if (*base == tokUShort)
-      *base = tokUnsigned;
-  }
-
-  // TBD!!! review/test this fxn
-//  if (!valid || !tok || !(strchr("*([,)", tok) || tok == tokIdent))
-  if (!valid | !tok)
-    //error("ParseBase(): Invalid or unsupported type\n");
-    error("Invalid or unsupported type\n");
-
-  return tok;
-}
-
-/*
-  base * name []  ->  name : [] * base
-  base *2 (*1 name []1) []2  ->  name : []1 *1 []2 *2 base
-  base *3 (*2 (*1 name []1) []2) []3  ->  name : []1 *1 []2 *2 []3 *3 base
-*/
-
-STATIC
-int ParseDerived(int tok)
-{
-  int stars = 0;
-  int params = 0;
-
-  while (tok == '*')
-  {
-    stars++;
-    tok = GetToken();
-  }
-
-
-
-  if (tok == '(')
-  {
-    tok = GetToken();
-    if (tok != ')' && !TokenStartsDeclaration(tok, 1))
-    {
-      tok = ParseDerived(tok);
-      if (tok != ')')
-        //error("ParseDerived(): ')' expected\n");
-        errorUnexpectedToken(tok);
-      tok = GetToken();
-    }
-    else
-    {
-      params = 1;
-    }
-  }
-  else if (tok == tokIdent)
-  {
-    PushSyntax2(tok, AddIdent(TokenIdentName));
-    tok = GetToken();
-  }
-  else
-  {
-    PushSyntax2(tokIdent, AddIdent("<something>"));
-  }
-
-  if (params | (tok == '('))
-  {
-    int t = SyntaxStack0[SyntaxStackCnt - 1];
-    if ((t == ')') | (t == ']'))
-      errorUnexpectedToken('('); // array of functions or function returning function
-    if (!params)
-      tok = GetToken();
-    else
-      PushSyntax2(tokIdent, AddIdent("<something>"));
-
-    PushSyntax('(');
-
-    ParseLevel++;
-    ParamLevel++;
-    ParseFxnParams(tok);
-    ParamLevel--;
-    ParseLevel--;
-    PushSyntax(')');
-    tok = GetToken();
-  }
-  else if (tok == '[')
-  {
-    // DONE!!! allow the first [] without the dimension in function parameters
-    int allowEmptyDimension = 1;
-    if (SyntaxStack0[SyntaxStackCnt - 1] == ')')
-      errorUnexpectedToken('['); // function returning array
-    while (tok == '[')
-    {
-      int oldsp = SyntaxStackCnt;
-      PushSyntax(tokVoid); // prevent cases like "int arr[arr];" and "int arr[arr[0]];"
-      PushSyntax(tok);
-      tok = ParseArrayDimension(allowEmptyDimension);
-      if (tok != ']')
-        //error("ParseDerived(): ']' expected\n");
-        errorUnexpectedToken(tok);
-      PushSyntax(']');
-      tok = GetToken();
-      DeleteSyntax(oldsp, 1);
-      allowEmptyDimension = 0;
-    }
-  }
-
-  while (stars--)
-    PushSyntax('*');
-
-  if (!tok || !strchr(",;{=)", tok))
-    //error("ParseDerived(): unexpected token %s\n", GetTokenName(tok));
-    errorUnexpectedToken(tok);
-
-  return tok;
-}
-
-STATIC
-void PushBase(int base[2])
-{
-  {
-    PushSyntax2(base[0], base[1]);
-  }
-
-  // Cannot have array of void
-  if (SyntaxStack0[SyntaxStackCnt - 1] == tokVoid &&
-      SyntaxStack0[SyntaxStackCnt - 2] == ']')
-    errorUnexpectedVoid();
-}
-
-STATIC
-int InitScalar(int synPtr, int tok);
-STATIC
-int InitArray(int synPtr, int tok);
-STATIC
-int InitStruct(int synPtr, int tok);
-
-STATIC
-int InitVar(int synPtr, int tok)
-{
-  int p = synPtr, t;
-  int undoIdents = IdentTableLen;
-
-  while ((t = SyntaxStack0[p]), (t == tokIdent) | (t == tokLocalOfs))
-    p++;
-
-  switch (t)
-  {
-  case '[':
-    // Initializers for aggregates must be enclosed in braces,
-    // except for arrays of char initialized with string literals,
-    // in which case braces are optional
-    if (tok != '{')
-    {
-      t = SyntaxStack0[p + 3];
-      if (((tok != tokLitStr) | ((t != tokChar) & (t != tokUChar) & (t != tokSChar)))
-         )
-        errorUnexpectedToken(tok);
-    }
-    tok = InitArray(p, tok);
-    break;
-  case tokStructPtr:
-    // Initializers for aggregates must be enclosed in braces
-    if (tok != '{')
-      errorUnexpectedToken(tok);
-    tok = InitStruct(p, tok);
-    break;
-  default:
-    tok = InitScalar(p, tok);
-    break;
-  }
-
-  if (!strchr(",;", tok))
-    errorUnexpectedToken(tok);
-
-  IdentTableLen = undoIdents; // remove all temporary identifier names from e.g. "sizeof" or "str"
-
-  return tok;
-}
-
-STATIC
-int InitScalar(int synPtr, int tok)
-{
-  unsigned elementSz = GetDeclSize(synPtr, 0);
-  int gotUnary, synPtr2, constExpr, exprVal;
-  int oldssp = SyntaxStackCnt;
-  int undoIdents = IdentTableLen;
-  int ttop;
-  int braces = 0;
-
-  // Initializers for scalars can be optionally enclosed in braces
-  if (tok == '{')
-  {
-    braces = 1;
-    tok = GetToken();
-  }
-
-  tok = ParseExpr(tok, &gotUnary, &synPtr2, &constExpr, &exprVal, ',', 0);
-
-  if (!gotUnary)
-    errorUnexpectedToken(tok);
-
-  if (braces)
-  {
-    if (tok != '}')
-      errorUnexpectedToken(tok);
-    tok = GetToken();
-  }
-
-  // Bar void and struct/union
-  scalarTypeCheck(synPtr2);
-
-
-  ttop = stack[sp - 1][0];
-  if (ttop == tokNumInt || ttop == tokNumUint)
-  {
-    int val = stack[sp - 1][1];
-    // TBD??? truncate values for types smaller than int (e.g. char and short),
-    // so they are always in range for the assembler?
-    GenIntData(elementSz, val);
-  }
-  else if (elementSz == (unsigned)SizeOfWord)
-  {
-    if (ttop == tokIdent)
-    {
-      GenAddrData(elementSz, IdentTable + stack[sp - 1][1], 0);
-    }
-    else if (ttop == '+' || ttop == '-')
-    {
-      int tleft = stack[sp - 3][0];
-      int tright = stack[sp - 2][0];
-      if (tleft == tokIdent &&
-          (tright == tokNumInt || tright == tokNumUint))
-      {
-        GenAddrData(elementSz, IdentTable + stack[sp - 3][1], (ttop == '+') ? stack[sp - 2][1] : -stack[sp - 2][1]);
-      }
-      else if (ttop == '+' &&
-               tright == tokIdent &&
-               (tleft == tokNumInt || tleft == tokNumUint))
-      {
-        GenAddrData(elementSz, IdentTable + stack[sp - 2][1], stack[sp - 3][1]);
-      }
-      else
-        errorNotConst();
-    }
-    else
-      errorNotConst();
-    // Defer storage of string literal data (if any) until the end.
-    // This will let us generate the contiguous array of pointers to
-    // string literals unperturbed by the string literal data
-    // (e.g. "char* colors[] = { "red", "green", "blue" };").
-  }
-  else
-    //error("ParseDecl(): cannot initialize a global variable with a non-constant expression\n");
-    errorNotConst();
-
-  IdentTableLen = undoIdents; // remove all temporary identifier names from e.g. "sizeof" or "str"
-  SyntaxStackCnt = oldssp; // undo any temporary declarations from e.g. "sizeof" or "str" in the expression
-  return tok;
-}
-
-STATIC
-int InitArray(int synPtr, int tok)
-{
-  int elementTypePtr = synPtr + 3;
-  int elementType = SyntaxStack0[elementTypePtr];
-  unsigned elementSz = GetDeclSize(elementTypePtr, 0);
-  int braces = 0;
-  unsigned elementCnt = 0;
-  unsigned elementsRequired = SyntaxStack1[synPtr + 1];
-  int arrOfChar = (elementType == tokChar) | (elementType == tokUChar) | (elementType == tokSChar);
-
-  if (tok == '{')
-  {
-    braces = 1;
-    tok = GetToken();
-  }
-
-  if ((arrOfChar & (tok == tokLitStr))
-     )
-  {
-    int ltok = tok;
-    unsigned sz = 0;
-    // this is 'someArray[someCountIfAny] = "some string"' or
-    // 'someArray[someCountIfAny] = { "some string" }'
-    do
-    {
-      GetString('"', 0, 'd');
-      if (sz + TokenStringSize < sz ||
-          sz + TokenStringSize >= truncUint(-1))
-        errorStrLen();
-      sz += TokenStringSize;
-      elementCnt += TokenStringLen;
-      tok = GetToken();
-    } while (tok == ltok); // concatenate adjacent string literals
-
-
-    if (elementsRequired && elementCnt > elementsRequired)
-      errorStrLen();
-
-    if (elementCnt < elementsRequired)
-      GenZeroData(elementsRequired - elementCnt, 0);
-
-    if (!elementsRequired)
-      GenZeroData(elementSz, 0), elementCnt++;
-
-    if (braces)
-    {
-      if (tok != '}')
-        errorUnexpectedToken(tok);
-      tok = GetToken();
-    }
-  }
-  else
-  {
-    while (tok != '}')
-    {
-      if (elementType == '[')
-      {
-        tok = InitArray(elementTypePtr, tok);
-      }
-      else if (elementType == tokStructPtr)
-      {
-        tok = InitStruct(elementTypePtr, tok);
-      }
-      else
-      {
-        tok = InitScalar(elementTypePtr, tok);
-      }
-
-      // Last element?
-      if (++elementCnt >= elementsRequired && elementsRequired)
-      {
-        if (braces & (tok == ','))
-          tok = GetToken();
-        break;
-      }
-
-      if (tok == ',')
-        tok = GetToken();
-      else if (tok != '}')
-        errorUnexpectedToken(tok);
-    }
-
-    if (braces)
-    {
-      if ((!elementCnt) | (tok != '}'))
-        errorUnexpectedToken(tok);
-      tok = GetToken();
-    }
-
-    if (elementCnt < elementsRequired)
-      GenZeroData((elementsRequired - elementCnt) * elementSz, 0);
-  }
-
-  // Store the element count if it's an incomplete array
-  if (!elementsRequired)
-    SyntaxStack1[synPtr + 1] = elementCnt;
-
-  return tok;
-}
-
-STATIC
-int InitStruct(int synPtr, int tok)
-{
-  int isUnion;
-  unsigned size, ofs = 0;
-  int braces = 0;
-  int c = 1;
-
-  synPtr = SyntaxStack1[synPtr];
-  isUnion = SyntaxStack0[synPtr++] == tokUnion;
-  size = SyntaxStack1[++synPtr];
-  synPtr += 3; // step inside the {} body of the struct/union
-
-  if (tok == '{')
-  {
-    braces = 1;
-    tok = GetToken();
-  }
-
-  // Find the first member
-  while (c)
-  {
-    int t = SyntaxStack0[synPtr];
-    c += (t == '(') - (t == ')') + (t == '{') - (t == '}');
-    if (c == 1 && t == tokMemberIdent)
-      break;
-    synPtr++;
-  }
-
-  while (tok != '}')
-  {
-    int c = 1;
-    int elementTypePtr, elementType;
-    unsigned elementOfs, elementSz;
-
-    elementOfs = SyntaxStack1[++synPtr];
-    elementTypePtr = ++synPtr;
-    elementType = SyntaxStack0[elementTypePtr];
-    elementSz = GetDeclSize(elementTypePtr, 0);
-
-    // Alignment
-    if (ofs < elementOfs)
-      GenZeroData(elementOfs - ofs, 0);
-
-    if (elementType == '[')
-    {
-      tok = InitArray(elementTypePtr, tok);
-    }
-    else if (elementType == tokStructPtr)
-    {
-      tok = InitStruct(elementTypePtr, tok);
-    }
-    else
-    {
-      tok = InitScalar(elementTypePtr, tok);
-    }
-
-    ofs = elementOfs + elementSz;
-
-    // Find the next member or the closing brace
-    while (c)
-    {
-      int t = SyntaxStack0[synPtr];
-      c += (t == '(') - (t == ')') + (t == '{') - (t == '}');
-      if (c == 1 && t == tokMemberIdent)
-        break;
-      synPtr++;
-    }
-
-    // Last member?
-    // Only one member (first) is initialized in unions explicitly
-    if ((!c) | isUnion)
-    {
-      if (braces & (tok == ','))
-        tok = GetToken();
-      break;
-    }
-
-    if (tok == ',')
-      tok = GetToken();
-    else if (tok != '}')
-      errorUnexpectedToken(tok);
-  }
-
-  if (braces)
-  {
-    if ((!ofs) | (tok != '}'))
-      errorUnexpectedToken(tok);
-    tok = GetToken();
-  }
-
-  // Implicit initialization of the rest and trailing padding
-  if (ofs < size)
-    GenZeroData(size - ofs, 0);
-
-  return tok;
-}
-
-STATIC
-int compatCheck2(int lastSyntaxPtr, int i)
-{
-  int res = 0;
-  int c = 0;
-  int t;
-  for (;;)
-  {
-    t = SyntaxStack0[lastSyntaxPtr];
-    if (t != SyntaxStack0[i])
-    {
-      if (SyntaxStack0[i] == ')' && SyntaxStack0[i - 1] == '(')
-      {
-        // Complete a previously incomplete parameter specification
-        int c1 = 1;
-        // Skip over the function params
-        do
-        {
-          t = SyntaxStack0[lastSyntaxPtr++];
-          c1 += (t == '(') - (t == ')');
-        } while (c1);
-        lastSyntaxPtr--;
-      }
-      else if (t == ')' &&
-               SyntaxStack0[i - 1] == '(' && SyntaxStack0[i] == tokIdent &&
-               SyntaxStack0[i + 1] == tokVoid && SyntaxStack0[i + 2] == ')')
-      {
-        // As an exception allow foo(void) to be redeclared as foo()
-        // since this happens very often in code.
-        // This weakens our redeclaration checks, however. Warn about it.
-        i += 2;
-        warning("Redeclaration from no parameters to unspecified parameters.\n");
-      }
-      else
-        goto lend;
-    }
-
-    if (t != tokIdent &&
-        SyntaxStack1[lastSyntaxPtr] != SyntaxStack1[i])
-    {
-      if (SyntaxStack0[lastSyntaxPtr - 1] == '[')
-      {
-        // Complete an incomplete array dimension or check for dimension mismatch
-        if (SyntaxStack1[lastSyntaxPtr] == 0)
-          SyntaxStack1[lastSyntaxPtr] = SyntaxStack1[i];
-        else if (SyntaxStack1[i])
-          goto lend;
-      }
-      else
-        goto lend;
-    }
-
-    c += (t == '(') - (t == ')') + (t == '[') - (t == ']');
-
-    if (!c)
-    {
-      switch (t)
-      {
-      case tokVoid:
-      case tokChar: case tokSChar: case tokUChar:
-      case tokShort: case tokUShort:
-      case tokInt: case tokUnsigned:
-      case tokStructPtr:
-        goto lok;
-      }
-    }
-
-    lastSyntaxPtr++;
-    i++;
-  }
-
-lok:
-  res = 1;
-
-lend:
-  return res;
-}
-
-STATIC
-void CheckRedecl(int lastSyntaxPtr)
-{
-  int tid, id, external = 0;
-  int i;
-  int curScopeOnly;
-  int level = ParseLevel;
-
-  tid = SyntaxStack0[lastSyntaxPtr];
-  id = SyntaxStack1[lastSyntaxPtr];
-  switch (tid)
-  {
-  case tokIdent:
-    switch (SyntaxStack0[lastSyntaxPtr + 1])
-    {
-
-    default:
-      external = 1;
-      // fallthrough
-    case tokLocalOfs: // block-scope auto
-    case tokIdent: // block-scope static
-      ;
-    }
-    // fallthrough
-
-  case tokTypedef:
-    break;
-
-  case tokMemberIdent:
-    {
-      int c = 1;
-      i = lastSyntaxPtr - 1;
-      do
-      {
-        int t = SyntaxStack0[i];
-        c -= (t == '(') - (t == ')') + (t == '{') - (t == '}');
-        if (c == 1 &&
-            t == tokMemberIdent && SyntaxStack1[i] == id &&
-            SyntaxStack0[i + 1] == tokLocalOfs)
-          errorRedecl(IdentTable + id);
-        i--;
-      } while (c);
-    }
-    return;
-
-  default:
-    errorInternal(23);
-  }
-
-  // limit search to current scope for typedef and enum,
-  // ditto for non-external declarations
-  curScopeOnly = tid != tokIdent || !external;
-
-  for (i = lastSyntaxPtr - 1; i >= 0; i--)
-  {
-    int t = SyntaxStack0[i];
-
-    switch (t)
-    {
-    case ')':
-      {
-        // Skip over the function params
-        int c = -1;
-        while (c)
-        {
-          t = SyntaxStack0[--i];
-          c += (t == '(') - (t == ')');
-        }
-      }
-      break;
-
-    case '#':
-      // the scope has changed to the outer scope
-      if (curScopeOnly)
-        return;
-      level--;
-      break;
-
-    case tokTypedef:
-    case tokIdent:
-      if (SyntaxStack1[i] == id)
-      {
-        if (level == ParseLevel)
-        {
-          // block scope:
-          //   can differentiate between auto(tokLocalOfs), static(tokIdent),
-          //   extern/proto(nothing) in SyntaxStack*[], hence dup checks and
-          //   type match checks needed here
-          // file scope:
-          //   can't differentiate between static(nothing), extern(nothing),
-          //   neither(nothing) in SyntaxStack*[], but duplicate definitions
-          //   are taken care of (in CG), hence only type match checks needed
-          //   here
-          if (level) // block scope: check for bad dups
-          {
-            switch (SyntaxStack0[i + 1])
-            {
-            case tokLocalOfs: // block-scope auto
-            case tokIdent: // block-scope static
-              // auto and static can't be redefined in block scope
-              errorRedecl(IdentTable + id);
-            default:
-              // extern can't be redefined as non-extern in block scope
-              if (!external)
-                errorRedecl(IdentTable + id);
-            }
-            // extern/proto type match check follows
-          }
-
-          if (compatCheck2(lastSyntaxPtr, i))
-            return;
-          errorRedecl(IdentTable + id);
-        }
-        else // elseof if (level == ParseLevel)
-        {
-          // The new decl is extern/proto.
-          // Ignore typedef and enum
-          if (t == tokIdent)
-          {
-            switch (SyntaxStack0[i + 1])
-            {
-            case tokLocalOfs: // block-scope auto
-            case tokIdent: // block-scope static
-              // Ignore auto and static
-              break;
-            default:
-              // extern/proto
-              if (compatCheck2(lastSyntaxPtr, i))
-                return;
-              errorRedecl(IdentTable + id);
-            }
-          }
-        }
-      } // endof if (SyntaxStack1[i] == id)
-      break;
-    } // endof switch (t)
-  } // endof for (i = lastSyntaxPtr - 1; i >= 0; i--)
-}
-
-// DONE: support extern
-// DONE: support static
-// DONE: support basic initialization
-// DONE: support simple non-array initializations with string literals
-// DONE: support basic 1-d array initialization
-// DONE: global/static data allocations
-STATIC
-int ParseDecl(int tok, unsigned structInfo[4], int cast, int label)
-{
-  int base[2];
-  int lastSyntaxPtr;
-  int external = tok == tokExtern;
-  int Static = tok == tokStatic;
-  (void)label;
-
-  if (external |
-      Static)
-  {
-    tok = GetToken();
-    if (!TokenStartsDeclaration(tok, 1))
-      //error("ParseDecl(): unexpected token %s\n", GetTokenName(tok));
-      // Implicit int (as in "extern x; static y;") isn't supported
-      errorUnexpectedToken(tok);
-  }
-  tok = ParseBase(tok, base);
-
-
-  for (;;)
-  {
-    lastSyntaxPtr = SyntaxStackCnt;
-
-    /* derived type */
-    tok = ParseDerived(tok);
-
-    /* base type */
-    PushBase(base);
-
-    if ((tok && strchr(",;{=", tok)) || (tok == ')' && ExprLevel))
-    {
-      int isLocal = 0, isGlobal = 0, isFxn, isStruct, isArray, isIncompleteArr;
-      unsigned alignment = 0;
-      int staticLabel = 0;
-
-      // Disallow void variables
-      if (SyntaxStack0[SyntaxStackCnt - 1] == tokVoid)
-      {
-        if (SyntaxStack0[SyntaxStackCnt - 2] == tokIdent &&
-            !(cast
-             ))
-          //error("ParseDecl(): Cannot declare a variable ('%s') of type 'void'\n", IdentTable + SyntaxStack1[lastSyntaxPtr]);
-          errorUnexpectedVoid();
-      }
-
-      isFxn = SyntaxStack0[lastSyntaxPtr + 1] == '(';
-
-
-      isArray = SyntaxStack0[lastSyntaxPtr + 1] == '[';
-      isIncompleteArr = isArray && SyntaxStack1[lastSyntaxPtr + 2] == 0;
-
-      isStruct = SyntaxStack0[lastSyntaxPtr + 1] == tokStructPtr;
-
-      if (!(ExprLevel || structInfo) &&
-          !(external |
-            Static) &&
-          !strcmp(IdentTable + SyntaxStack1[lastSyntaxPtr], "<something>") &&
-          tok == ';')
-      {
-        if (isStruct)
-        {
-          // This is either an incomplete tagged structure/union declaration, e.g. "struct sometag;",
-          // or a tagged complete structure/union declaration, e.g. "struct sometag { ... };", without an instance variable,
-          // or an untagged complete structure/union declaration, e.g. "struct { ... };", without an instance variable
-          int declPtr, curScope;
-          int j = SyntaxStack1[lastSyntaxPtr + 1];
-
-          if (j + 2 < SyntaxStackCnt &&
-              IdentTable[SyntaxStack1[j + 1]] == '<' && // without tag
-              SyntaxStack0[j + 2] == tokSizeof) // but with the {} "body"
-            errorDecl();
-
-          // If a structure/union with this tag has been declared in an outer scope,
-          // this new declaration should override it
-          declPtr = FindTaggedDecl(IdentTable + SyntaxStack1[j + 1], lastSyntaxPtr - 1, &curScope);
-          if (declPtr >= 0 && !curScope)
-          {
-            // If that's the case, unbind this declaration from the old declaration
-            // and make it a new incomplete declaration
-            PushSyntax(SyntaxStack0[j]); // tokStruct or tokUnion
-            PushSyntax2(tokTag, SyntaxStack1[j + 1]);
-            SyntaxStack1[lastSyntaxPtr + 1] = SyntaxStackCnt - 2;
-          }
-          return GetToken();
-        }
-      }
-
-
-      // Structure/union members can't be initialized nor be functions nor
-      // be incompletely typed arrays inside structure/union declarations
-      if (structInfo && ((tok == '=') | isFxn | (tok == '{') | isIncompleteArr))
-        errorDecl();
-
-
-      // Error conditions in declarations(/definitions/initializations):
-      // Legend:
-      //   +  error
-      //   -  no error
-      //
-      // file scope          fxn   fxn {}  var   arr[]   arr[]...[]   arr[incomplete]   arr[incomplete]...[]
-      //                     -     -       -     -       -            +                 +
-      // file scope          fxn=          var=  arr[]=  arr[]...[]=  arr[incomplete]=  arr[incomplete]...[]=
-      //                     +             -     -       +            -                 +
-      // file scope  extern  fxn   fxn {}  var   arr[]   arr[]...[]   arr[incomplete]   arr[incomplete]...[]
-      //                     -     -       -     -       -            -                 -
-      // file scope  extern  fxn=          var=  arr[]=  arr[]...[]=  arr[incomplete]=  arr[incomplete]...[]=
-      //                     +             +     +       +            +                 +
-      // file scope  static  fxn   fxn {}  var   arr[]   arr[]...[]   arr[incomplete]   arr[incomplete]...[]
-      //                     -     -       -     -       -            +                 +
-      // file scope  static  fxn=          var=  arr[]=  arr[]...[]=  arr[incomplete]=  arr[incomplete]...[]=
-      //                     +             -     -       +            -                 +
-      // fxn scope           fxn   fxn {}  var   arr[]   arr[]...[]   arr[incomplete]   arr[incomplete]...[]
-      //                     -     +       -     -       -            +                 +
-      // fxn scope           fxn=          var=  arr[]=  arr[]...[]=  arr[incomplete]=  arr[incomplete]...[]=
-      //                     +             -     +       +            +                 +
-      // fxn scope   extern  fxn   fxn {}  var   arr[]   arr[]...[]   arr[incomplete]   arr[incomplete]...[]
-      //                     -     +       -     -       -            -                 -
-      // fxn scope   extern  fxn=          var=  arr[]=  arr[]...[]=  arr[incomplete]=  arr[incomplete]...[]=
-      //                     +             +     +       +            +                 +
-      // fxn scope   static  fxn   fxn {}  var   arr[]   arr[]...[]   arr[incomplete]   arr[incomplete]...[]
-      //                     +     +       +     +       +            +                 +
-      // fxn scope   static  fxn=          var=  arr[]=  arr[]...[]=  arr[incomplete]=  arr[incomplete]...[]=
-      //                     +             +     +       +            +                 +
-
-      if (isFxn & (tok == '='))
-        //error("ParseDecl(): cannot initialize a function\n");
-        errorInit();
-
-      if ((isFxn & (tok == '{')) && ParseLevel)
-        //error("ParseDecl(): cannot define a nested function\n");
-        errorDecl();
-
-      if ((isFxn & Static) && ParseLevel)
-        //error("ParseDecl(): cannot declare a static function in this scope\n");
-        errorDecl();
-
-      if (external & (tok == '='))
-        //error("ParseDecl(): cannot initialize an external variable\n");
-        errorInit();
-
-      if (isIncompleteArr & !(external |
-                              (tok == '=')))
-        //error("ParseDecl(): cannot define an array of incomplete type\n");
-        errorDecl();
-
-      // TBD!!! de-uglify
-      if (!strcmp(IdentTable + SyntaxStack1[lastSyntaxPtr], "<something>"))
-      {
-        // Disallow nameless variables, prototypes, structure/union members and typedefs.
-        if (structInfo ||
-            !ExprLevel)
-          error("Identifier expected in declaration\n");
-      }
-      else
-      {
-        // Disallow named variables and prototypes in sizeof(typedecl) and (typedecl).
-        if (ExprLevel && !structInfo)
-          error("Identifier unexpected in declaration\n");
-      }
-
-      if (!isFxn
-         )
-      {
-        // This is a variable or a variable (member) in a struct/union declaration
-        int sz = GetDeclSize(lastSyntaxPtr, 0);
-
-        if (!((sz | isIncompleteArr) || ExprLevel)) // incomplete type
-          errorDecl(); // TBD!!! different error when struct/union tag is not found
-
-        if (isArray && !GetDeclSize(lastSyntaxPtr + 4, 0))
-          // incomplete type of array element (e.g. struct/union)
-          errorDecl();
-
-        alignment = GetDeclAlignment(lastSyntaxPtr);
-
-        if (structInfo)
-        {
-          // It's a variable (member) in a struct/union declaration
-          unsigned tmp;
-          unsigned newAlignment = alignment;
-          // Update structure/union alignment
-          if (structInfo[1] < newAlignment)
-            structInfo[1] = newAlignment;
-          // Align structure member
-          tmp = structInfo[2];
-          structInfo[2] = (structInfo[2] + newAlignment - 1) & ~(newAlignment - 1);
-          if (structInfo[2] < tmp || structInfo[2] != truncUint(structInfo[2]))
-            errorVarSize();
-          // Change tokIdent to tokMemberIdent and insert a local var offset token
-          SyntaxStack0[lastSyntaxPtr] = tokMemberIdent;
-          InsertSyntax2(lastSyntaxPtr + 1, tokLocalOfs, (int)structInfo[2]);
-
-          // Advance member offset for structures, keep it zero for unions
-          if (structInfo[0] == tokStruct)
-          {
-            tmp = structInfo[2];
-            structInfo[2] += sz;
-            if (structInfo[2] < tmp || structInfo[2] != truncUint(structInfo[2]))
-              errorVarSize();
-          }
-          // Update max member size for unions
-          else if (structInfo[3] < (unsigned)sz)
-          {
-            structInfo[3] = sz;
-          }
-        }
-        else if (ParseLevel && !((external | Static) || ExprLevel))
-        {
-          // It's a local variable
-          isLocal = 1;
-          // Defer size calculation until initialization
-          // Insert a local var offset token, the offset is to be updated
-          InsertSyntax2(lastSyntaxPtr + 1, tokLocalOfs, 0);
-        }
-        else if (!ExprLevel)
-        {
-          // It's a global variable (external, static or neither)
-          isGlobal = 1;
-          if (Static && ParseLevel)
-          {
-            // It's a static variable in function scope, "rename" it by providing
-            // an alternative unique numeric identifier right next to it and use it
-            staticLabel = LabelCnt++;
-            InsertSyntax2(lastSyntaxPtr + 1, tokIdent, AddNumericIdent(staticLabel));
-          }
-        }
-      }
-
-      // If it's a type declaration in a sizeof(typedecl) expression or
-      // in an expression with a cast, e.g. (typedecl)expr, we're done
-      if (ExprLevel && !structInfo)
-      {
-        DumpDecl(lastSyntaxPtr, 0);
-        return tok;
-      }
-
-      if (isLocal | isGlobal)
-      {
-        int hasInit = tok == '=';
-        int needsGlobalInit = isGlobal & !external;
-        int sz = GetDeclSize(lastSyntaxPtr, 0);
-        int initLabel = 0;
-        int bss = (!hasInit) & UseBss;
-
-        if (isGlobal)
-          DumpDecl(lastSyntaxPtr, 0);
-
-        if (hasInit)
-        {
-          tok = GetToken();
-        }
-
-        if (isLocal & hasInit)
-          needsGlobalInit = isArray | (isStruct & (tok == '{'));
-
-        if (needsGlobalInit)
-        {
-          char** oldHeaderFooter = CurHeaderFooter;
-          if (oldHeaderFooter)
-            puts2(oldHeaderFooter[1]);
-          CurHeaderFooter = bss ? BssHeaderFooter : DataHeaderFooter;
-          puts2(CurHeaderFooter[0]);
-
-          // DONE: imperfect condition for alignment
-          if (alignment != 1)
-            GenWordAlignment(bss);
-
-          if (isGlobal)
-          {
-            if (Static && ParseLevel)
-              GenNumLabel(staticLabel);
-            else
-              GenLabel(IdentTable + SyntaxStack1[lastSyntaxPtr], Static);
-          }
-          else
-          {
-            // Generate numeric labels for global initializers of local vars
-            GenNumLabel(initLabel = LabelCnt++);
-          }
-
-          // Generate global initializers
-          if (hasInit)
-          {
-            if (isGlobal)
-            {
-              GenStartCommentLine(); printf2("=\n");
-            }
-            tok = InitVar(lastSyntaxPtr, tok);
-            // Update the size in case it's an incomplete array
-            sz = GetDeclSize(lastSyntaxPtr, 0);
-          }
-          else
-          {
-            GenZeroData(sz, bss);
-          }
-
-          puts2(CurHeaderFooter[1]);
-          if (oldHeaderFooter)
-            puts2(oldHeaderFooter[0]);
-          CurHeaderFooter = oldHeaderFooter;
-        }
-
-        if (isLocal)
-        {
-          // Now that the size of the local is certainly known,
-          // update its offset in the offset token
-          SyntaxStack1[lastSyntaxPtr + 1] = AllocLocal(sz);
-
-          DumpDecl(lastSyntaxPtr, 0);
-        }
-
-        // Copy global initializers into local vars
-        if (isLocal & needsGlobalInit)
-        {
-          GenStartCommentLine(); printf2("=\n");
-          if (!StructCpyLabel)
-            StructCpyLabel = LabelCnt++;
-
-          sp = 0;
-
-          push2('(', SizeOfWord * 3);
-          push2(tokLocalOfs, SyntaxStack1[lastSyntaxPtr + 1]);
-          push(',');
-          push2(tokIdent, AddNumericIdent(initLabel));
-          push(',');
-          push2(tokNumUint, sz);
-          push(',');
-          push2(tokIdent, AddNumericIdent(StructCpyLabel));
-          push2(')', SizeOfWord * 3);
-
-          GenExpr();
-        }
-        // Initialize local vars with expressions
-        else if (hasInit & !needsGlobalInit)
-        {
-          int gotUnary, synPtr, constExpr, exprVal;
-          int brace = 0;
-
-          // Initializers for scalars can be optionally enclosed in braces
-          if ((!isStruct) & (tok == '{'))
-          {
-            brace = 1;
-            tok = GetToken();
-          }
-
-          // ParseExpr() will transform the initializer expression into an assignment expression here
-          tok = ParseExpr(tok, &gotUnary, &synPtr, &constExpr, &exprVal, '=', SyntaxStack1[lastSyntaxPtr]);
-
-          if (!gotUnary)
-            errorUnexpectedToken(tok);
-
-          if (brace)
-          {
-            if (tok != '}')
-              errorUnexpectedToken(tok);
-            tok = GetToken();
-          }
-
-          if (!isStruct)
-          {
-            // This is a special case for initialization of integers smaller than int.
-            // Since a local integer variable always takes as much space as a whole int,
-            // we can optimize code generation a bit by storing the initializer as an int.
-            // This is an old accidental optimization and I preserve it for now.
-            // Note, this implies a little-endian CPU.
-            stack[sp - 1][1] = SizeOfWord;
-          }
-
-          // Storage of string literal data from the initializing expression
-          // occurs here.
-          GenExpr();
-        }
-      }
-      else if (tok == '{')
-      {
-        // It's a function body. Let's add function parameters as
-        // local variables to the symbol table and parse the body.
-        int undoSymbolsPtr = SyntaxStackCnt;
-        int undoIdents = IdentTableLen;
-        int i;
-        int endLabel = 0;
-
-        DumpDecl(lastSyntaxPtr, 0);
-
-        CurFxnName = IdentTable + SyntaxStack1[lastSyntaxPtr];
-        IsMain = !strcmp(CurFxnName, "main");
-
-        gotoLabCnt = 0;
-
-        if (verbose)
-          printf("%s()\n", CurFxnName);
-
-        ParseLevel++;
-        GetFxnInfo(lastSyntaxPtr, &CurFxnParamCntMin, &CurFxnParamCntMax, &CurFxnReturnExprTypeSynPtr, NULL); // get return type
-
-
-
-        CurHeaderFooter = CodeHeaderFooter;
-        puts2(CurHeaderFooter[0]);
-
-        GenLabel(CurFxnName, Static);
-
-
-        GenFxnProlog();
-        CurFxnEpilogLabel = LabelCnt++;
-
-        // A new scope begins before the function parameters
-        PushSyntax('#');
-        AddFxnParamSymbols(lastSyntaxPtr);
-
-
-        // The block doesn't begin yet another new scope.
-        // This is to catch redeclarations of the function parameters.
-        tok = ParseBlock(BrkCntTargetFxn, 0);
-        ParseLevel--;
-        if (tok != '}')
-          //error("ParseDecl(): '}' expected\n");
-          errorUnexpectedToken(tok);
-
-        for (i = 0; i < gotoLabCnt; i++)
-          if (gotoLabStat[i] == 2)
-            error("Undeclared label '%s'\n", IdentTable + gotoLabels[i][0]);
-
-        // DONE: if execution of main() reaches here, before the epilog (i.e. without using return),
-        // main() should return 0.
-        if (IsMain)
-        {
-          sp = 0;
-          push(tokNumInt);
-          push(tokReturn); // value produced by generated code is used
-          GenExpr();
-        }
-
-        GenNumLabel(CurFxnEpilogLabel);
-
-
-        GenFxnEpilog();
-
-        if (GenFxnSizeNeeded())
-          GenNumLabel(endLabel = LabelCnt++);
-
-        puts2(CurHeaderFooter[1]);
-        CurHeaderFooter = NULL;
-
-        if (GenFxnSizeNeeded())
-          GenRecordFxnSize(CurFxnName, endLabel);
-
-
-
-        CurFxnName = NULL;
-        IdentTableLen = undoIdents; // remove all identifier names
-        SyntaxStackCnt = undoSymbolsPtr; // remove all params and locals
-        SyntaxStack1[SymFuncPtr] = DummyIdent;
-      }
-      else if (isFxn)
-      {
-        // function prototype
-        DumpDecl(lastSyntaxPtr, 0);
-      }
-
-      CheckRedecl(lastSyntaxPtr);
-
-      if ((tok == ';') | (tok == '}'))
-        break;
-
-      tok = GetToken();
-      continue;
-    }
-
-    //error("ParseDecl(): unexpected token %s\n", GetTokenName(tok));
-    errorUnexpectedToken(tok);
-  }
-
-  tok = GetToken();
-  return tok;
-}
-
-STATIC
-void ParseFxnParams(int tok)
-{
-  int base[2];
-  int lastSyntaxPtr;
-  int cnt = 0;
-  int ellCnt = 0;
-
-  for (;;)
-  {
-    lastSyntaxPtr = SyntaxStackCnt;
-
-    if (tok == ')') /* unspecified params */
-      break;
-
-    if (!TokenStartsDeclaration(tok, 1))
-    {
-      if (tok == tokEllipsis)
-      {
-        // "..." cannot be the first parameter and
-        // it can be only one
-        if (!cnt || ellCnt)
-          //error("ParseFxnParams(): '...' unexpected here\n");
-          errorUnexpectedToken(tok);
-        ellCnt++;
-      }
-      else
-        //error("ParseFxnParams(): Unexpected token %s\n", GetTokenName(tok));
-        errorUnexpectedToken(tok);
-      base[0] = tok; // "..."
-      base[1] = 0;
-      PushSyntax2(tokIdent, AddIdent("<something>"));
-      tok = GetToken();
-    }
-    else
-    {
-      if (ellCnt)
-        //error("ParseFxnParams(): '...' must be the last in the parameter list\n");
-        errorUnexpectedToken(tok);
-
-      /* base type */
-      tok = ParseBase(tok, base);
-
-      /* derived type */
-      tok = ParseDerived(tok);
-    }
-
-    /* base type */
-    PushBase(base);
-
-
-
-    /* Decay arrays to pointers */
-    lastSyntaxPtr++; /* skip name */
-    if (SyntaxStack0[lastSyntaxPtr] == '[')
-    {
-      int t;
-      DeleteSyntax(lastSyntaxPtr, 1);
-      t = SyntaxStack0[lastSyntaxPtr];
-      if (t == tokNumInt || t == tokNumUint)
-        DeleteSyntax(lastSyntaxPtr, 1);
-      SyntaxStack0[lastSyntaxPtr] = '*';
-    }
-    /* "(Un)decay" functions to function pointers */
-    else if (SyntaxStack0[lastSyntaxPtr] == '(')
-    {
-      InsertSyntax(lastSyntaxPtr, '*');
-    }
-    lastSyntaxPtr--; /* "unskip" name */
-
-    cnt++;
-
-    if (tok == ')' || tok == ',')
-    {
-      int t = SyntaxStack0[SyntaxStackCnt - 2];
-      if (SyntaxStack0[SyntaxStackCnt - 1] == tokVoid)
-      {
-        // Disallow void variables. TBD!!! de-uglify
-        if (t == tokIdent &&
-            !(!strcmp(IdentTable + SyntaxStack1[SyntaxStackCnt - 2], "<something>") &&
-              cnt == 1 && tok == ')'))
-          //error("ParseFxnParams(): Cannot declare a variable ('%s') of type 'void'\n", IdentTable + SyntaxStack1[lastSyntaxPtr]);
-          errorUnexpectedVoid();
-      }
-
-
-
-      if (tok == ')')
-        break;
-
-      tok = GetToken();
-      continue;
-    }
-
-    //error("ParseFxnParams(): Unexpected token %s\n", GetTokenName(tok));
-    errorUnexpectedToken(tok);
-  }
-}
-
-STATIC
-void AddFxnParamSymbols(int SyntaxPtr)
-{
-  int i;
-  unsigned paramOfs = 2 * SizeOfWord; // ret addr, xbp
-
-  if (SyntaxPtr < 0 ||
-      SyntaxPtr > SyntaxStackCnt - 3 ||
-      SyntaxStack0[SyntaxPtr] != tokIdent ||
-      SyntaxStack0[SyntaxPtr + 1] != '(')
-    //error("Internal error: AddFxnParamSymbols(): Invalid input\n");
-    errorInternal(6);
-
-  CurFxnSyntaxPtr = SyntaxPtr;
-  CurFxnLocalOfs = 0;
-  CurFxnMinLocalOfs = 0;
-
-
-
-  SyntaxPtr += 2; // skip "ident("
-
-  for (i = SyntaxPtr; i < SyntaxStackCnt; i++)
-  {
-    int tok = SyntaxStack0[i];
-
-    if (tok == tokIdent)
-    {
-      unsigned sz;
-      int paramPtr;
-
-      if (i + 1 >= SyntaxStackCnt)
-        //error("Internal error: AddFxnParamSymbols(): Invalid input\n");
-        errorInternal(7);
-
-      if (SyntaxStack0[i + 1] == tokVoid) // "ident(void)" = no params
-        break;
-      if (SyntaxStack0[i + 1] == tokEllipsis) // "ident(something,...)" = no more params
-        break;
-
-      // Make sure the parameter is not an incomplete structure
-      sz = GetDeclSize(i, 0);
-      if (sz == 0)
-        //error("Internal error: AddFxnParamSymbols(): GetDeclSize() = 0\n");
-        //errorInternal(8);
-        errorDecl();
-
-      // Let's calculate this parameter's relative on-stack location
-      paramPtr = SyntaxStackCnt;
-      PushSyntax2(SyntaxStack0[i], SyntaxStack1[i]);
-      PushSyntax2(tokLocalOfs, paramOfs);
-
-      if (sz + SizeOfWord - 1 < sz)
-        errorVarSize();
-      sz = (sz + SizeOfWord - 1) & ~(SizeOfWord - 1u);
-      if (paramOfs + sz < paramOfs)
-        errorVarSize();
-      paramOfs += sz;
-      if (paramOfs > (unsigned)GenMaxLocalsSize())
-        errorVarSize();
-
-      // Duplicate this parameter in the symbol table
-      i++;
-      while (i < SyntaxStackCnt)
-      {
-        tok = SyntaxStack0[i];
-        if (tok == tokIdent || tok == ')')
-        {
-          DumpDecl(paramPtr, 0);
-          if (IdentTable[SyntaxStack1[paramPtr]] == '<')
-            error("Parameter name expected\n");
-          CheckRedecl(paramPtr);
-          i--;
-          break;
-        }
-        else if (tok == '(')
-        {
-          int c = 1;
-          i++;
-          PushSyntax(tok);
-          while (c && i < SyntaxStackCnt)
-          {
-            tok = SyntaxStack0[i];
-            c += (tok == '(') - (tok == ')');
-            PushSyntax2(SyntaxStack0[i], SyntaxStack1[i]);
-            i++;
-          }
-        }
-        else
-        {
-          PushSyntax2(SyntaxStack0[i], SyntaxStack1[i]);
-          i++;
-        }
-      }
-    }
-    else if (tok == ')') // endof "ident(" ... ")"
-      break;
-    else
-      //error("Internal error: AddFxnParamSymbols(): Unexpected token %s\n", GetTokenName(tok));
-      errorInternal(9);
-  }
-}
-
-STATIC
-int ParseStatement(int tok, int BrkCntTarget[2], int casesIdx)
-{
-/*
-  labeled statements:
-  + ident : statement
-  + case const-expr : statement
-  + default : statement
-
-  compound statement:
-  + { declaration(s)/statement(s)-opt }
-
-  expression statement:
-  + expression-opt ;
-
-  selection statements:
-  + if ( expression ) statement
-  + if ( expression ) statement else statement
-  + switch ( expression ) { statement(s)-opt }
-
-  iteration statements:
-  + while ( expression ) statement
-  + do statement while ( expression ) ;
-  + for ( expression-opt ; expression-opt ; expression-opt ) statement
-
-  jump statements:
-  + goto ident ;
-  + continue ;
-  + break ;
-  + return expression-opt ;
-*/
-  int gotUnary, synPtr,  constExpr, exprVal;
-  int brkCntTarget[2];
-  int statementNeeded;
-
-  do
-  {
-    statementNeeded = 0;
-
-    if (tok == ';')
-    {
-      tok = GetToken();
-    }
-    else if (tok == '{')
-    {
-      // A new {} block begins in the function body
-      int undoSymbolsPtr = SyntaxStackCnt;
-      int undoLocalOfs = CurFxnLocalOfs;
-      int undoIdents = IdentTableLen;
-      GenStartCommentLine(); printf2("{\n");
-      ParseLevel++;
-      tok = ParseBlock(BrkCntTarget, casesIdx);
-      ParseLevel--;
-      if (tok != '}')
-        //error("ParseStatement(): '}' expected. Unexpected token %s\n", GetTokenName(tok));
-        errorUnexpectedToken(tok);
-      UndoNonLabelIdents(undoIdents); // remove all identifier names, except those of labels
-      SyntaxStackCnt = undoSymbolsPtr; // remove all params and locals
-      CurFxnLocalOfs = undoLocalOfs; // destroy on-stack local variables
-      GenStartCommentLine(); printf2("}\n");
-      tok = GetToken();
-    }
-    else if (tok == tokReturn)
-    {
-      // DONE: functions returning void vs non-void
-      int retVoid = CurFxnReturnExprTypeSynPtr >= 0 &&
-                    SyntaxStack0[CurFxnReturnExprTypeSynPtr] == tokVoid;
-      GenStartCommentLine(); printf2("return\n");
-      tok = GetToken();
-      if (tok == ';')
-      {
-        gotUnary = 0;
-        if (!retVoid)
-          //error("ParseStatement(): missing return value\n");
-          errorUnexpectedToken(tok);
-      }
-      else
-      {
-        if (retVoid)
-          //error("Error: ParseStatement(): cannot return a value from a function returning 'void'\n");
-          errorUnexpectedToken(tok);
-        if ((tok = ParseExpr(tok, &gotUnary, &synPtr, &constExpr, &exprVal, 0, 0)) != ';')
-          //error("ParseStatement(): ';' expected\n");
-          errorUnexpectedToken(tok);
-        if (gotUnary)
-          //error("ParseStatement(): cannot return a value of type 'void'\n");
-
-          // Bar void
-          nonVoidTypeCheck(synPtr);
-      }
-      if (gotUnary)
-      {
-
-
-        decayArray(&synPtr, 0);
-
-
-        {
-          int castSize = GetDeclSize(CurFxnReturnExprTypeSynPtr, 1);
-
-
-          // If return value (per function declaration) is a scalar type smaller than machine word,
-          // properly zero- or sign-extend the returned value to machine word size.
-          // TBD??? Move this cast to the caller?
-          if (castSize != SizeOfWord && castSize != GetDeclSize(synPtr, 1))
-          {
-            if (constExpr)
-            {
-              switch (castSize)
-              {
-              case 1:
-                exprVal &= 0xFFu;
-                break;
-              case -1:
-                if ((exprVal &= 0xFFu) >= 0x80)
-                  exprVal -= 0x100;
-                break;
-              case 2:
-                exprVal &= 0xFFFFu;
-                break;
-              case -2:
-                if ((exprVal &= 0xFFFFu) >= 0x8000)
-                  exprVal -= 0x10000;
-                break;
-              }
-            }
-            else
-            {
-              switch (castSize)
-              {
-              case 1:
-                push(tokUChar);
-                break;
-              case -1:
-                push(tokSChar);
-                break;
-              case 2:
-                push(tokUShort);
-                break;
-              case -2:
-                push(tokShort);
-                break;
-              }
-            }
-          }
-        }
-        if (constExpr)
-          stack[0][1] = exprVal;
-        push(tokReturn); // value produced by generated code is used
-        GenExpr();
-      }
-      tok = GetToken();
-      // If this return is the last statement in the function, the epilogue immediately
-      // follows and there's no need to jump to it.
-      if (!(tok == '}' && ParseLevel == 1 && !IsMain))
-        GenJumpUncond(CurFxnEpilogLabel);
-    }
-    else if (tok == tokWhile)
-    {
-      int labelBefore = LabelCnt++;
-      int labelAfter = LabelCnt++;
-      int forever = 0;
-      GenStartCommentLine(); printf2("while\n");
-
-      tok = GetToken();
-      if (tok != '(')
-        //error("ParseStatement(): '(' expected after 'while'\n");
-        errorUnexpectedToken(tok);
-
-      tok = GetToken();
-      if ((tok = ParseExpr(tok, &gotUnary, &synPtr, &constExpr, &exprVal, 0, 0)) != ')')
-        //error("ParseStatement(): ')' expected after 'while ( expression'\n");
-        errorUnexpectedToken(tok);
-
-      if (!gotUnary)
-        //error("ParseStatement(): expression expected in 'while ( expression )'\n");
-        errorUnexpectedToken(tok);
-
-      // DONE: void control expressions
-      //error("ParseStatement(): unexpected 'void' expression in 'while ( expression )'\n");
-      // Bar void and struct/union
-      scalarTypeCheck(synPtr);
-
-      GenNumLabel(labelBefore);
-
-      if (constExpr)
-      {
-
-        // Special cases for while(0) and while(1)
-        if (!(forever = truncInt(exprVal)))
-          GenJumpUncond(labelAfter);
-      }
-      else
-      {
-        switch (stack[sp - 1][0])
-        {
-        case '<':
-        case '>':
-        case tokEQ:
-        case tokNEQ:
-        case tokLEQ:
-        case tokGEQ:
-        case tokULess:
-        case tokUGreater:
-        case tokULEQ:
-        case tokUGEQ:
-          push2(tokIfNot, labelAfter);
-          GenExpr();
-          break;
-        default:
-
-          push(tokReturn); // value produced by generated code is used
-          GenExpr();
-          GenJumpIfZero(labelAfter);
-          break;
-        }
-      }
-
-      tok = GetToken();
-      brkCntTarget[0] = labelAfter; // break target
-      brkCntTarget[1] = labelBefore; // continue target
-      tok = ParseStatement(tok, brkCntTarget, casesIdx);
-
-      // Special case for while(0)
-      if (!(constExpr && !forever))
-        GenJumpUncond(labelBefore);
-      GenNumLabel(labelAfter);
-    }
-    else if (tok == tokDo)
-    {
-      int labelBefore = LabelCnt++;
-      int labelWhile = LabelCnt++;
-      int labelAfter = LabelCnt++;
-      GenStartCommentLine(); printf2("do\n");
-      GenNumLabel(labelBefore);
-
-      tok = GetToken();
-      brkCntTarget[0] = labelAfter; // break target
-      brkCntTarget[1] = labelWhile; // continue target
-      tok = ParseStatement(tok, brkCntTarget, casesIdx);
-      if (tok != tokWhile)
-        //error("ParseStatement(): 'while' expected after 'do statement'\n");
-        errorUnexpectedToken(tok);
-
-      GenStartCommentLine(); printf2("while\n");
-      tok = GetToken();
-      if (tok != '(')
-        //error("ParseStatement(): '(' expected after 'while'\n");
-        errorUnexpectedToken(tok);
-
-      tok = GetToken();
-      if ((tok = ParseExpr(tok, &gotUnary, &synPtr, &constExpr, &exprVal, 0, 0)) != ')')
-        //error("ParseStatement(): ')' expected after 'while ( expression'\n");
-        errorUnexpectedToken(tok);
-
-      if (!gotUnary)
-        //error("ParseStatement(): expression expected in 'while ( expression )'\n");
-        errorUnexpectedToken(tok);
-
-      tok = GetToken();
-      if (tok != ';')
-        //error("ParseStatement(): ';' expected after 'do statement while ( expression )'\n");
-        errorUnexpectedToken(tok);
-
-      // DONE: void control expressions
-      //error("ParseStatement(): unexpected 'void' expression in 'while ( expression )'\n");
-      // Bar void and struct/union
-      scalarTypeCheck(synPtr);
-
-      GenNumLabel(labelWhile);
-
-      if (constExpr)
-      {
-
-        // Special cases for while(0) and while(1)
-        if (truncInt(exprVal))
-          GenJumpUncond(labelBefore);
-      }
-      else
-      {
-        switch (stack[sp - 1][0])
-        {
-        case '<':
-        case '>':
-        case tokEQ:
-        case tokNEQ:
-        case tokLEQ:
-        case tokGEQ:
-        case tokULess:
-        case tokUGreater:
-        case tokULEQ:
-        case tokUGEQ:
-          push2(tokIf, labelBefore);
-          GenExpr();
-          break;
-        default:
-
-          push(tokReturn); // value produced by generated code is used
-          GenExpr();
-          GenJumpIfNotZero(labelBefore);
-          break;
-        }
-      }
-
-      GenNumLabel(labelAfter);
-
-      tok = GetToken();
-    }
-    else if (tok == tokIf)
-    {
-      int labelAfterIf = LabelCnt++;
-      int labelAfterElse = LabelCnt++;
-      GenStartCommentLine(); printf2("if\n");
-
-      tok = GetToken();
-      if (tok != '(')
-        //error("ParseStatement(): '(' expected after 'if'\n");
-        errorUnexpectedToken(tok);
-
-      tok = GetToken();
-      if ((tok = ParseExpr(tok, &gotUnary, &synPtr, &constExpr, &exprVal, 0, 0)) != ')')
-        //error("ParseStatement(): ')' expected after 'if ( expression'\n");
-        errorUnexpectedToken(tok);
-
-      if (!gotUnary)
-        //error("ParseStatement(): expression expected in 'if ( expression )'\n");
-        errorUnexpectedToken(tok);
-
-      // DONE: void control expressions
-      //error("ParseStatement(): unexpected 'void' expression in 'if ( expression )'\n");
-      // Bar void and struct/union
-      scalarTypeCheck(synPtr);
-
-      if (constExpr)
-      {
-
-        // Special cases for if(0) and if(1)
-        if (!truncInt(exprVal))
-          GenJumpUncond(labelAfterIf);
-      }
-      else
-      {
-        switch (stack[sp - 1][0])
-        {
-        case '<':
-        case '>':
-        case tokEQ:
-        case tokNEQ:
-        case tokLEQ:
-        case tokGEQ:
-        case tokULess:
-        case tokUGreater:
-        case tokULEQ:
-        case tokUGEQ:
-          push2(tokIfNot, labelAfterIf);
-          GenExpr();
-          break;
-        default:
-
-          push(tokReturn); // value produced by generated code is used
-          GenExpr();
-          GenJumpIfZero(labelAfterIf);
-          break;
-        }
-      }
-
-      tok = GetToken();
-      tok = ParseStatement(tok, BrkCntTarget, casesIdx);
-
-      // DONE: else
-      if (tok == tokElse)
-      {
-        GenJumpUncond(labelAfterElse);
-        GenNumLabel(labelAfterIf);
-        GenStartCommentLine(); printf2("else\n");
-        tok = GetToken();
-        tok = ParseStatement(tok, BrkCntTarget, casesIdx);
-        GenNumLabel(labelAfterElse);
-      }
-      else
-      {
-        GenNumLabel(labelAfterIf);
-      }
-    }
-    else if (tok == tokFor)
-    {
-      int labelBefore = LabelCnt++;
-      int labelExpr3 = LabelCnt++;
-      int labelBody = LabelCnt++;
-      int labelAfter = LabelCnt++;
-      int cond = -1;
-      static int expr3Stack[STACK_SIZE >> 1][2];
-      static int expr3Sp;
-
-      GenStartCommentLine(); printf2("for\n");
-      tok = GetToken();
-      if (tok != '(')
-        //error("ParseStatement(): '(' expected after 'for'\n");
-        errorUnexpectedToken(tok);
-
-      tok = GetToken();
-
-      {
-        if ((tok = ParseExpr(tok, &gotUnary, &synPtr, &constExpr, &exprVal, 0, 0)) != ';')
-          //error("ParseStatement(): ';' expected after 'for ( expression'\n");
-          errorUnexpectedToken(tok);
-        if (gotUnary)
-        {
-          GenExpr();
-        }
-        tok = GetToken();
-      }
-
-      GenNumLabel(labelBefore);
-      if ((tok = ParseExpr(tok, &gotUnary, &synPtr, &constExpr, &exprVal, 0, 0)) != ';')
-        //error("ParseStatement(): ';' expected after 'for ( expression ; expression'\n");
-        errorUnexpectedToken(tok);
-      if (gotUnary)
-      {
-        // DONE: void control expressions
-        //error("ParseStatement(): unexpected 'void' expression in 'for ( ; expression ; )'\n");
-        // Bar void and struct/union
-        scalarTypeCheck(synPtr);
-
-        if (constExpr)
-        {
-
-          // Special cases for for(...; 0; ...) and for(...; 1; ...)
-          cond = truncInt(exprVal) != 0;
-        }
-        else
-        {
-          switch (stack[sp - 1][0])
-          {
-          case '<':
-          case '>':
-          case tokEQ:
-          case tokNEQ:
-          case tokLEQ:
-          case tokGEQ:
-          case tokULess:
-          case tokUGreater:
-          case tokULEQ:
-          case tokUGEQ:
-            push2(tokIfNot, labelAfter);
-            GenExpr();
-            break;
-          default:
-
-            push(tokReturn); // value produced by generated code is used
-            GenExpr();
-            GenJumpIfZero(labelAfter);
-            break;
-          }
-        }
-      }
-      else
-      {
-        // Special case for for(...; ; ...)
-        cond = 1;
-      }
-      if (!cond)
-        // Special case for for(...; 0; ...)
-        GenJumpUncond(labelAfter);
-
-      tok = GetToken();
-      if ((tok = ParseExpr(tok, &gotUnary, &synPtr, &constExpr, &exprVal, 0, 0)) != ')')
-        //error("ParseStatement(): ')' expected after 'for ( expression ; expression ; expression'\n");
-        errorUnexpectedToken(tok);
-
-      // Try to reorder expr3 with body to reduce the number of jumps, favor small expr3's
-      if (gotUnary && sp <= 16 && (unsigned)sp <= division(sizeof expr3Stack , sizeof expr3Stack[0]) - expr3Sp)
-      {
-        int cnt = sp;
-        // Stash the stack containing expr3
-        memcpy(expr3Stack + expr3Sp, stack, cnt * sizeof stack[0]);
-        expr3Sp += cnt;
-
-        // Body
-        tok = GetToken();
-        brkCntTarget[0] = labelAfter; // break target
-        brkCntTarget[1] = labelExpr3; // continue target
-        tok = ParseStatement(tok, brkCntTarget, casesIdx);
-
-        // Unstash expr3 and generate code for it
-        expr3Sp -= cnt;
-        memcpy(stack, expr3Stack + expr3Sp, cnt * sizeof stack[0]);
-        sp = cnt;
-        GenNumLabel(labelExpr3);
-        GenExpr();
-
-        // Special case for for(...; 0; ...)
-        if (cond)
-          GenJumpUncond(labelBefore);
-      }
-      else
-      {
-        if (gotUnary)
-        {
-          GenJumpUncond(labelBody);
-          // expr3
-          GenNumLabel(labelExpr3);
-          GenExpr();
-          GenJumpUncond(labelBefore);
-          GenNumLabel(labelBody);
-        }
-
-        // Body
-        tok = GetToken();
-        brkCntTarget[0] = labelAfter; // break target
-        brkCntTarget[1] = gotUnary ? labelExpr3 : (cond ? labelBefore : labelAfter); // continue target
-        tok = ParseStatement(tok, brkCntTarget, casesIdx);
-
-        // Special case for for(...; 0; ...)
-        if (brkCntTarget[1] != labelAfter)
-          GenJumpUncond(brkCntTarget[1]);
-      }
-
-      GenNumLabel(labelAfter);
-
-
-    }
-    else if (tok == tokBreak)
-    {
-      GenStartCommentLine(); printf2("break\n");
-      if ((tok = GetToken()) != ';')
-        //error("ParseStatement(): ';' expected\n");
-        errorUnexpectedToken(tok);
-      tok = GetToken();
-      if (BrkCntTarget == NULL)
-        //error("ParseStatement(): 'break' must be within 'while', 'for' or 'switch' statement\n");
-        errorCtrlOutOfScope();
-      GenJumpUncond(BrkCntTarget[0]);
-    }
-    else if (tok == tokCont)
-    {
-      GenStartCommentLine(); printf2("continue\n");
-      if ((tok = GetToken()) != ';')
-        //error("ParseStatement(): ';' expected\n");
-        errorUnexpectedToken(tok);
-      tok = GetToken();
-      if (BrkCntTarget == NULL || BrkCntTarget[1] == 0)
-        //error("ParseStatement(): 'continue' must be within 'while' or 'for' statement\n");
-        errorCtrlOutOfScope();
-      GenJumpUncond(BrkCntTarget[1]);
-    }
-    else if (tok == tokSwitch)
-    {
-      int undoCases = CasesCnt;
-      int brkLabel = LabelCnt++;
-      int lbl = LabelCnt++;
-      int i;
-      GenStartCommentLine(); printf2("switch\n");
-
-      tok = GetToken();
-      if (tok != '(')
-        //error("ParseStatement(): '(' expected after 'switch'\n");
-        errorUnexpectedToken(tok);
-
-      tok = GetToken();
-      if ((tok = ParseExpr(tok, &gotUnary, &synPtr, &constExpr, &exprVal, 0, 0)) != ')')
-        //error("ParseStatement(): ')' expected after 'switch ( expression'\n");
-        errorUnexpectedToken(tok);
-
-      if (!gotUnary)
-        //error("ParseStatement(): expression expected in 'switch ( expression )'\n");
-        errorUnexpectedToken(tok);
-
-      // DONE: void control expressions
-      //error("ParseStatement(): unexpected 'void' expression in 'switch ( expression )'\n");
-      anyIntTypeCheck(synPtr);
-
-      push(tokReturn); // value produced by generated code is used
-      GenExpr();
-
-      tok = GetToken();
-
-      // Skip the code for the cases
-      GenJumpUncond(lbl);
-
-      brkCntTarget[0] = brkLabel; // break target
-      brkCntTarget[1] = 0; // continue target
-      if (BrkCntTarget)
-      {
-        // Preserve the continue target
-        brkCntTarget[1] = BrkCntTarget[1]; // continue target
-      }
-
-      // Reserve a slot in the case table for the default label
-      AddCase(0, 0);
-
-      tok = ParseStatement(tok, brkCntTarget, CasesCnt);
-
-      // If there's no default target, will use the break target as default
-      if (!Cases[undoCases][1])
-        Cases[undoCases][1] = brkLabel;
-
-      // End of switch reached (not via break), skip conditional jumps
-      GenJumpUncond(brkLabel);
-      // Generate conditional jumps
-      GenNumLabel(lbl);
-      for (i = undoCases + 1; i < CasesCnt; i++)
-      {
-        GenJumpIfEqual(Cases[i][0], Cases[i][1]);
-      }
-      // If none of the cases matches, take the default case
-      if (Cases[undoCases][1] != brkLabel)
-        GenJumpUncond(Cases[undoCases][1]);
-      GenNumLabel(brkLabel); // break label
-
-      CasesCnt = undoCases;
-    }
-    else if (tok == tokCase)
-    {
-      int i;
-      GenStartCommentLine(); printf2("case\n");
-
-      if (!casesIdx)
-        //error("ParseStatement(): 'case' must be within 'switch' statement\n");
-        errorCtrlOutOfScope();
-
-      tok = GetToken();
-      if ((tok = ParseExpr(tok, &gotUnary, &synPtr, &constExpr, &exprVal, 0, 0)) != ':')
-        //error("ParseStatement(): ':' expected after 'case expression'\n");
-        errorUnexpectedToken(tok);
-
-      if (!gotUnary)
-        errorUnexpectedToken(tok);
-
-      anyIntTypeCheck(synPtr);
-      if (!constExpr)
-        //error("ParseStatement(): constant integer expression expected in 'case expression :'\n");
-        errorNotConst();
-
-      // Check for dups
-      exprVal = truncInt(exprVal);
-      for (i = casesIdx; i < CasesCnt; i++)
-        if (Cases[i][0] == exprVal)
-          error("Duplicate case value\n");
-
-      AddCase(exprVal, LabelCnt);
-      GenNumLabel(LabelCnt++); // case exprVal:
-
-      tok = GetToken();
-
-      // a statement is needed after "case:"
-      statementNeeded = 1;
-    }
-    else if (tok == tokDefault)
-    {
-      GenStartCommentLine(); printf2("default\n");
-
-      if (!casesIdx)
-        //error("ParseStatement(): 'default' must be within 'switch' statement\n");
-        errorCtrlOutOfScope();
-
-      if (Cases[casesIdx - 1][1])
-        //error("ParseStatement(): only one 'default' allowed in 'switch'\n");
-        errorUnexpectedToken(tok);
-
-      tok = GetToken();
-      if (tok != ':')
-        //error("ParseStatement(): ':' expected after 'default'\n");
-        errorUnexpectedToken(tok);
-
-      tok = GetToken();
-
-      GenNumLabel(Cases[casesIdx - 1][1] = LabelCnt++); // default:
-
-      // a statement is needed after "default:"
-      statementNeeded = 1;
-    }
-    else if (tok == tok_Asm)
-    {
-      tok = GetToken();
-      if (tok != '(')
-        //error("ParseStatement(): '(' expected after 'asm'\n");
-        errorUnexpectedToken(tok);
-
-      tok = GetToken();
-      if (tok != tokLitStr)
-        //error("ParseStatement(): string literal expression expected in 'asm ( expression )'\n");
-        errorUnexpectedToken(tok);
-
-      do
-      {
-        GetString('"', 0, 'a');
-        tok = GetToken();
-      } while (tok == tokLitStr); // concatenate adjacent string literals
-      printf2("\n");
-
-      if (tok != ')')
-        //error("ParseStatement(): ')' expected after 'asm ( expression'\n");
-        errorUnexpectedToken(tok);
-
-      tok = GetToken();
-      if (tok != ';')
-        //error("ParseStatement(): ';' expected after 'asm ( expression )'\n");
-        errorUnexpectedToken(tok);
-
-      tok = GetToken();
-    }
-    else if (tok == tokGoto)
-    {
-      if ((tok = GetToken()) != tokIdent)
-        errorUnexpectedToken(tok);
-      GenStartCommentLine(); printf2("goto %s\n", TokenIdentName);
-      GenJumpUncond(AddGotoLabel(TokenIdentName, 0));
-      if ((tok = GetToken()) != ';')
-        errorUnexpectedToken(tok);
-      tok = GetToken();
-    }
-    else
-    {
-      tok = ParseExpr(tok, &gotUnary, &synPtr, &constExpr, &exprVal, tokGotoLabel, 0);
-      if (tok == tokGotoLabel)
-      {
-        // found a label
-        GenStartCommentLine(); printf2("%s:\n", IdentTable + stack[0][1]);
-        GenNumLabel(AddGotoLabel(IdentTable + stack[0][1], 1));
-        // a statement is needed after "label:"
-        statementNeeded = 1;
-      }
-      else
-      {
-        if (tok != ';')
-          //error("ParseStatement(): ';' expected\n");
-          errorUnexpectedToken(tok);
-        if (gotUnary)
-          GenExpr();
-      }
-      tok = GetToken();
-    }
-  } while (statementNeeded);
-
-  return tok;
-}
-
-// TBD!!! think of ways of getting rid of casesIdx
-STATIC
-int ParseBlock(int BrkCntTarget[2], int casesIdx)
-{
-  int tok = GetToken();
-
-  // Catch redeclarations of function parameters by not
-  // beginning a new scope if this block begins a function
-  // (the caller of ParseBlock() must've begun a new scope
-  // already, before the function parameters).
-  if (BrkCntTarget == BrkCntTargetFxn)
-    BrkCntTarget = NULL;
-  else
-  // Otherwise begin a new scope.
-    PushSyntax('#');
-
-  for (;;)
-  {
-    if (tok == 0)
-      return tok;
-
-    if (tok == '}' && ParseLevel > 0)
-      return tok;
-
-    if (TokenStartsDeclaration(tok, 0))
-    {
-      tok = ParseDecl(tok, NULL, 0, 1);
-
-    }
-    else if (ParseLevel > 0 || tok == tok_Asm)
-    {
-      tok = ParseStatement(tok, BrkCntTarget, casesIdx);
-    }
-    else
-      //error("ParseBlock(): Unexpected token %s\n", GetTokenName(tok));
-      errorUnexpectedToken(tok);
-  }
-}
-
-int main(int argc, char** argv)
-{
-  // gcc/MinGW inserts a call to __main() here.
-  int i;
-
-  // Run-time initializer for SyntaxStack0[] to reduce
-  // executable file size (SyntaxStack0[] will be in .bss)
-  static unsigned char SyntaxStackInit[] =
-  {
-    tokVoid,     // SymVoidSynPtr
-    tokInt,      // SymIntSynPtr
-    tokUnsigned, // SymUintSynPtr
-    tokVoid,     // SymWideCharSynPtr
-    tokFloat,    // SymFloatSynPtr
-    tokIdent,    // SymFuncPtr
-    '[',
-    tokNumUint,
-    ']',
-    tokChar
-  }; // SyntaxStackCnt must be initialized to the number of elements in SyntaxStackInit[]
-  memcpy(SyntaxStack0, SyntaxStackInit, sizeof SyntaxStackInit);
-  SyntaxStackCnt = division(sizeof SyntaxStackInit , sizeof SyntaxStackInit[0]);
-
-  SyntaxStack1[SymFuncPtr] = DummyIdent = AddIdent("");
-
-
-  GenInit();
-
-  // Parse the command line arguments
-  for (i = 1; i < argc; i++)
-  {
-    // DONE: move code-generator-specific options to
-    // the code generator
-    if (GenInitParams(argc, argv, &i))
-    {
-      continue;
-    }
-    else if (!strcmp(argv[i], "--os"))
-    {
-      compileOS = 1;
-      continue;
-    }
-    else if (!strcmp(argv[i], "--bdos"))
-    {
-      compileUserBDOS = 1;
-      continue;
-    }
-    else if (!strcmp(argv[i], "-signed-char"))
-    {
-      // this is the default option
-      CharIsSigned = 1;
-      continue;
-    }
-    else if (!strcmp(argv[i], "-unsigned-char"))
-    {
-      CharIsSigned = 0;
-      continue;
-    }
-    else if (!strcmp(argv[i], "-leading-underscore"))
-    {
-      // this is the default option for x86
-      UseLeadingUnderscores = 1;
-      continue;
-    }
-    else if (!strcmp(argv[i], "-no-leading-underscore"))
-    {
-      // this is the default option for MIPS
-      UseLeadingUnderscores = 0;
-      continue;
-    }
-    else if (!strcmp(argv[i], "-label"))
-    {
-      if (i + 1 < argc)
-      {
-        LabelCnt = atoi(argv[++i]);
-        continue;
-      }
-    }
-    else if (!strcmp(argv[i], "-no-externs"))
-    {
-      GenExterns = 0;
-      continue;
-    }
-    else if (!strcmp(argv[i], "-verbose"))
-    {
-      warnings = verbose = 1;
-      continue;
-    }
-    else if (!strcmp(argv[i], "-Wall"))
-    {
-      warnings = 1;
-      continue;
-    }
-    else if (!strcmp(argv[i], "-I") || !strcmp(argv[i], "-SI"))
-    {
-      if (i + 1 < argc)
-      {
-        int len = strlen(argv[++i]) + 1;
-        if (argv[i - 1][1] == 'I')
-        {
-          if (MAX_SEARCH_PATH - SearchPathsLen < len)
-            //error("Path name too long\n");
-            errorFileName();
-          strcpy(SearchPaths + SearchPathsLen, argv[i]);
-          SearchPathsLen += len;
-        }
-        else
-        {
-          if (MAX_SEARCH_PATH - SysSearchPathsLen < len)
-            //error("Path name too long\n");
-            errorFileName();
-          strcpy(SysSearchPaths + SysSearchPathsLen, argv[i]);
-          SysSearchPathsLen += len;
-        }
-        continue;
-      }
-    }
-    else if (!strcmp(argv[i], "-nopp"))
-    {
-      // TBD!!! don't do preprocessing when this option is present
-      continue;
-    }
-    // DONE: '-D macro[=expansion]': '#define macro 1' when there's no '=expansion'
-    else if (!strcmp(argv[i], "-D"))
-    {
-      if (i + 1 < argc)
-      {
-        char id[MAX_IDENT_LEN + 1];
-        char* e = strchr(argv[++i], '=');
-        int len;
-        if (e)
-        {
-          len = e - argv[i];
-          e++;
-        }
-        else
-        {
-          len = strlen(argv[i]);
-          e = "1";
-        }
-        if (len > 0 && len <= MAX_IDENT_LEN)
-        {
-          int j, bad = 1;
-          memcpy(id, argv[i], len);
-          id[len] = '\0';
-          for (j = 0; j < len; j++)
-            if ((bad = !(id[j] == '_' || (!j * isalpha(id[j] & 0xFFu) + j * isalnum(id[j] & 0xFFu)))) != 0)
-              break;
-          if (!bad)
-          {
-            DefineMacro(id, e);
-            continue;
-          }
-        }
-      }
-    }
-    else if (argv[i][0] == '-')
-    {
-      // unknown option
-    }
-    else if (FileCnt == 0)
-    {
-      // If it's none of the known options,
-      // assume it's the source code file name
-      if (strlen(argv[i]) > MAX_FILE_NAME_LEN)
-        //error("File name too long\n");
-        errorFileName();
-      strcpy(FileNames[0], argv[i]);
-      if ((Files[0] = fopen(FileNames[0], "r")) == NULL)
-        //error("Cannot open file \"%s\"\n", FileNames[0]);
-        errorFile(FileNames[0]);
-      LineNos[0] = LineNo;
-      LinePoss[0] = LinePos;
-      FileCnt++;
-      continue;
-    }
-    else if (FileCnt == 1 && OutFile == NULL)
-    {
-      // This should be the output file name
-      if ((OutFile = fopen(argv[i], "w")) == NULL)
-        //error("Cannot open output file \"%s\"\n", argv[i]);
-        errorFile(argv[i]);
-      continue;
-    }
-
-    error("Invalid or unsupported command line option\n");
-  }
-
-  if (!FileCnt)
-    error("Input file not specified\n");
-  if (!OutFile)
-    error("Output file not specified\n");
-
-
-  GenInitFinalize();
-
-  // Define a few macros useful for conditional compilation
-  DefineMacro("__SMALLER_C__", "0x0100");
-  if (SizeOfWord == 2)
-    DefineMacro("__SMALLER_C_16__", "");
-  else if (SizeOfWord == 4)
-    DefineMacro("__SMALLER_C_32__", "");
-  if (OutputFormat == FormatSegHuge)
-    DefineMacro("__HUGE__", "");
-  if (OutputFormat == FormatSegUnreal)
-    DefineMacro("__UNREAL__", "");
-  if (CharIsSigned)
-    DefineMacro("__SMALLER_C_SCHAR__", "");
-  else
-    DefineMacro("__SMALLER_C_UCHAR__", "");
-
-  // populate CharQueue[] with the initial file characters
-  ShiftChar();
-
-  puts2(FileHeader);
-
-  // compile
-  ParseBlock(NULL, 0);
-
-  GenFin();
-
-  DumpSynDecls();
-
-  DumpMacroTable();
-
-
-  DumpIdentTable();
-
-  GenStartCommentLine(); printf2("Next label number: %d\n", LabelCnt);
-
-  if (warnings && warnCnt)
-    printf("%d warnings\n", warnCnt);
-  GenStartCommentLine(); printf2("Compilation succeeded.\n");
-
-  if (OutFile)
-    fclose(OutFile);
-
-  return 0;
-}

+ 0 - 20
BCC/userBDOS/lib/stdlib.c

@@ -154,26 +154,6 @@ word strcat(char* dest, char* src)
   return strcpy(dest+endOfDest, src);
 }
 
-/*
-Appends string from src to dest up to n characters
-Returns pointer to resulting dest string
-*/
-char *strncat(char *dest, char *src, word n)
-{
-  word len1 = strlen(dest);
-  word len2 = strlen(src);
-    
-  if (len2 < n) 
-  {
-	  strcpy(&dest[len1], src);
-  }
-  else
-  {
-    strncpy(&dest[len1], src, n);
-    dest[len1 + n] = '\0';
-  }
-  return dest;
-}
 
 /*
 Compares two strings a and b