Logo Search packages:      
Sourcecode: ncc version File versions  Download package

parser.C

/*******************************************************************************

      C parser

*******************************************************************************/
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <unistd.h>
#include <assert.h>

#include "global.h"

exprtree CExpr;
lrt last_result_type;

//***************************************************************************
//          Forward
//***************************************************************************
static NormPtr constant_int_expression (NormPtr, int&);
static NormPtr parse_expression (NormPtr);
static NormPtr parse_structure (NormPtr);
//***************************************************************************
//          Declarations I
//***************************************************************************
static NormPtr skip_parens (NormPtr);
static NormPtr skip_brackets (NormPtr);
static int initializer_nsize (NormPtr, int);
static NormPtr get_enum_consts (NormPtr);

class declarator
{
      NormPtr p;
      int dp;
inline      void dcl ();
      void dirdcl ();
      void bitfield ();
      void arglist_to_specs ();
      NormPtr parse (NormPtr);

#ifdef GNU_VIOLATIONS
      NormPtr bt_typeof (NormPtr);
#endif
      NormPtr builtin (NormPtr);
      NormPtr bt_enum (NormPtr);
      NormPtr bt_typedef (NormPtr);
      NormPtr bt_struct (NormPtr);

      void complete_size ();
      void argument_conversions ();
      void semantics ();
      bool do_argument_conversions;
   public:
      ObjPtr basetype;
      bool have_extern, have_static, have_typedef, have_const,
           have_init, have_code, is_anonymous, is_struct_dcl;

      declarator (bool b = false) { do_argument_conversions = b; is_struct_dcl = false; }
      NormPtr parse_base (NormPtr);
      NormPtr parse_dcl (NormPtr);

      typeID gentype;
      NormPtr args;
      NormPtr psst, pslen;
      int symbol;
      int spec [MSPEC];
};
//***********************************************************************
//          definitions : declarator
//***********************************************************************

NormPtr declarator::parse (NormPtr i)
{
      p = i; dp = 0; args = symbol = -1; have_init = have_code = false;

      if (CODE [i] == ':' || (ISSYMBOL (CODE [i]) && CODE [i + 1] == ':'))
            bitfield ();
      else dcl ();

      /* Ben Lau for M68K Kernel from uClinux */
      if (CODE [p] == RESERVED___asm__)
            p = skip_parens (p + 1);

      spec [dp] = -1;
      have_init = CODE [p] == '=';
      have_code = CODE [p] == '{';

      return p;
}

void declarator::bitfield ()
{
      if (CODE [p] != ':') symbol = CODE [p++];
      spec [0] = ':';
      p = constant_int_expression (++p, spec [1]);
      dp = 2;
}

void declarator::dcl ()
{
      int ns = 0;

      for (;; p++)
            if (CODE [p] == '*') ++ns;
            else if (CODE [p] != RESERVED_const
                  && CODE [p] != RESERVED_volatile) break;
      dirdcl ();
      while (ns--) spec [dp++] = '*';
}

NormPtr array_size_expression (NormPtr p, int &r)
{
      NormPtr pe = constant_int_expression (p, r);
      if (CODE [p] != ']' && infuncs) {
            pe = parse_expression (p);
            r = 0;
      }
      return pe;
}

void declarator::dirdcl ()
{
      if (CODE [p] == '(') {
            ++p;
            dcl ();
            if (CODE [p++] != ')') syntax_error (p, "Missing parenthesis");
      } else if (ISSYMBOL (CODE [p]))
            symbol = CODE [p++];

      for (;;) {
            switch (CODE [p]) {
            case '(':
                  if (args == -1) args = p;
                  spec [dp++] = '(';
                  arglist_to_specs ();
                  continue;
            case '[':
                  if (CODE [++p] == ']') {
                        spec [dp++] = '[';
                        spec [dp++] = 0;
                        p++; continue;
                  }
                  spec [dp++] = '[';
                  p = array_size_expression (p, spec [dp++]);
                  if (CODE [p++] != ']')
                        syntax_error (p, "No :]");
                  continue;
            }
            break;
      }
}

void declarator::complete_size ()
{
      int t = CODE [p + 1];
      if (ISSTRING (t)) gstr: spec [1] = strlen (C_Strings [t - STRINGBASE]) + 1;
      else if (t == '(' && ISSTRING (CODE [p + 2]) && CODE [p + 3] == ')') {
            t = CODE [p + 2];
            goto gstr;
      } else if (t == '{') {
            int i, a = esizeof_objptr (basetype);
            for (i = 2; spec [i] == '['; i += 2)
                  a *= spec [i + 1];
            spec [1] = initializer_nsize (p + 1, a);
      } else syntax_error (p, "incomplete array initializer single");
}

void declarator::semantics ()
{
      int i = 0, v, dpi = dp;

      if (spec [0] == '(') {
            if (have_init) syntax_error (p, "Function != Variable");
      } else if (have_code) syntax_error (p, "Variable != Function");

      if (spec [0] == ':') {
            if (spec [1] < 0 || spec [1] > BITFIELD_Q)
                  syntax_error (p, "absurd");
            return;
      }

      while (i < dpi)
            if (spec [i] == '[') {
                  i += 2;
                  if (spec [i] == '(')
                        syntax_error (p, "array of functions");
            } else if (spec [i] == '(') {
                  i += 2;
                  v = spec [i];
                  if (v == '(' || v == '[')
                        syntax_error (p, "Function returning invalid");
            } else i++;
}

static int initializer_nsize (NormPtr p, int na)
{
      int ec = 1;
      NormPtr e = skip_brackets (p++);

      while (p < e)
            if (CODE [p] == ',') ec++, p++;
            else if (CODE [p] == '{') {
                  ec += na;
                  p = skip_brackets (p);
            } else p++;

      return na ? ec / na : ec;
}

