* sim/ucsim/mkecho: inserted #!/bin/sh for Cygwin, so that it's executable
[fw/sdcc] / src / asm.c
index 733e338396933b0d62536329a1c7320efe3410e9..b22d352e269232a584926633aa9f1c73e3133afe 100644 (file)
--- a/src/asm.c
+++ b/src/asm.c
+/** @file asm.c
+    Provides output functions that modify the output string
+    based on the input tokens and the assembler token mapping
+    specification loaded.
+
+    Note that the functions below only handle digit format modifiers.
+    eg %02X is ok, but %lu and %.4u will fail.
+*/
 #include "common.h"
 #include "asm.h"
 
+#if defined __MINGW32__
+   // for O_BINARY in _pipe()
+#  include <fcntl.h>
+#elif !defined(__BORLANDC__) && !defined(_MSC_VER)
+   // for pipe and close
+#  include <unistd.h>
+#endif
+
+/* A 'token' is like !blah or %24f and is under the programmers
+   control. */
+#define MAX_TOKEN_LEN          64
+
 static hTab *_h;
 
-static const char *_findMapping(const char *szKey)
+char *
+FileBaseName (char *fileFullName)
 {
-    return shash_find(_h, szKey);
+  char *p = fileFullName;
+
+  if (!fileFullName) {
+    return "unknown";
+  }
+
+  while (*fileFullName)
+    {
+      if ((*fileFullName == '/') || (*fileFullName == '\\') || (*fileFullName == ':'))
+       {
+         p = fileFullName;
+         p++;
+       }
+      fileFullName++;
+    }
+  return p;
 }
 
