C Programming Column
by Al Stevens


Listing One
#include <stdio.h>
#include "interp.h"
// ----- intrinsic functions
int iprntf(int* p)           //   printf   
{
    printf(reinterpret_cast<char*>(p[0]),p[1],p[2],p[3],p[4]);
    return 0;
}
int igtch()                 //  getchar
{
    return getchar();
}
int iptch(int* c)           //  putchar   
{
    return putchar(*c);
}
char* getver()              // return a string
{
    return "Version 1.0";
}
Intrinsic funcs[] = {
    Intrinsic("int printf",       reinterpret_cast<ifunc>(iprntf)),
    Intrinsic("int getchar",      reinterpret_cast<ifunc>(igtch) ),
    Intrinsic("int putchar",      reinterpret_cast<ifunc>(iptch) ),
    Intrinsic("string getversion",reinterpret_cast<ifunc>(getver)),
    Intrinsic("",        0)
};
// ---------- error messages 
char *erm[]={  "Unexpected end of file", "Unrecognized",
               "Duplicate ident",        "Undeclared ident",
               "Syntax Error",           "Unmatched {}",
               "Unmatched ()",           "Missing",
               "Not a function",         "Misplaced break",
               "Out of place",           "Not an identifer",
               "Mismatched arguments",   "Divide by zero",
               "Invalid constant",       "No main function"
};
static FILE *fp;
int main(int argc, char *argv[])
{
    if (argc == 2)  {
        if ((fp = fopen(argv[1], "r")) != 0) {
            try {
                SInterpreter si(funcs);
                si.interpret();
            }
            catch (SIException sex) {
                printf("\n%s %s on line %d\n",erm[sex.ercode], 
                            sex.msg.c_str(), sex.lineno);
            }
            fclose(fp);
        }
    }
    return 0;
}
// ----- functions that the interpreter requires
int getsource(void)     {   return getc(fp);    }
void ungetsource(int c) {   ungetc(c, fp);      }


Listing Two
// ---------------- interp.h --------------------
#include <vector>
#include <string>

// namespace DDJScriptInterpreter   {

// ----------- error codes
enum errs { EARLYEOF,           UNRECOGNIZED,
            DUPL_DECLARE,       UNDECLARED,
            SYNTAX,             BRACERR,
            PARENERR,           MISSING,
            NOTFUNC,            BREAKERR,
            OUTOFPLACE,         NOTIDENT,
            MISMATCHEDARG,      DIVIDEERR,
            INVALIDCONSTANT,    NOMAIN     };