static NormPtr skip_parens (NormPtr p)
{
      int ns = 0;

      for (; p < C_Ntok; p++)
            if (CODE [p] == '(') ++ns;
            else if (CODE [p] == ')')
                  if (--ns == 0) return p + 1;
      return syntax_error (p, "Unclosed parenthesis:)");
}

static NormPtr skip_brackets (NormPtr p)
{
      int ns = 0;

      for (; p < C_Ntok; p++)
            if (CODE [p] == '{') ++ns;
            else if (CODE [p] == '}')
                  if (--ns == 0) return p + 1;
      return syntax_error (p, "Unclosed brackets:}");
}

//***********************************************************************
//          definitions : declarator
//***********************************************************************

void declarator::argument_conversions ()
{
      int tspec [MSPEC], *tp = tspec, *vp = spec;

      if (basetype >= TYPEDEF_BASE && *vp == -1) {
            type t;
            opentype (basetype - TYPEDEF_BASE, t);
            if (t.spec [0] == '(') *tp++ = '*';
      }

      if (*vp == '(') *tp++ = '*';
      for (;;vp++) {
            switch (*vp) {
            case '*': *tp++ = '*'; continue;
            case '[': *tp++ = '*'; vp++; continue;
            case '(': *tp++ = '('; *tp++ = *++vp; continue;
            }
            *tp = -1;
            break;
      }
      intcpy (spec, tspec);
}

NormPtr declarator::parse_dcl (NormPtr p)
{
      p = parse (p);
      if (have_init && spec [0] == '[' && spec [1] == 0) complete_size ();
      semantics ();
      if (do_argument_conversions) argument_conversions ();
      gentype = gettype (basetype, spec);
      return p;
}

NormPtr declarator::parse_base (NormPtr p)
{
      have_extern = have_static = have_typedef = have_const = is_anonymous = false;

      while (ISDCLFLAG (CODE [p]))
            switch (CODE [p++]) {
            case RESERVED_extern:  have_extern  = true; break;
            case RESERVED_static:  have_static  = true; break;
            case RESERVED_typedef: have_typedef = true; break;
            case RESERVED_const:   have_const   = true; break;
            }

      if ((have_extern && have_static) || (have_extern && have_typedef)
      || (have_static && have_typedef)) syntax_error (p, "Decide");

      if (ISBASETYPE (CODE [p]) || ISHBASETYPE (CODE [p]))
            p =  builtin (p);
      else if (CODE [p] == RESERVED_struct || CODE [p] == RESERVED_union)
            p = bt_struct (p);
      else if (ISSYMBOL (CODE [p]))
            p = bt_typedef (p);
      else if (CODE [p] == RESERVED_enum)
            p = bt_enum (p + 1);
#ifdef GNU_VIOLATIONS
      else if (CODE [p] == RESERVED___typeof__)
            p = bt_typeof (p + 1);
      else if (CODE [p] == RESERVED___label__) {
            while (CODE [p] != ';') p++;
      }
#endif
      else basetype = S_INT;

      while (ISDCLFLAG (CODE [p]))
            switch (CODE [p++]) {
            case RESERVED_extern:  have_extern  = true; break;
            case RESERVED_static:  have_static  = true; break;
            case RESERVED_typedef: have_typedef = true; break;
            case RESERVED_const:   have_const   = true; break;
            }

      return p;
}

NormPtr declarator::builtin (NormPtr p)
{
      int bt, sh, lo, si, us;

      bt = sh = lo = si = us = 0;
      for (;ISBASETYPE (CODE [p]) || ISHBASETYPE (CODE [p])
       || CODE [p] == RESERVED_const; p++)
            switch (CODE [p]) {
            case RESERVED_long:     lo++; break;
            case RESERVED_short:    sh++; break;
            case RESERVED_signed:   si++; break;
            case RESERVED_unsigned: us++; break;
            case RESERVED_const:    continue;
            default: if (bt) syntax_error (p, "Please specify");
                  bt = CODE [p];
      }

      if (bt == 0) bt = RESERVED_int;
      if ((lo && sh) || (si && us)) syntax_error (p, "AMBIGUOUS specifiers");
      switch (bt) {
      case RESERVED_float: basetype = FLOAT; break;
      case RESERVED_double: basetype = DOUBLE; break;
      case RESERVED_void: basetype = VOID; break;
      case RESERVED_char: basetype = (us) ? U_CHAR : S_CHAR; break;
      case RESERVED_int:
            if (sh) basetype = (us) ? U_SINT : S_SINT;
            else if (lo == 1) basetype = (us) ? U_LINT : S_LINT;
            else if (lo > 1) basetype = (us) ? U_LONG : S_LONG;
            else basetype = (us) ? U_INT : S_INT;
      }

      return p;
}

NormPtr declarator::bt_enum (NormPtr p)
{
      basetype = S_INT;
      if (!ISSYMBOL (CODE [p]) && CODE [p] != '{')
            syntax_error (p, "DEAD rats after enum");

      if (CODE [p] != '{' && CODE [p + 1] != '{') {
            if (!valid_enumtag (CODE [p]) &&
                !introduce_enumtag (CODE [p], true))
                  syntax_error (p, "enum tag REDEFINED");
            return p + 1;
      }

      if (CODE [p] != '{')
            if (!introduce_enumtag (CODE [p++]))
                  syntax_error (p, "enum tag REDEFINED");

      return get_enum_consts (p);
}

NormPtr declarator::bt_typedef (NormPtr p)
{
      if ((basetype = lookup_typedef (CODE [p])) == -1) {
            basetype = S_INT;
            return p;
      }
      ++p;
      return ISHBASETYPE (CODE [p]) ? p + 1 : p;
}

