Add support for #pragma foo(bar)

Report unsupported/unknown preprocessor directives.
Report line number of error rather than character offset.
diff --git a/libacc/acc.cpp b/libacc/acc.cpp
index 733f188..096500d 100644
--- a/libacc/acc.cpp
+++ b/libacc/acc.cpp
@@ -1039,16 +1039,35 @@
 
     class InputStream {
     public:
+        int getChar() {
+            if (bumpLine) {
+                line++;
+                bumpLine = false;
+            }
+            int ch = get();
+            if (ch == '\n') {
+                bumpLine = true;
+            }
+            return ch;
+        }
+        int getLine() {
+            return line;
+        }
+    protected:
+        InputStream() :
+            line(1), bumpLine(false) {
+        }
+    private:
         virtual int get() = 0;
-        virtual long tell() = 0;
+        int line;
+        bool bumpLine;
     };
 
     class FileInputStream : public InputStream {
     public:
         FileInputStream(FILE* in) : f(in) {}
-        virtual int get() { return fgetc(f); }
-        virtual long tell() { return ftell(f); }
     private:
+        virtual int get() { return fgetc(f); }
         FILE* f;
     };
 
@@ -1057,14 +1076,12 @@
         TextInputStream(const char* text, size_t textLength)
             : pText(text), mTextLength(textLength), mPosition(0) {
         }
+
+    private:
         virtual int get() {
             return mPosition < mTextLength ? pText[mPosition++] : EOF;
         }
-        virtual long tell() {
-            return mPosition;
-        }
 
-    private:
         const char* pText;
         size_t mTextLength;
         size_t mPosition;
@@ -1091,14 +1108,83 @@
     CodeBuf codeBuf;
     CodeGenerator* pGen;
 
-    static const int ERROR_BUF_SIZE = 512;
-    char mErrorBuf[ERROR_BUF_SIZE];
+    class String {
+    public:
+        String() {
+            mpBase = 0;
+            mUsed = 0;
+            mSize = 0;
+        }
+
+        ~String() {
+            if (mpBase) {
+                free(mpBase);
+            }
+        }
+
+        char* getUnwrapped() {
+            return mpBase;
+        }
+
+        void appendCStr(const char* s) {
+            int n = strlen(s);
+            memcpy(ensure(n), s, n + 1);
+        }
+
+        void append(char c) {
+            * ensure(1) = c;
+        }
+
+        void printf(const char* fmt,...) {
+            va_list ap;
+            va_start(ap, fmt);
+            vprintf(fmt, ap);
+            va_end(ap);
+        }
+
+        void vprintf(const char* fmt, va_list ap) {
+            char* temp;
+            int numChars = vasprintf(&temp, fmt, ap);
+            memcpy(ensure(numChars), temp, numChars+1);
+            free(temp);
+        }
+
+        size_t len() {
+            return mUsed;
+        }
+
+    private:
+        char* ensure(int n) {
+            size_t newUsed = mUsed + n;
+            if (newUsed > mSize) {
+                size_t newSize = mSize * 2 + 10;
+                if (newSize < newUsed) {
+                    newSize = newUsed;
+                }
+                mpBase = (char*) realloc(mpBase, newSize + 1);
+                mSize = newSize;
+            }
+            mpBase[newUsed] = '\0';
+            char* result = mpBase + mUsed;
+            mUsed = newUsed;
+            return result;
+        }
+
+        char* mpBase;
+        size_t mUsed;
+        size_t mSize;
+    };
+
+    String mErrorBuf;
+
     jmp_buf mErrorRecoveryJumpBuf;
 
+    String mPragmas;
+    int mPragmaStringCount;
+
     static const int ALLOC_SIZE = 99999;
 
-    /* depends on the init string */
-    static const int TOK_STR_SIZE = 48;
+    // Indentifiers start at 0x100 and increase by # (chars + 1) * 8
     static const int TOK_IDENT = 0x100;
     static const int TOK_INT = 0x100;
     static const int TOK_IF = 0x120;
@@ -1107,8 +1193,9 @@
     static const int TOK_BREAK = 0x190;
     static const int TOK_RETURN = 0x1c0;
     static const int TOK_FOR = 0x1f8;
-    static const int TOK_DEFINE = 0x218;
-    static const int TOK_MAIN = 0x250;
+    static const int TOK_PRAGMA = 0x218;
+    static const int TOK_DEFINE = TOK_PRAGMA + (7*8);
+    static const int TOK_MAIN = TOK_DEFINE + (7*8);
 
     static const int TOK_DUMMY = 1;
     static const int TOK_NUM = 2;
@@ -1168,7 +1255,7 @@
                 ch = dch;
             }
         } else
-            ch = file->get();
+            ch = file->getChar();
         /*    printf("ch=%c 0x%x\n", ch, ch); */
     }
 