class SIException {
public:
  errs ercode;
  int lineno;
  std::string msg;
  SIException(errs er = SYNTAX, int lno = 0, std::string m = std::string()) : 
                ercode(er), lineno(lno), msg(m)
        {  }
};
typedef int(*ifunc)(void*);
// --- intrinsic function table (provided by shell application)
class Intrinsic {
public:
    std::string signature;
    ifunc fn;
    Intrinsic(const std::string& sig = std::string(), ifunc f = 0) : 
                signature(sig), fn(f)
        {  }
};
typedef short int token;
enum DatumType { unknown, number, strng };
#define UNARY(op)                                                       \
Datum operator op () const                                              \
{                                                                       \
    nostring();                                                         \
    return Datum(op value);                                             \
}
#define RELATIONAL(op)                                                  \
bool operator op (const Datum& d) const                                 \
{                                                                       \
    sametype(d);                                                        \
    return (type == strng) ? (strval op d.strval) : (value op d.value); \
}
#define ARITHMETIC(op)                                                  \
Datum operator op (const Datum& d) const                                \
{                                                                       \
    nostring();                                                         \
    d.nostring();                                                       \
    return Datum(value op d.value);                                     \
}
#define LOGICAL(op)                                                     \
bool operator op (const Datum& d) const                                 \
{                                                                       \
    nostring();                                                         \
    d.nostring();                                                       \
    return value op d.value;                                            \
}
class Datum {
    void nostring() const
        { if (type == strng) throw SIException(); }
    void sametype(const Datum& d) const
        { if (type != d.type) throw SIException(); }
public:
    DatumType type;
    int value;          // number value
    std::string strval; // string value
    Datum() : type(unknown), value(0)
        {  }
    explicit Datum(int val) : type(number), value(val)
        {  }
    explicit Datum(std::string str) : type(strng), value(0), strval(str)
        {  }
    Datum& operator=(const Datum& d)
        { type = d.type; value = d.value; strval = d.strval; return *this; }
    Datum operator+(const Datum& d) const
    {
        sametype(d);
        if (type == strng)
            return Datum(strval + d.strval);    // concatenate strings
        return Datum(value + d.value);          // sum numbers
    }
    bool operator!() const
    {
        nostring();
        return !value;
    }
    UNARY(-)
    ARITHMETIC(*)
    ARITHMETIC(/)
    ARITHMETIC(-)
    RELATIONAL(<=)
    RELATIONAL(>=)
    RELATIONAL(!=)
    RELATIONAL(==)
    RELATIONAL(<)
    RELATIONAL(>)
    LOGICAL(&&)
    LOGICAL(||)
};
class Token {
public:
    token tok;
    Datum datum;
int tokennumber;
    Token(token t = 0) : tok(t)
        {  }
    bool operator<(const Token& t) const
        { return tok < t.tok; }
    bool operator==(const Token& t) const
        { return tok == t.tok; }
    Token& operator=(const Token& t)
        { tok = t.tok; datum = t.datum; return *this; }  
};
typedef std::vector<Token>          token_buffer;
typedef token_buffer::iterator      token_iter;
enum SymbolType { none, variable, ifunction, pfunction };
class Symbol {
public:
    SymbolType type;
    std::string name;
    Datum datum;
    int entry;          // subscript to function's first entry in token buffer
    ifunc fn;           // points to intrinsic function
    Symbol(SymbolType ty = none, const std::string nm = std::string() ) : 
            type(ty), name(nm), entry(0), fn(0)
        {  }
    bool operator<(const Symbol& s) const
        { return name < s.name; }
    bool operator==(const Symbol& s) const
        { return name == s.name; }
    Symbol& operator=(const Symbol& s)
        { type = s.type; name = s.name; datum = s.datum; 
                             entry = s.entry; fn = s.fn; return *this; }
};
typedef std::vector<Symbol>         symbol_table;
typedef symbol_table::iterator      symbol_iter;
class SInterpreter  {
    token_iter tokiter; // iterates the token buffer during interpreting
private:
    class Keyword {
    public:
        std::string kw;
        Token kwtoken;
        Keyword(const char* k, Token tk) : kw(k), kwtoken(tk)
            {  }
    };
    symbol_table    symboltable;
    token_buffer    tokens;
    int currentscope;   // index of first symbol table entry for current scope
    static token tokentbl[];
    static Keyword keywords[];
    Datum frtn;         // return value from a function     
    bool breaking, returning;
    int skipping;
    int linenumber;
    bool scanned;       // true when lexical scan is complete
    int LineNumber();   // current source file line number  
    void initialize();  // initialize data variables
    // functions for lexical scan
    void lexicalscan();
    bool declarator(bool islocal, bool isparameter = false);
    void declarators(bool islocal);
    Token compilenextsourcetoken();
    int escseq();
    int getsourcechar();
    int getrawsourcechar();

    // functions for compiling and interpreting program
    Token nexttoken();
    void prevtoken();
    Token needtoken(token tkn);
    Datum function(Symbol sym);

    bool findsymbol(int& ndx, const std::string& name, int fromscope = 0);
    void compound_statement(int scope);
    void statement();
    void outofscope();

    void statements();
    void skip_statements();

    bool istoken(token tkn);
    void skippair(token ltkn, token rtkn);

    Datum primary();
    Datum mult();
    Datum plus();
    Datum le();
    Datum eq();
    Datum and();
    Datum expression();

    bool isidentchar(int c)
    {
        return isalpha(c) || isdigit(c) || c == '_';
    }
    bool iswhite(int c)
    {
        return c == ' ' || c == '\t';
    }
public:
    explicit SInterpreter(const Intrinsic* inf);
    int interpret();
};
// } // namespace DDJScriptInterpreter
// ------ functions provided by the shell
int getsource();
void ungetsource(int ch);




5