NormPtr declarator::bt_struct (NormPtr p)
{
      bool isst = CODE [p++] == RESERVED_struct;

      if (!ISSYMBOL (CODE [p]) && CODE [p] != '{')
            syntax_error (p, "DEAD RATS after struct");

      if (CODE [p] != '{' && CODE [p + 1] != '{') {
            basetype = (CODE [p + 1] == ';')
                  ? fwd_struct_tag (CODE [p], isst)
                  : use_struct_tag (CODE [p], isst);
            return p + 1;
      }

      if ((is_anonymous = CODE [p] == '{'))
            basetype = introduce_anon_struct (isst);
      else if ((basetype = introduce_named_struct (CODE [p++], isst)) == -1)
            syntax_error (p, "Redefined structure tag");

      is_struct_dcl = true;
      psst = p++ - 1;
      p = parse_structure (p);
      pslen = p - psst;
      return p;
}

static NormPtr get_enum_consts (NormPtr p)
{
      int counter = 0, s;

      for (++p;;) {
            s = CODE [p++];
            if (s == '}') break;
            if (!ISSYMBOL (s))
                  syntax_error (p, "Random NOISE INSIDE ENUM");
            if (CODE [p] == '=')
                  p = constant_int_expression (++p, counter);
            if (!introduce_enumconst (s, counter++))
                  syntax_error (p, "Enumeration constant exists");
            s = CODE [p++];
            if (s == '}') break;
            if (s != ',')
                  syntax_error (p, "RANDOM noise inside enum");
      }

      return p;
}

//***************************************************************************
//          Forward
//***************************************************************************
static NormPtr initializer_expr (Symbol, NormPtr);
static NormPtr initializer_aggregate (Symbol, NormPtr);
static NormPtr parse_function (Symbol, NormPtr, NormPtr, NormPtr);
static bool is_dcl_start (int);
//***************************************************************************
//          Declarations II
//
//    Four places of declarators:
//    1) Declarator in code or global
//    2) Declarator inside structure block
//    3) Function argument list
//    4) (type cast)
//***************************************************************************
class cast_type
{
   public:
      typeID gentype;
      NormPtr parse (NormPtr);
};

class arglist
{
      NormPtr argument (NormPtr);
      NormPtr parse_newstyle (NormPtr);
      bool old_declaration (NormPtr);
      NormPtr parse_oldstyle (NormPtr, bool = false);
   public:
      bool nolist;
      typeID types [100];
      int names [100], ii;
      void parse_declare (NormPtr);
      NormPtr parse (NormPtr);
};

class declaration
{
   protected:
virtual     void semantics (NormPtr);
      NormPtr parse_initializer (NormPtr);
   public:
      declarator D;
      declaration (bool b = false) : D (b) { }
      NormPtr parse (NormPtr);
};

class declaration_instruct : public declaration
{
      void semantics (NormPtr);
};
//***********************************************************************
//          definitions:      cast, arglist
//***********************************************************************

NormPtr cast_type::parse (NormPtr p)
{
      declarator B;
      p = B.parse_dcl (B.parse_base (p));

      if (B.have_typedef || B.have_extern || B.have_static
      || B.have_code || B.have_init || B.symbol != -1
      || B.spec [0] == ':') syntax_error (p, "Improper cast");

      gentype = B.gentype;

      return p;
}

NormPtr arglist::argument (NormPtr p)
{
      declarator B (true);
      p = B.parse_dcl (B.parse_base (p));

      if (B.have_typedef || B.have_extern || B.have_static
      || B.have_code || B.have_init || B.spec [0] == ':')
            syntax_error (p, "Crap argument");

      names [ii] = B.symbol;
      types [ii++] = B.gentype;

      return p;
}

bool arglist::old_declaration (NormPtr p)
{
      return ISSYMBOL (CODE [p])
             && (CODE [p + 1] == ',' || CODE [p + 1] == ')')
             && lookup_typedef (CODE [p]) == -1;
}

NormPtr arglist::parse_newstyle (NormPtr p)
{
      ii = 0;

      if (CODE [p] == ')') {
            nolist = true;
            return p + 1;
      }

      if (CODE [p] == RESERVED_void && CODE [p + 1] == ')')
            return p + 2;

      while (1) {
            if (CODE [p] == ELLIPSIS) {
                  types [ii++] = SPECIAL_ELLIPSIS;
                  if (CODE [p + 1] != ')')
                        syntax_error (p, "'...' must be last");
                  return p + 2;
            }
            switch (CODE [p = argument (p)]) {
            default: syntax_error (p, "Invalid argument list");
            case ')': return p + 1;
            case ',': p++;
            }
      }

      return p + 1;
}

NormPtr arglist::parse_oldstyle (NormPtr p, bool dcl)
{
      // few syntax/semantics tests. We suppose old program, which
      // is syntactically correct for the last 10 years 
      int i = 0, j;
      ii = 1;
      types [0] = ARGLIST_OPEN;
      types [1] = -1;

      if (CODE [p] != ')')
            do names [i++] = CODE [p++]; while (CODE [p++] == ',');

      if (dcl) {
            declaration D (true);
            while (CODE [p] != '{') {
                  p = D.parse (p);
                  for (j = 0; j < i; j++)
                        if (names [j] == D.D.symbol) {
                              names [j] = -1;
                              break;
                        }
            }
            for (j = 0; j < i; j++) if (names [j] != -1)
                  introduce_obj (names [j], SIntType, DEFAULT);
      } else {
            if (!is_dcl_start (CODE [p])) return p;
            while (CODE [p] != '{') p++;
      }
      return p;
}

void arglist::parse_declare (NormPtr p)
{
      if (old_declaration (p)) {
            parse_oldstyle (p, true);
            return; 
      }

      int i;
      parse_newstyle (p);

      for (i = 0; i < ii; i++)
            if (types [i] != SPECIAL_ELLIPSIS) {
                  if (names [i] == -1)
                        syntax_error (p, "Abstract argument");
                  introduce_obj (names [i], types [i], DEFAULT);
            }
}

NormPtr arglist::parse (NormPtr p)
{
      nolist = false;
      return old_declaration (p) ? parse_oldstyle (p) : parse_newstyle (p);
}