@@ -1197,14 +1284,18 @@
                     pdef(TAG_TOK); /* fill last ident tag */
                     *(int *) tok = SYM_DEFINE;
                     *(char* *) (tok + 4) = dstk; /* define stack */
-                }
-                /* well we always save the values ! */
-                while (ch != '\n') {
+                    while (ch != '\n') {
+                        pdef(ch);
+                        inp();
+                    }
                     pdef(ch);
-                    inp();
+                    pdef(TAG_MACRO);
+                } else if (tok == TOK_PRAGMA) {
+                    doPragma();
+                } else {
+                    error("Unsupported preprocessor directive \"%s\"", last_id);
                 }
-                pdef(ch);
-                pdef(TAG_MACRO);
+
             }
             inp();
         }
@@ -1321,23 +1412,54 @@
 #endif
     }
 
+    void doPragma() {
+        // # pragma name(val)
+        int state = 0;
+        while(ch != EOF && ch != '\n' && state < 10) {
+            switch(state) {
+                case 0:
+                    if (isspace(ch)) {
+                        inp();
+                    } else {
+                        state++;
+                    }
+                    break;
+                case 1:
+                    if (isalnum(ch)) {
+                        mPragmas.append(ch);
+                        inp();
+                    } else if (ch == '(') {
+                        mPragmas.append(0);
+                        inp();
+                        state++;
+                    } else {
+                        state = 11;
+                    }
+                    break;
+                case 2:
+                    if (isalnum(ch)) {
+                        mPragmas.append(ch);
+                        inp();
+                    } else if (ch == ')') {
+                        mPragmas.append(0);
+                        inp();
+                        state = 10;
+                    } else {
+                        state = 11;
+                    }
+                    break;
+            }
+        }
+        if(state != 10) {
+            error("Unexpected pragma syntax");
+        }
+        mPragmaStringCount += 2;
+    }
 
     virtual void verror(const char* fmt, va_list ap) {
-        char* pBase = mErrorBuf;
-        int bytesLeft = sizeof(mErrorBuf);
-        int bytesAdded = snprintf(pBase, bytesLeft, "%ld: ", file->tell());
-        bytesLeft -= bytesAdded;
-        pBase += bytesAdded;
-        if (bytesLeft > 0) {
-            bytesAdded = vsnprintf(pBase, bytesLeft, fmt, ap);
-            bytesLeft -= bytesAdded;
-            pBase += bytesAdded;
-        }
-        if (bytesLeft > 0) {
-            bytesAdded = snprintf(pBase, bytesLeft, "\n");
-            bytesLeft -= bytesAdded;
-            pBase += bytesAdded;
-        }
+        mErrorBuf.printf("%ld: ", file->getLine());
+        mErrorBuf.vprintf(fmt, ap);
+        mErrorBuf.printf("\n");
         longjmp(mErrorRecoveryJumpBuf, 1);
     }
 
@@ -1680,7 +1802,7 @@
         pGlobalBase = 0;
         pVarsBase = 0;
         pGen = 0;
-        mErrorBuf[0] = 0;
+        mPragmaStringCount = 0;
     }
 
     void setArchitecture(const char* architecture) {
@@ -1745,9 +1867,10 @@
             pGen->init(&codeBuf);
             file = new TextInputStream(text, textLength);
             sym_stk = (char*) calloc(1, ALLOC_SIZE);
-            dstk = strcpy(sym_stk,
-                    " int if else while break return for define main ")
-                    + TOK_STR_SIZE;
+            static const char* predefinedSymbols =
+                " int if else while break return for pragma define main ";
+            dstk = strcpy(sym_stk, predefinedSymbols)
+                    + strlen(predefinedSymbols);
             pGlobalBase = (char*) calloc(1, ALLOC_SIZE);
             glo = pGlobalBase;
             pVarsBase = (char*) calloc(1, ALLOC_SIZE);
@@ -1810,8 +1933,26 @@
         return NULL;
     }
 
+    void getPragmas(ACCsizei* actualStringCount,
+                    ACCsizei maxStringCount, ACCchar** strings) {
+        int stringCount = mPragmaStringCount;
+        if (actualStringCount) {
+            *actualStringCount = stringCount;
+        }
+        if (stringCount > maxStringCount) {
+            stringCount = maxStringCount;
+        }
+        if (strings) {
+            char* pPragmas = mPragmas.getUnwrapped();
+            while (stringCount-- > 0) {
+                *strings++ = pPragmas;
+                pPragmas += strlen(pPragmas) + 1;
+            }
+        }
+    }
+
     char* getErrorMessage() {
-        return mErrorBuf;
+        return mErrorBuf.getUnwrapped();
     }
 
 };
@@ -1988,5 +2129,12 @@
     }
 }
 
+extern "C"
+void accGetPragmas(ACCscript* script, ACCsizei* actualStringCount,
+                   ACCsizei maxStringCount, ACCchar** strings){
+    script->compiler.getPragmas(actualStringCount, maxStringCount, strings);
+}
+
+
 } // namespace acc