-static va_list _iprintf(char *pInto, const char *szFormat, va_list ap)
+static const char *
+_findMapping (const char *szKey)
 {
-    char *pStart = pInto;
-    char *sz = gc_strdup(szFormat);
-    static int count;
-
-    while (*sz) {
-       if (*sz == '%') {
-           switch (*++sz) {
-               /* See if it's a special emitter */
-           case 'r':
-               wassert(0);
-               break;
-           /* Name of the code segment */
+  return shash_find (_h, szKey);
+}
+
+// Append a string onto another, and update the pointer to the end of
+// the new string.
+static char *
+_appendAt (char *at, char *onto, const char *sz)
+{
+  wassert (at && onto && sz);
+  strcpy (at, sz);
+  return at + strlen (sz);
+}
+
+void 
+tvsprintf (char *buffer, const char *format, va_list ap)
+{
+  // Under Linux PPC va_list is a structure instead of a primitive type,
+  // and doesnt like being passed around.  This version turns everything
+  // into one function.
+
+  // Supports:
+  //  !tokens
+  //  %[CIFN] - special formats with no argument (ie list isnt touched)
+  //  All of the system formats
+
+  // This is acheived by expanding the tokens and zero arg formats into
+  // one big format string, which is passed to the native printf.
+  static int count;
+  char noTokens[INITIAL_INLINEASM];
+  char newFormat[INITIAL_INLINEASM];
+  char *pInto = noTokens;
+  char *p;
+  char token[MAX_TOKEN_LEN];
+  const char *sz = format;
+
+  // NULL terminate it to let strlen work.
+  *pInto = '\0';
+
+  /* First pass: expand all of the macros */
+  while (*sz)
+    {
+      if (*sz == '!')
+       {
+         /* Start of a token.  Search until the first
+            [non alpha, *] and call it a token. */
+         const char *t;
+         p = token;
+         sz++;
+         while (isalpha (*sz) || *sz == '*')
+           {
+             *p++ = *sz++;
+           }
+         *p = '\0';
+         /* Now find the token in the token list */
+         if ((t = _findMapping (token)))
+           {
+             pInto = _appendAt (pInto, noTokens, t);
+           }
+         else
+           {
+             fprintf (stderr, "Cant find token \"%s\"\n", token);
+             wassert (0);
+           }
+       }
+      else
+        {
+          *pInto++ = *sz++;
+        }
+    }
+
+  *pInto = '\0';
+
+  /* Second pass: Expand any macros that we own */
+  sz = noTokens;
+  pInto = newFormat;
+
+  while (*sz)
+    {
+      if (*sz == '%')
+       {
+         // See if its one that we handle.
+         sz++;
+         switch (*sz)
+           {
            case 'C':
-               strcpy(pInto, CODE_NAME);
-               pInto = pStart + strlen(pStart);
-               sz++;
-               break;
+             // Code segment name.
+             pInto = _appendAt (pInto, newFormat, CODE_NAME);
+              sz++;
+             break;
            case 'F':
-               strcpy(pInto, srcFileName);
-               pInto = pStart + strlen(pStart);        
-               sz++;
-               break;
+             // Source file name.
+             pInto = _appendAt (pInto, newFormat, fullSrcFileName);
+              sz++;
+             break;
+            case 'N':
+              // Current function name.
+              pInto = _appendAt (pInto, newFormat, currFunc->rname);
+              sz++;
+              break;
            case 'I':
-               sprintf(pInto, "%u", ++count);
-               pInto = pStart + strlen(pStart);
-               sz++;
+             {
+               // Unique ID.
+               char id[20];
+               sprintf (id, "%u", ++count);
+               pInto = _appendAt (pInto, newFormat, id);
+                sz++;
                break;
+             }
            default:
+             // Not one of ours.  Copy until the end.
+             *pInto++ = '%';
+             while (!isalpha (*sz))
                {
-                   /* Scan out the arg and pass it on to sprintf */
-                   char *p = sz-1, tmp;
-                   while (isdigit(*sz))
-                       sz++;
-                   /* Skip the format */
-                   tmp = *++sz;
-                   *sz = '\0';
-                   vsprintf(pInto, p, ap);
-                   /* PENDING: Assume that the arg length was an int */
-                   va_arg(ap, int);
-                   *sz = tmp;
+                 *pInto++ = *sz++;
                }
+             *pInto++ = *sz++;
            }
-           pInto = pStart + strlen(pStart);
        }
-       else {
-           *pInto++ = *sz++;
+      else
+       {
+         *pInto++ = *sz++;
        }
     }
-    *pInto = '\0';
 
-    return ap;
-}
+  *pInto = '\0';
 
-void tvsprintf(char *buffer, const char *szFormat, va_list ap)
-{
-    char *sz = gc_strdup(szFormat);
-    char *pInto = buffer, *p;
-
-    buffer[0] = '\0';
-    
-    while (*sz) {
-       if (*sz == '!') {
-           /* Start of a token.  Search until the first
-              [non alplha, *] and call it a token. */
-           char old;
-           const char *t;
-           p = ++sz;
-           while (isalpha(*sz) || *sz == '*') {
-               sz++;
-           }
-           old = *sz;
-           *sz = '\0';
-           /* Now find the token in the token list */
-           if ((t = _findMapping(p))) {
-               ap = _iprintf(pInto, t, ap);
-               pInto = buffer + strlen(buffer);
-           }
-           else {
-               fprintf(stderr, "Cant find token \"%s\"\n", p);
-               wassert(0);
-           }
-           *sz = old;
-       }
-       else if (*sz == '%') {
-           char *pFormat = sz;
-           char old;
-           sz++;
-           while (!isalpha(*sz))
-               sz++;
-           sz++;
-           old = *sz;
-           *sz = '\0';
-           vsprintf(pInto, pFormat, ap);
-           pInto = buffer + strlen(buffer);
-           *sz = old;
-           va_arg(ap, int);
-       }
-       else {
-           *pInto++ = *sz++;
-       }
-    }
-    *pInto = '\0';
+  // Now do the actual printing
+  vsprintf (buffer, newFormat, ap);
 }
 
-void tfprintf(FILE *fp, const char *szFormat, ...)
+void 
+tfprintf (FILE * fp, const char *szFormat,...)
 {
-    va_list ap;
-    char buffer[MAX_INLINEASM];
+  va_list ap;
+  char buffer[INITIAL_INLINEASM];
 
-    va_start(ap, szFormat);
-    tvsprintf(buffer, szFormat, ap);
-    fputs(buffer, fp);
+  va_start (ap, szFormat);
+  tvsprintf (buffer, szFormat, ap);
+  fputs (buffer, fp);
 }
 
-void tsprintf(char *buffer, const char *szFormat, ...)
+void 
+tsprintf (char *buffer, const char *szFormat,...)
 {
-    va_list ap;
-    va_start(ap, szFormat);
-    tvsprintf(buffer, szFormat, ap);
+  va_list ap;
+  va_start (ap, szFormat);
+  tvsprintf (buffer, szFormat, ap);
 }
 
-void asm_addTree(const ASM_MAPPINGS *pMappings)
+void 
+asm_addTree (const ASM_MAPPINGS * pMappings)
 {
-    const ASM_MAPPING *pMap;
-    /* Traverse down first */
-    if (pMappings->pParent)
-       asm_addTree(pMappings->pParent);
-    pMap = pMappings->pMappings;
-    while (pMap->szKey && pMap->szValue) {
-       shash_add(&_h, pMap->szKey, pMap->szValue);
-       pMap++;
+  const ASM_MAPPING *pMap;
+
+  /* Traverse down first */
+  if (pMappings->pParent)
+    asm_addTree (pMappings->pParent);
+  pMap = pMappings->pMappings;
+  while (pMap->szKey && pMap->szValue) {
+      shash_add (&_h, pMap->szKey, pMap->szValue);
+      pMap++;
+  }
+}
+
+/*-----------------------------------------------------------------*/
+/* printILine - return the readable i-code for this ic             */
+/*                                                                 */
+/* iCodePrint wants a file stream so we need a pipe to fool it     */
+/*-----------------------------------------------------------------*/
+static char verbalICode[1024];
+
+char *printILine (iCode *ic) {
+  int filedes[2];
+  FILE *pipeStream;
+  iCodeTable *icTab=getTableEntry(ic->op);
+  
+#if defined __MINGW32__
+  assert(_pipe(filedes, 256, O_BINARY)!=-1); // forget it
+#else
+  assert(pipe(filedes)!=-1); // forget it
+#endif
+
+  // stuff the pipe with the readable icode
+  pipeStream=fdopen(filedes[1],"w");
+  icTab->iCodePrint(pipeStream, ic, icTab->printName);
+  // it really needs an extra push
+  fflush(pipeStream);
+  // now swallow it
+  pipeStream=fdopen(filedes[0],"r");
+  fgets(verbalICode, sizeof(verbalICode), pipeStream);
+  // clean up the mess, we'll return here for all icodes!!
+  assert(!close (filedes[0]));
+  assert(!close (filedes[1]));
+  // kill the trailing NL
+  verbalICode[strlen(verbalICode)-1]='\0';
+  // and throw it up
+  return verbalICode;
+}
+
+/*-----------------------------------------------------------------*/
+/* printCLine - return the c-code for this lineno                  */
+/*-----------------------------------------------------------------*/
+static FILE *inFile=NULL;
+static char inLineString[1024];
+static int inLineNo=0;
+static char lastSrcFile[PATH_MAX];
+int rewinds=0;
+
+char *printCLine (char *srcFile, int lineno) {
+  char *ilsP=inLineString;
+
+  if (inFile) {
+    if (strcmp (lastSrcFile, srcFile) != 0) {
+      fclose (inFile);
+      inFile = NULL;
+      inLineNo = 0;
+    }
+  }
+  if (!inFile) {
+    inFile=fopen(srcFile, "r");
+    if (!inFile) {
+      perror ("printCLine");
+      exit (1);
     }
+    strcpy (lastSrcFile, srcFile);
+  }
+  if (lineno<inLineNo) {
+    fseek (inFile, 0, SEEK_SET);
+    inLineNo=0;
+    rewinds++;
+  }
+  while (fgets (inLineString, 1024, inFile)) {
+    inLineNo++;
+    if (inLineNo==lineno) {
+      // remove the trailing NL
+      inLineString[strlen(inLineString)-1]='\0';
+      break;
+    }
+  }
+  while (isspace ((int)*ilsP))
+    ilsP++;
+
+  return ilsP;
 }
 
-static const ASM_MAPPING _asxxxx_mapping[] = {
-    { "labeldef", "%s::" },
-    { "slabeldef", "%s:" },
-    { "tlabeldef", "%05d$:" },
-    { "tlabel", "%05d$" },
-    { "immed", "#" },
-    { "zero", "#0x00" },
-    { "one", "#0x01" },
-    { "area", ".area %s" },
-    { "areacode", ".area %s" },
-    { "areadata", ".area %s" },
-    { "ascii", ".ascii \"%s\"" },
-    { "ds", ".ds %d" },
-    { "db", ".db" },
-    { "dbs", ".db %s" },
-    { "dw", ".dw" },
-    { "dws", ".dw %s" },
-    { "constbyte", "0x%02X" },
-    { "constword", "0x%04X" },
-    { "immedword", "#0x%04X" },
-    { "immedbyte", "#0x%02X" },
-    { "hashedstr", "#%s" },
-    { "lsbimmeds", "#<%s" },
-    { "msbimmeds", "#>%s" },
-    { "module", ".module %s" },
-    { "global", ".globl %s" },
-    { "fileprelude", "" },
-    { "functionheader", 
-      "; ---------------------------------\n"
-      "; Function %s\n"
-      "; ---------------------------------"
-    },
-    { "functionlabeldef", "%s:" },
-    { "bankimmeds", "0 ; PENDING: bank support" },
-    { NULL, NULL }
+static const ASM_MAPPING _asxxxx_mapping[] =
+{
+  {"labeldef", "%s::"},
+  {"slabeldef", "%s:"},
+  {"tlabeldef", "%05d$:"},
+  {"tlabel", "%05d$"},
+  {"immed", "#"},
+  {"zero", "#0x00"},
+  {"one", "#0x01"},
+  {"area", ".area %s"},
+  {"areacode", ".area %s"},
+  {"areadata", ".area %s"},
+  {"areahome", ".area %s"},
+  {"ascii", ".ascii \"%s\""},
+  {"ds", ".ds %d"},
+  {"db", ".db"},
+  {"dbs", ".db %s"},
+  {"dw", ".dw"},
+  {"dws", ".dw %s"},
+  {"constbyte", "0x%02X"},
+  {"constword", "0x%04X"},
+  {"immedword", "#0x%04X"},
+  {"immedbyte", "#0x%02X"},
+  {"hashedstr", "#%s"},
+  {"lsbimmeds", "#<%s"},
+  {"msbimmeds", "#>%s"},
+  {"module", ".module %s"},
+  {"global", ".globl %s"},
+  {"fileprelude", ""},
+  {"functionheader",
+   "; ---------------------------------\n"
+   "; Function %s\n"
+   "; ---------------------------------"
+  },
+  {"functionlabeldef", "%s:"},
+  {"bankimmeds", "0    ; PENDING: bank support"},
+  {"los","(%s & 0xFF)"},
+  {"his","(%s >> 8)"},
+  {"hihis","(%s >> 16)"},
+  {"hihihis","(%s >> 24)"},
+  {"lod","(%d & 0xFF)"},
+  {"hid","(%d >> 8)"},
+  {"hihid","(%d >> 16)"},
+  {"hihihid","(%d >> 24)"},
+  {"lol","(%05d$ & 0xFF)"},
+  {"hil","(%05d$ >> 8)"},
+  {"hihil","(%05d$ >> 16)"},
+  {"hihihil","(%05d$ >> 24)"},
+  {"equ","="},
+  {NULL, NULL}
+};
+
+static const ASM_MAPPING _gas_mapping[] =
+{
+  {"labeldef", "%s::"},
+  {"slabeldef", "%s:"},
+  {"tlabeldef", "%05d$:"},
+  {"tlabel", "%05d$"},
+  {"immed", "#"},
+  {"zero", "#0x00"},
+  {"one", "#0x01"},
+  {"area", ".section %s"},
+  {"areacode", ".section %s"},
+  {"areadata", ".section %s"},
+  {"areahome", ".section %s"},
+  {"ascii", ".ascii \"%s\""},
+  {"ds", ".ds %d"},
+  {"db", ".db"},
+  {"dbs", ".db %s"},
+  {"dw", ".dw"},
+  {"dws", ".dw %s"},
+  {"constbyte", "0x%02X"},
+  {"constword", "0x%04X"},
+  {"immedword", "#0x%04X"},
+  {"immedbyte", "#0x%02X"},
+  {"hashedstr", "#%s"},
+  {"lsbimmeds", "#<%s"},
+  {"msbimmeds", "#>%s"},
+  {"module", ".file \"%s.c\""},
+  {"global", ".globl %s"},
+  {"extern", ".globl %s"},
+  {"fileprelude", ""},
+  {"functionheader",
+   "; ---------------------------------\n"
+   "; Function %s\n"
+   "; ---------------------------------"
+  },
+  {"functionlabeldef", "%s:"},
+  {"bankimmeds", "0    ; PENDING: bank support"},  
+  {NULL, NULL}
+};
+
+static const ASM_MAPPING _a390_mapping[] =
+{
+  {"labeldef", "%s:"},
+  {"slabeldef", "%s:"},
+  {"tlabeldef", "L%05d:"},
+  {"tlabel", "L%05d"},
+  {"immed", "#"},
+  {"zero", "#0"},
+  {"one", "#1"},
+  {"area", "; SECTION NOT SUPPORTED"},
+  {"areacode", "; SECTION NOT SUPPORTED"},
+  {"areadata", "; SECTION NOT SUPPORTED"},
+  {"areahome", "; SECTION NOT SUPPORTED"},
+  {"ascii", "db \"%s\""},
+  {"ds", "; STORAGE NOT SUPPORTED"},
+  {"db", "db"},
+  {"dbs", "db \"%s\""},
+  {"dw", "dw"},
+  {"dws", "dw %s"},
+  {"constbyte", "0%02xh"},
+  {"constword", "0%04xh"},
+  {"immedword", "#0%04Xh"},
+  {"immedbyte", "#0%02Xh"},
+  {"hashedstr", "#%s"},
+  {"lsbimmeds", "#<%s"},
+  {"msbimmeds", "#>%s"},
+  {"module", "; .file \"%s.c\""},
+  {"global", "; .globl %s"},
+  {"fileprelude", ""},
+  {"functionheader",
+   "; ---------------------------------\n"
+   "; Function %s\n"
+   "; ---------------------------------"
+  },
+  {"functionlabeldef", "%s:"},
+  {"bankimmeds", "0    ; PENDING: bank support"},  
+  {"los","(%s & 0FFh)"},
+  {"his","((%s / 256) & 0FFh)"},
+  {"hihis","((%s / 65536) & 0FFh)"},
+  {"hihihis","((%s / 16777216) & 0FFh)"},
+  {"lod","(%d & 0FFh)"},
+  {"hid","((%d / 256) & 0FFh)"},
+  {"hihid","((%d / 65536) & 0FFh)"},
+  {"hihihid","((%d / 16777216) & 0FFh)"},
+  {"lol","(L%05d & 0FFh)"},
+  {"hil","((L%05d / 256) & 0FFh)"},
+  {"hihil","((L%05d / 65536) & 0FFh)"},
+  {"hihihil","((L%09d / 16777216) & 0FFh)"},
+  {"equ"," equ"},
+  {NULL, NULL}
 };
 
-const ASM_MAPPINGS asm_asxxxx_mapping = {
-    NULL,
-    _asxxxx_mapping
+static const ASM_MAPPING _xa_asm_mapping[] =
+{
+  {"labeldef", "%s:"},
+  {"slabeldef", "%s:"},
+  {"tlabeldef", "L%05d:"},
+  {"tlabel", "L%05d"},
+  {"immed", "#"},
+  {"zero", "#0"},
+  {"one", "#1"},
+  {"area", ".area %s"},
+  {"areacode", ".area %s"},
+  {"areadata", ".area %s"},
+  {"areahome", ".area %s"},
+  {"ascii", ".db \"%s\""},
+  {"ds", ".ds %d"},
+  {"db", ".db"},
+  {"dbs", ".db \"%s\""},
+  {"dw", ".dw"},
+  {"dws", ".dw %s"},
+  {"constbyte", "0x%02x"},
+  {"constword", "0x%04x"},
+  {"immedword", "0x%04x"},
+  {"immedbyte", "0x%02x"},
+  {"hashedstr", "#%s"},
+  {"lsbimmeds", "#<%s"},
+  {"msbimmeds", "#>%s"},
+  {"module", "; .module %s"},
+  {"global", ".globl %s"},
+  {"fileprelude", ""},
+  {"functionheader",
+   "; ---------------------------------\n"
+   "; Function %s\n"
+   "; ---------------------------------"
+  },
+  {"functionlabeldef", "%s:"},
+  {"bankimmeds", "0    ; PENDING: bank support"},  
+  {"los","(%s & 0FFh)"},
+  {"his","((%s / 256) & 0FFh)"},
+  {"hihis","((%s / 65536) & 0FFh)"},
+  {"hihihis","((%s / 16777216) & 0FFh)"},
+  {"lod","(%d & 0FFh)"},
+  {"hid","((%d / 256) & 0FFh)"},
+  {"hihid","((%d / 65536) & 0FFh)"},
+  {"hihihid","((%d / 16777216) & 0FFh)"},
+  {"lol","(L%05d & 0FFh)"},
+  {"hil","((L%05d / 256) & 0FFh)"},
+  {"hihil","((L%05d / 65536) & 0FFh)"},
+  {"hihihil","((L%09d / 16777216) & 0FFh)"},
+  {"equ"," equ"},
+  {NULL, NULL}
+};
+
+const ASM_MAPPINGS asm_asxxxx_mapping =
+{
+  NULL,
+  _asxxxx_mapping
 };
 
+const ASM_MAPPINGS asm_gas_mapping =
+{
+  NULL,
+  _gas_mapping
+};
+
+const ASM_MAPPINGS asm_a390_mapping =
+{
+  NULL,
+  _a390_mapping
+};
+
+const ASM_MAPPINGS asm_xa_asm_mapping =
+{
+  NULL,
+  _xa_asm_mapping
+};