void declarator::arglist_to_specs ()
{
      arglist A;
      p = A.parse (p + 1);
      if (A.nolist) A.types [A.ii++] = ARGLIST_OPEN;
      A.types [A.ii] = -1;
      spec [dp++] = make_arglist (A.types);
}

//***********************************************************************
//          definitions:      declaration, instructure
//***********************************************************************

NormPtr declaration::parse (NormPtr p)
{
      VARSPC vs;
      bool ok;
      typeID t;
      NormPtr dclstart = p;   // to report beginning of function...

      D.is_struct_dcl = false;
      p = D.parse_base (p);
      if (CODE [p] == ';') {
            if (D.is_struct_dcl && usage_only && report_structs && !D.is_anonymous) {
                  D.is_struct_dcl = false;
                  struct_location (D.basetype, D.psst, D.pslen);
            } else if (D.is_struct_dcl && D.is_anonymous)
                  spill_anonymous (D.basetype);
      } else while (CODE [p] != ';') {
            p = D.parse_dcl (p);

            semantics (p);
            t = D.gentype;

            vs = (D.have_extern)?EXTERN:(D.have_static)?STATIC:DEFAULT;

            if (D.have_typedef) ok = introduce_tdef (D.symbol, t);
            else ok = introduce_obj (D.symbol, t, vs);
            if (!ok) syntax_error (p, "redefined: ", expand (D.symbol));

            if (D.is_anonymous) D.is_anonymous = !rename_struct (t, D.symbol);

            if (D.is_struct_dcl && usage_only && report_structs) {
                  D.is_struct_dcl = false;
                  struct_location (D.basetype, D.psst, D.pslen);
            }

            if (D.have_code) return parse_function (D.symbol, D.args, p, dclstart);
            if (D.have_init) p = parse_initializer (p + 1);

            if (CODE [p] == ';') break;
            if (CODE [p] != ',') {
                  if (CODE [p] != RESERVED___asm__)
                  syntax_error(p, "unaccaptable declaration, separator;",
                               expand (CODE [p]));
                  p = skip_parens (p + 1);
                  continue;
            }
            p++;
      }

      return p + 1;
}

NormPtr declaration::parse_initializer (NormPtr p)
{
      if (CODE [p] != '{')
            return initializer_expr (D.symbol, p);

#ifdef PARSE_ARRAY_INITIALIZERS
      return initializer_aggregate (D.symbol, p);
#else
      return base_of (D.gentype) < _BTLIMIT ?
             skip_brackets (p) : initializer_aggregate (D.symbol, p);
#endif
}

void declaration::semantics (NormPtr p)
{
      if (D.spec [0] == ':'
      || (D.have_typedef && (D.have_init || D.have_code)))
            syntax_error (p, "Not the \"right thing\"");
      if (D.symbol == -1) syntax_error (p, "ABSENT symbol");
      if (D.have_code && !INGLOBAL)
            syntax_error (p, "Do you like nested functions?");
}

void declaration_instruct::semantics (NormPtr p)
{
      if (D.have_static || D.have_extern || D.have_typedef
      || D.spec [0] == '(' || D.have_init || D.have_code
      || (D.symbol == -1 && D.spec [0] != ':'))
            syntax_error (p, "Not good dcl in struct");
}

static bool is_typename (int token)
{
      return token == RESERVED_struct || token == RESERVED_union
            || ISBASETYPE(token) || ISHBASETYPE (token) 
            || token == RESERVED_enum
            || (ISSYMBOL (token) && is_typedef (token));
}

static bool is_dcl_start (int token)
{
      return ISDCLFLAG (token) || is_typename (token)
#ifdef GNU_VIOLATIONS
            || token == RESERVED___label__
            || token == RESERVED___typeof__
#endif
                        ;
}

//**************************************************************************
//          Part II
//
//    By now we are ok with the declarations (introducing new names
//    to the program). Whenever we see a declaration, invoke a declarator.
//    We can at any time lookup what's an identifier, with lookup().
//
//    Missing:
//          parsing expressions in initializers
//
//    But this is ok, because this is exactly what we are going to
//    do now.
//**************************************************************************
//                C expressions
//**************************************************************************
NormPtr ExpressionPtr;

static int bopid;

static int priority (int op)
{
      if (op > 256) switch (op) {
            case LSH:   bopid = SHL;      return 11;
            case RSH:   bopid = SHR;      return 11;
            case GEQCMP:      bopid = CGRE;     return 10;
            case LEQCMP:      bopid = CLEE;     return 10;
            case EQCMP: bopid = BEQ;      return 9;
            case NEQCMP:      bopid = BNEQ;     return 9;
            case ANDAND:      bopid = IAND;     return 5;
            case OROR:  bopid = IOR;      return 4;
            default:                return 0;
      }
      switch (op) {
            case '*':   bopid = MUL;      return 13;
            case '/':   bopid = DIV;      return 13;
            case '%':   bopid = REM;      return 13;
            case '+':   bopid = ADD;      return 12;
            case '-':   bopid = SUB;      return 12;
            case '>':   bopid = CGR;      return 10;
            case '<':   bopid = CLE;      return 10;
            case '&':   bopid = BAND;     return 8;
      }
      if (op == '^') {
            bopid = BXOR;
            return 7;
      }
      if (op != '|') return 0;
      bopid = BOR;
      return 6;
}

static int xlate_uop (int op)
{
      switch (op) {
            case '!':   return LNEG;
            case '*':   return PTRIND;
            case '+':   return UPLUS;
            case '-':   return UMINUS;
            case '&':   return ADDROF;
      }
      switch (op) {
            case PLUSPLUS:          return PPPRE;
            case MINUSMINUS:  return MMPRE;
            default:          return OCPL;
      }
}

subexpr *&ee = CExpr.ee;
int &NeTop = CExpr.ne;

class expression_parser
{
inline      void reloc ();
      void value_to_expression (exprID, Symbol);
#ifdef GNU_VIOLATIONS
      exprID gnu_st_expr ();
      exprID gnu_ctor_expr (typeID);
#endif
#ifdef LABEL_VALUES
      exprID gnu_label_value ();
#endif
      exprID sizeof_typename ();
      exprID unary_expression ();
      exprID argument_expression_list ();
      exprID primary_expression ();
      exprID prefix_expression ();
      exprID binary_expression (exprID, int);
      exprID logicalOR_expression ();

      int nee, extra;
    public:
      expression_parser (NormPtr, subexpr*);

      exprID postfix_expression ();
      exprID assignment_expression ();
      exprID conditional_expression ();
      exprID expression ();

      NormPtr EP;
      subexpr *ee;
      int iee;
      ~expression_parser ();
};

//***********************************************************************
//          definitions
//***********************************************************************

exprID expression_parser::sizeof_typename ()
{
      cast_type T;
      EP = T.parse (EP + 2);
      if (CODE [EP++] != ')') syntax_error (EP, "erroneous sizeof");
      ee [iee].action = VALUE;
      exprID c = sizeof_typeID (T.gentype);
      ee [iee].voici.value = c;
      return iee++;
}

#define ISUNARY(x) \
      ((x<'~') ? (x=='!'||x=='*'||x=='&'||x=='-'||x=='+')\
      : (x==PLUSPLUS || x==MINUSMINUS || x=='~'))

exprID expression_parser::unary_expression ()
{
      int prefix [40];
      typeID casts [40];
      int ipr = 0, t;
      exprID e = -1;

      for (t = CODE [EP]; t < STRINGBASE; t = CODE [++EP])
            if (ISUNARY (t)) prefix [ipr++] = xlate_uop (t);
            else if (t == '(')
                  if (is_dcl_start (CODE [EP + 1])) {
                        cast_type C;
                        EP = C.parse (EP + 1);
                        casts [ipr] = C.gentype;
                        prefix [ipr++] = CAST;
#ifdef GNU_VIOLATIONS
                        if (CODE [EP + 1] == '{') {
                              e = gnu_ctor_expr (C.gentype);
                              goto have_unary;
                        }
#endif
                  } else break;
            else if (t == RESERVED_sizeof)
                  if (CODE [EP+1] == '(' && is_dcl_start (CODE [EP+2])) {
                        e = sizeof_typename ();
                        goto have_unary;
                  } else prefix [ipr++] = SIZEOF;
#ifdef LABEL_VALUES
            else if (t == ANDAND) {
                  e = gnu_label_value ();
                  goto have_unary;
            }
#endif
            else break;
            
      if ((e = postfix_expression ()) == -1 && ipr > 0)
            syntax_error (EP, "prefix operator w/o operand");

have_unary:
      reloc (); /* * */
      while (ipr--) {
            ee [iee].voici.e = e;
            if ((ee [iee].action = prefix [ipr]) == CAST)
                  ee [iee].voila.cast = casts [ipr];
            e = iee++;
      }

      return e;
}

exprID expression_parser::primary_expression ()
{
      int t = CODE [EP++];

      if (ISSYMBOL (t)) {
            ee [iee].action = SYMBOL;
            ee [iee].voici.symbol = t;
            return iee++;
      }

      if (ISNUMBER (t) || ISSTRING (t)) {
            value_to_expression (iee, t);
            return iee++;
      }

      if (t != '(') {
            EP--;
            return -1;
      }

      exprID e;
#ifdef GNU_VIOLATIONS
      if (CODE [EP] == '{') e = gnu_st_expr (); else
#endif
      e = expression ();
      if (CODE [EP++] != ')')
            syntax_error (EP, "parse error");
      return e;
}

exprID expression_parser::postfix_expression ()
{
      exprID e = primary_expression (), c;
      if (e == -1) return -1;

      int t;
      for (t = CODE [EP];; t = CODE [++EP]) {
            ee [iee].voici.e = e;

            switch (t) {
            case PLUSPLUS:
                  ee [e = iee++].action = PPPOST; break;
            case MINUSMINUS:
                  ee [e = iee++].action = MMPOST; break;
            case '[':
                  EP++;
                  ee [e = iee++].action = ARRAY;
                  c = expression ();
                  ee [e].e = c;
                  if (CODE [EP] != ']')
                        syntax_error (EP, "missing ']'");
                  break;
            case '(':
                  EP++;
                  ee [e = iee++].action = FCALL;
                  c = argument_expression_list ();
                  ee [e].e = c;
                  if (CODE [EP] != ')')
                        syntax_error (EP, "missing ')'");
                  break;
            case POINTSAT:
                  ee [e = iee++].action = PTRIND;
                  ee [iee].voici.e = e;
            case '.':
                  ee [e = iee++].action = MEMB;
                  ee [e].voila.member = CODE [++EP];
                  if (!ISSYMBOL (ee [e].voila.member))
                        syntax_error (EP, "->members only");
                  break;
            default:
                  return e;
            }
      }
}

exprID expression_parser::binary_expression (exprID lop, int pri)
{
static      int p2;
      int coperator = bopid;
      exprID e;
      EP++;
      if ((e = unary_expression ()) == -1)
            syntax_error (EP, "two operands expected");

      p2 = priority (CODE [EP]);
      while (p2 > pri)
            e = binary_expression (e, p2);

      ee [iee].voici.e = lop;
      ee [iee].action = coperator;
      ee [iee].e = e;
      e = iee++;

      return (p2 < pri) ? e : binary_expression (e, pri);
}

exprID expression_parser::logicalOR_expression ()
{
      int p;
      exprID e = unary_expression ();
      if (e == -1) return -1;

      while ((p = priority (CODE [EP])))
            e = binary_expression (e, p);

      return e;
}

exprID expression_parser::conditional_expression ()
{
      exprID e = logicalOR_expression (), c;
      if (e == -1) return -1;

      if (CODE [EP] == '?') {
            ee [iee].voici.e = e;
            ee [e = iee++].action = COND;
            EP++;
            c = expression ();
            ee [e].e = c;
            if (CODE [EP++] != ':')
                  syntax_error (EP, "(what) ? is ':' missing");
            if ((c = conditional_expression ()) == -1)
                  syntax_error (EP, "(what) ? is : missing");
            ee [e].voila.eelse = c;
      }

      return e;
}

exprID expression_parser::assignment_expression ()
{
      exprID e = conditional_expression (), c;
      if (e == -1) return -1;

      if (!ISASSIGNMENT (CODE [EP])) return e;

      ee [iee].voici.e = e;
      ee [e = iee++].action = CODE [EP++];
      if ((c = assignment_expression ()) == -1)
            syntax_error (EP, " = (missing operand)");
      ee [e].e = c;

      return e;
}

exprID expression_parser::expression ()
{
      exprID e = assignment_expression (), c;
      if (e == -1) return -1;

      if (CODE [EP] == ',') {
            ++EP;
            ee [iee].voici.e = e;
            ee [e = iee++].action = COMMA;
            c = expression ();
            ee [e].e = c;
      }

      return e;
}

exprID expression_parser::argument_expression_list ()
{
      exprID e = assignment_expression (), c;
      if (e == -1) return -1;

      if (CODE [EP] == ',') {
            ++EP;
            ee [iee].voici.e = e;
            ee [e = iee++].action = ARGCOMMA;
            c = argument_expression_list ();
            ee [e].e = c;
      }

      return e;
}

expression_parser::expression_parser (NormPtr p, subexpr *tee)
{
#define STDNEE 138
      ExpressionPtr = EP = p;
      nee = STDNEE;
      extra = false;
      ee = tee;
      iee = 0;
}

void expression_parser::reloc ()
{
#define RELOCAT 10
      if (nee - iee < RELOCAT) {
            subexpr *bigger = new subexpr [nee += 32];
            memcpy (bigger, ee, iee * sizeof ee [0]);
            if (extra) delete [] ee;
            ee = bigger;
            extra = true;
      }
}

expression_parser::~expression_parser ()
{
      if (extra) delete [] ee;
}
//***********************************************************************
//          definitions
//***********************************************************************

void expression_parser::value_to_expression (exprID i, Symbol s)
{
      if (ISSTRING (s)) {
            ee [i].action = SVALUE;
            ee [i].voici.value = s - STRINGBASE;
            return;
      }

      if (s >= INUMBER) {
            ee [i].action = UVALUE;
            ee [i].voici.uvalue = s - INUMBER;
            return;
      }

      if (s >= FLOATBASE) {
            ee [i].action = FVALUE;
            ee [i].voici.fvalue = C_Floats [s - FLOATBASE];
            return;
      }

      if (s >= UINT32BASE) {
            ee [i].action = UVALUE;
            ee [i].voici.uvalue = C_Unsigned [s - UINT32BASE];
            return;
      }

      ee [i].action = VALUE;
      ee [i].voici.value = getint (s);
}

static NormPtr parse_expression (NormPtr p)
{
      subexpr tee [STDNEE];
      expression_parser PP (p, tee);

      CExpr.first = PP.expression ();
      CExpr.ee = PP.ee;
      CExpr.ne = PP.iee;
      if (!usage_only) prcode (p, PP.EP - p);
      ncc->cc_expression ();
      return PP.EP;
}

static NormPtr constant_int_expression (NormPtr p, int &r)
{
      if (ISNUMBER (CODE [p]) && CODE [p] < UINT32BASE
      && !priority (CODE [p + 1])) {
            r = getint (CODE [p]);
            return p + 1;
      }

      subexpr tee [STDNEE];
      expression_parser PP (p, tee);

      CExpr.first = PP.conditional_expression ();
      CExpr.ee = PP.ee;
      CExpr.ne = PP.iee;
      r = cc_int_expression ();
      return PP.EP;
}

//**************************************************************************
//
//    Some GNU Violations we don't like
//
//**************************************************************************
#ifdef GNU_VIOLATIONS
static NormPtr compound_statement (NormPtr p);
exprID expression_parser::gnu_st_expr ()
{
      EP = compound_statement (EP + 1);
      ee [iee].action = COMPOUND_RESULT;
      ee [iee].voici.using_result = last_result;
      ee [iee].voila.result_type = gettype (last_result_type.base,
                                    last_result_type.spec);
      return iee++;
}

static NormPtr initializer_aggregate (Symbol, NormPtr);

exprID expression_parser::gnu_ctor_expr (typeID c)
{
      open_compound ();
      introduce_obj (intern_sym, c, DEFAULT);
      EP = initializer_aggregate (intern_sym, EP + 1);
      //EP = skip_brackets (EP + 1);
      close_region ();
      ee [iee].action = VALUE;
      return iee++;
}

NormPtr declarator::bt_typeof (NormPtr p)
{
      if (CODE [p++] != '(') syntax_error (p, "typeof '('");
      if (is_dcl_start (CODE [p])) {
            cast_type C;
            p = C.parse (p);
            basetype = C.gentype + TYPEDEF_BASE;
      } else {
            subexpr tee [STDNEE];
            expression_parser PP (p, tee);
            CExpr.first = PP.expression ();
            CExpr.ee = PP.ee;
            CExpr.ne = PP.iee;
            basetype = typeof_expression ();
            p = PP.EP;
      }
      if (CODE [p] != ')') syntax_error (p, "typeof ')'");
      return p + 1;
}
#endif

#ifdef LABEL_VALUES
exprID expression_parser::gnu_label_value ()
{
      int s = CODE [++EP];
      if (!ISSYMBOL (s)) syntax_error (EP, "&&identifier only, for labels");
      ee [iee].action = AVALUE;
      ee [iee].voici.symbol = s;
      EP++;
      return iee++;
}
#endif
//**************************************************************************
//          Part III
//
//    statements, this is really easy
//**************************************************************************

static int IDLEV = -1;
#define PCMD(CMD) \
      if (pseudo_code) {\
            printf ("#X: %s\n", CMD);\
      }
struct PINDENT { PINDENT () { IDLEV += 1; } ~PINDENT () { PCMD ("*"); IDLEV -= 1; } };
#define PSEUDOCODE(CMD) PINDENT P; PCMD(CMD);

static NormPtr while_statement (NormPtr p);
static NormPtr for_statement (NormPtr p);
static NormPtr do_statement (NormPtr p);
static NormPtr switch_statement (NormPtr p);
static NormPtr if_statement (NormPtr p);
static NormPtr compound_statement (NormPtr p);
static NormPtr __asm___statement (NormPtr p);

static NormPtr statement (NormPtr p)
{
      int t = CODE [p++];

      if (ISSYMBOL (t) && CODE [p] == ':')
            return CODE [p + 1] == '}' ? p + 1 : statement (p + 1);

      switch (t) {
      case RESERVED_default:
            if (CODE [p] != ':') syntax_error (p, "default:");
            return p + 1;
      case RESERVED_case:
            int tmp;
            p = constant_int_expression (p, tmp);
            if (CODE [p] == ELLIPSIS) p = constant_int_expression (p + 1, tmp);
            if (CODE [p] != ':') syntax_error (p, "case ERROR:");
            return p + 1;
      case RESERVED_continue:
      case RESERVED_break:
            if (CODE [p] != ';') syntax_error (p, "break | continue ';'");
            return p + 1;
      case RESERVED_goto:
            if (ISSYMBOL (CODE [p]) && CODE [p + 1] == ';')
                  return p + 2;
      case RESERVED_return:
            p = parse_expression (p);
            if (CODE [p] != ';') syntax_error (p, "return ... ';'");
            return p + 1;
      case RESERVED_while:    return while_statement (p);
      case RESERVED_for:      return for_statement (p);
      case RESERVED_do: return do_statement (p);
      case RESERVED_switch:   return switch_statement (p);
      case RESERVED_if: return if_statement (p);
      case RESERVED___asm__:  return __asm___statement (p);
      case RESERVED_else:     syntax_error (p, "else without if");
      case '{':         return compound_statement (p);
      default:
            p = parse_expression (p - 1);
            if (CODE [p++] != ';')
                  syntax_error (p, "expression + ';' = statement");
      case ';':
            return p;
      }
}

static NormPtr parenth_expression (NormPtr p)
{
      if (CODE [p++] != '(')
            syntax_error (p, "'(' expression");
      p = parse_expression (p);
      if (CODE [p++] != ')')
            syntax_error (p, "expression ')'");
      return p;
}

static NormPtr while_statement (NormPtr p)
{
      PSEUDOCODE ("REPEAT");
      return statement (parenth_expression (p));
}

static NormPtr do_statement (NormPtr p)
{
      PSEUDOCODE ("REPEAT");
      p = statement (p);
      if (CODE [p++] != RESERVED_while)
            syntax_error (p, "do w/o while");
      p = parenth_expression (p);
      if (CODE [p++] != ';')
            syntax_error (p, "This is special, but you need a ';'");
      return p;
}

static NormPtr for_statement (NormPtr p)
{
      if (CODE [p++] != '(')
            syntax_error (p, "for '('...");
      p = parse_expression (p);
      PSEUDOCODE ("REPEAT");
      if (CODE [p++] != ';')
            syntax_error (p, "for (expression ';' ...");
      p = parse_expression (p);
      if (CODE [p++] != ';')
            syntax_error (p, "for (expression; expression ';' ...");
      p = parse_expression (p);
      if (CODE [p++] != ')')
            syntax_error (p, "for (;; ')'");
      return statement (p);
}

static NormPtr switch_statement (NormPtr p)
{
      p = parenth_expression (p);
      return statement (p);
}

static NormPtr if_statement (NormPtr p)
{
      {
            PSEUDOCODE ("IF");
            p = statement (parenth_expression (p));
      }
      if (CODE [p] == RESERVED_else) {
            PSEUDOCODE ("ELSE");
            return statement (p + 1);
      }
      return p;
}

static NormPtr parse_declaration (NormPtr p)
{
      declaration D;
      return D.parse (p);
}

static NormPtr compound_statement (NormPtr p)
{
      open_compound ();

#ifdef NCC_ISOC99
      while (CODE [p] != '}')
            p = (is_dcl_start (CODE [p]) && CODE [p + 1] != ':') ?
            parse_declaration (p) : statement (p);
#else
      while (CODE [p] != '}')
            if (is_dcl_start (CODE [p]))
                  p = parse_declaration (p);
            else break;

      while (CODE [p] != '}')
            p = statement (p);
#endif

      close_region ();
      return p + 1;
}

static NormPtr __asm___statement (NormPtr p)
{
      NormPtr ast = p + 1;
      if (CODE [p] != '(') syntax_error (p, "__asm__ '('");
      p = skip_parens (p);
      if (CODE [p++] != ';') syntax_error (p, "asm() ';'");
      ncc->inline_assembly (ast, p - ast - 1);
#ifdef      GNU_VIOLATIONS
      last_result_type.base = VOID;
      last_result_type.spec [0] = -1;
#endif
      ++last_result;
      return p;
}

//***********************************************************************
//
//          Part IV - the rest
//
//***********************************************************************

//***********************************************************************
//
//    Aggregate initializers:
//    The goal is to: a) Catch functions assigned to structure
//    members, and b) Catch function calls in initializers.
//
//***********************************************************************

static inline NormPtr join_expression (dcle &E, NormPtr p)
{
#if 0
      if (ISNUMBER (CODE [p]) || ISSTRING (CODE [p]))
      if (CODE [p + 1] == ',' || CODE [p + 1] == '}') {
            // skip these quickly (may be lots of them)
            E.tofield ();
            return p + 1;
      }
printf ("herez!\n");
#endif
      NormPtr pe, cntk;
      subexpr tee [STDNEE];
      expression_parser EEP (p, tee);
      exprID e;
      typeID t;
      Symbol *se, *tmp;
      // root subexpression manually constructed
      tee [0].action = '=';
      EEP.iee = 1;
      // right part of the assignment is in CODE[]
      // and is assignment expression
      if ((e = EEP.assignment_expression ()) == -1)
            syntax_error (p, "wrong in here");
      pe = EEP.EP;
      EEP.ee [0].e = e;
      // check to see if the type of the assignment is
      // a structure
      CExpr.first = e;
      CExpr.ee = EEP.ee;
      CExpr.ne = EEP.iee;
      t = typeof_expression () - TYPEDEF_BASE;
      // ..and advance E accordingly
      if (spec_of (t)[0] == -1 && base_of (t) > _BTLIMIT)
            E.tostruct (base_of (t));
      else E.tofield ();
      // skip these quickly (calculated constant exprs)
#if 0
      if (EEP.ee [e].action <= FVALUE)
            return pe;
#endif
      // left part of the assignment is made in
      // E.mk_current and is a postfix expression
      tmp = E.mk_current ();
      if (0||!usage_only) prcode (p, EEP.EP - p, tmp);
      cntk = C_Ntok;
      se = CODE;
      CODE = tmp;
      for (C_Ntok = 0; CODE [C_Ntok] != -1; C_Ntok++);
      EEP.EP = 0;
      e = EEP.postfix_expression ();
      EEP.ee [0].voici.e = e;
      CODE = se;
      C_Ntok = cntk;
      // these two joined at tee[0] which is an
      // assignment.  Now send to compiler
      CExpr.first = 0;
      CExpr.ee = EEP.ee;
      CExpr.ne = EEP.iee;
      ncc->cc_expression ();
      return pe;
}


static NormPtr initializer_aggregate (Symbol s, NormPtr p)
{
      dcle E (s);
      for (;;) {
            for (;;)
            if (CODE [p] == '{') {
                  p++;
                  if (!E.open_bracket ()) syntax_error (p, "open");
            } else if (ISSYMBOL (CODE [p]) && CODE [p + 1] == ':') {
                  Symbol d [2] = { CODE [p], -1 };
                  if (!E.designator (d)) syntax_error (p, "designator");
                  if (CODE [p += 2] != '{') break;
            } else if (CODE [p] == '.' || CODE [p] == '[') {
                  Symbol d [20];
                  int di = 0;
                  while (CODE [p] == '.' || CODE [p] == '[')
                        if (CODE [p++] == '.')
                              d [di++] = CODE [p++];
                        else {
                              p = constant_int_expression (p, d [di]);
                              if (CODE [p++] == ELLIPSIS)
                                    p = constant_int_expression (p, d [di]) + 1;
                              if (d [di] < 0) d [di] = -1;
                              d [di++] += INUMBER;
                        }
                  if (CODE [p] == '=') p++;
                  d [di] = -1;
                  if (!E.designator (d)) syntax_error (p, "designator");
                  if (CODE [p] != '{') break;
            } else break;

            if (CODE [p] != ',' && CODE [p] != '}')
                  p = join_expression (E, p);

            for (;;)
            if (CODE [p] == '}') {
                  p++;
                  if (!E.close_bracket ()) return p; //*/*/*/*/*/*/*> OUT
            } else if (CODE [p] == ',') {
                  if (CODE [++p] == '}') continue;
                  if (!E.comma ()) syntax_error (p, "excess");
            } else break;
      }
}

//******** end aggregate initializers

static NormPtr initializer_expr (Symbol s, NormPtr p)
{
      subexpr tee [STDNEE];
      tee [0].action = '=';
      tee [0].voici.e = 1;
      tee [1].action = SYMBOL;
      tee [1].voici.symbol = s;
      expression_parser EEP (p, tee);
      EEP.iee = 2;
      exprID e;

      if ((e = EEP.assignment_expression ()) == -1)
            syntax_error (p, "erroneous initialization");
      EEP.ee [0].e = e;

      CExpr.first = 0;
      CExpr.ee = EEP.ee;
      CExpr.ne = EEP.iee;
      if (!usage_only) prcode (p, EEP.EP - p, s);
      ncc->cc_expression ();
      return EEP.EP;
}

static NormPtr parse_structure (NormPtr p)
{
      declaration_instruct D;
      while (CODE [p] != '}' && p < C_Ntok)
            p = D.parse (p);
      close_region ();
      return p + 1;
}

static NormPtr parse_function (Symbol s, NormPtr a, NormPtr p, NormPtr b)
{
      NormPtr e = skip_brackets (p);
      if (!function_definition (s, a, p, e, b+1))
            //syntax_error (p, "Function definition already defined", expand (s));
            ;
      return e;
}

void do_functions ()
{
      int i;
      NormPtr args, body;

      infuncs = true;
      for (i = 0; function_no (i, &args, &body); i++) {
            PSEUDOCODE("PCODE.0");
            arglist A;
            A.parse_declare (args + 1);
            compound_statement (body + 1);
            close_region ();
      }
}

//
// Well, that's it.
//
void parse_translation_unit ()
{
      NormPtr p = 0;
      declaration D;

      while (p < C_Ntok)
            if (CODE [p] == ';') p++;
            else if (CODE [p] == RESERVED___asm__) p = skip_parens (p + 1);
            else p = D.parse (p);

      do_functions ();
}

void parse_C ()
{
      parse_translation_unit ();
}

Generated by  Doxygen 1.6.0   Back to index