/*     
      BYTE CODE INTERPRETER . Magma 1.0 . 1996 . Sylvain HUET

         readmag2.cpp : module magma du loader de packages, 2e partie
*/
// Modification history
//
//$ FA(27/03/2001): Include code generator interface
//$ FA(27/03/2001): Substitute PUSH by call to code generator cgen() function
//$ FA(28/03/2001): Delete all occurrences of 'MGnbyt'
//$ FA(06/04/2001): Modify PKpushfun to use OPGETGLOBAL
//$ FA(17/04/2001): Adapt compiler to use specialised getters and setters (OPGETLOCALi, etc)
//$ FA(19/04/2001): Promote file to C++. Renamed from readmag2.c to readmag2.cpp. 
//                  Opcodes are defined in interp.h
//$ FA(19/04/2001): Use new opcode mnemonics as well as the new specialised 'pushint' bytecodes
//$ FA(20/04/2001): Use specialised 'newtuple' bytecodes
//$ FA(03/05/2001): Use new lexer interface (lexer.h)
//$ FA(03/05/2001): Accept floating-point literals
//$ FA(17/07/2001): Use lexer utility function a2i() as a replacement of Mgetnum()
//$ FA(25/07/2001): Replace atof() by a2f()
//


#include <string.h>
#include "lexer.h"
extern "C" {
# include "mmemory.h"
# include "listlab.h"
# include "loadpak.h"
}
//$ FA(27/03/2001): Include code generator interface
#include "coder.h"
//
#include "opcode.h"


extern int MGnglob;
int PKreadlab(mmachine m,manlyz z,int ind);
int PKreada(mmachine m,manlyz z,int ind);
int PKreadp(mmachine m,manlyz z,int ind);

/* lecture d'une Expression [L'] (le premier crochet a ete lu) */
int PKreadtab(mmachine m,manlyz z,int ind)
{
  int k,n,q;
  int res;

  n=0;
  q=1;
  while(q)
    {
      if (Mreadtok(z))
        {
          sprintf(z->mess,"missing element");
          return MERRTYP;
        }
      if (z->tok[0]==']') q=0;
      else
        {
          if (k=PKreada(m,z,ind)) return k;
          n++;
        }
    }
//$ FA(27/03/2001) - Substitute PUSH by call to code generator cgen() function
  if (res = writeNewtuple(n))
    return res;
//
  
  return 0;
}

/* empilement d'une chaine de caracteres dans le bytecode
   la chaine commence et finit par des guillemets */
int PKpushstring(mmachine m,manlyz z,char *name)
{
  int c,n,ind,i;

  if ((*name)!='\"') return MERRTYP;
  name++;
//$ FA(27/03/2001) - Substitute PUSH by call to code generator cgen() function
  CODER_WRITEINT32(0)
//$ FA(27/03/2001) - Get offset of last bytecode generated
  ind = CODER_LASTOFFSET;
//
  n=0;
  while(1)
    {
      c=*(name++);
      if (c=='\\')
        {
          c=*(name++);
          if (c=='n') c=10;
          else if (c=='z') c=0;
          else if ((c>='0')&&(c<='9'))
            {
              i=c-'0';
              c=*name;
              if ((c>='0')&&(c<='9'))
                {
                  name++;
                  i=(i*10)+c-'0';
                  c=*name;
                  if ((c>='0')&&(c<='9'))
                    {
                      name++;
                      i=(i*10)+c-'0';
                    }
                }
              c=i;
            }
          else while(c<32) c=*(name++);
        }
      else if (c=='\"')
        {
//$ FA(27/03/2001) - Set calculated string length
          CODER_BACKPATCH(ind, (uint32)n)
//
          return n+1;
        }
      n++;
//$ FA(27/03/2001) - Substitute PUSH by call to code generator cgen() function
	  CODER_WRITEBYTE(c)
//
    }
}

/* empilement d'une fonction */
int PKpushfun(mmachine m,manlyz z,int ind)
{
  int i,k;

  if (Mreadtok(z)) return MERRTYP;
  i=Msearchlabel(m,m->top[ind+PKGGLB],z->tok);
  if (i==-1)
    {
      if (k=Maddlabel(m,ind+PKGGLB,z->tok,MGnglob)) return k;
      i=MGnglob++;
    }
//$ FA(06/04/2001): Modify PKpushfun to use OPGETGLOBAL
  int res;
  if (res = writeAccessor(kAccessorGlobal, true, i))
    return res;
//
  return 0;
}

/* lecture d'une Expression T */
int PKreadt(mmachine m,manlyz z,int ind)
{
  int i,k;
  int res;

//$ FA(04/05/2001) - Accept floating-point literals
  if (z->lex.current().kind() == Token::kInt) {
//$ FA(27/03/2001) - Substitute PUSH by call to code generator cgen() function
    int n;
    a2i(z->lex.current().lexeme(), &n); //$ FA(17/07/2001)
    if (res = writePushint(n))
      return res;
    return MERROK;
  }
  if (z->lex.current().kind() == Token::kFloat) {
    float f;
    a2f(z->lex.current().lexeme(), &f); //$ FA(25/07/2001)
    if (res = writePushfloat(f))
      return res;
    return MERROK;
  }
//
  if (z->tok[0]=='\'')
    {
      //if (Mreadtok(z)) return MERRTYP;
      //i=(z->tok[0])&255;
      i = z->tok[1]&0xff;
//$ FA(27/03/2001) - Substitute PUSH by call to code generator cgen() function
      CODER_WRITEOPCODE(kPushbyte)
      CODER_WRITEBYTE(i)
//
      return 0;
    }
  if (!strcmp(z->tok,"nil"))
    {
//$ FA(27/03/2001) - Substitute PUSH by call to code generator cgen() function
	  CODER_WRITEOPCODE(kPushnil)
//
      return 0;
    }
  if (z->tok[0]=='\"')
    {
//$ FA(27/03/2001) - Substitute PUSH by call to code generator cgen() function
	  CODER_WRITEOPCODE(kPushstr)
//
      k=PKpushstring(m,z,z->tok);
      if (k<0) return k;
      return 0;
    }
  if (z->tok[0]=='(')
    {
      if (k=PKreadp(m,z,ind)) return k;
      if ((Mreadtok(z))||(z->tok[0]!=')'))
        {
          sprintf(z->mess,") expected");
          return MERRTYP;
        }
      return 0;
    }
  if (z->tok[0]=='{')
    {
      if (k=PKreadp(m,z,ind)) return k;
      if ((Mreadtok(z))||(z->tok[0]!='}'))
        {
          sprintf(z->mess,"} expected");
          return MERRTYP;
        }
      return 0;
    }
  if (z->tok[0]=='[') return PKreadtab(m,z,ind);
  if (z->tok[0]=='@') return PKpushfun(m,z,ind);

  if (z->lex.current().is(Token::kIdent)) return PKreadlab(m,z,ind);
  sprintf(z->mess,"term expected");
  return MERRTYP;
}

/* lecture d'une Expression A6 */
int PKreada6(mmachine m,manlyz z,int ind)
{
  int k;

  if (!strcmp(z->tok,"~"))
    {
      if (Mreadtok(z))
        {
          sprintf(z->mess,"missing element");
          return MERRTYP;
        }
      if (k=PKreada6(m,z,ind)) return k;
//$ FA(27/03/2001) - Substitute PUSH by call to code generator cgen() function
      CODER_WRITEOPCODE(kIntnot)
//
      return 0;
    }
  if (!strcmp(z->tok,"-"))
    {
      if (Mreadtok(z))
        {
          sprintf(z->mess,"missing element");
          return MERRTYP;
        }
      if (k=PKreada6(m,z,ind)) return k;
//$ FA(27/03/2001) - Substitute PUSH by call to code generator cgen() function
      CODER_WRITEOPCODE(kIntneg)
//
      return 0;
    }
  if (!strcmp(z->tok,"-."))
    {
      if (Mreadtok(z))
        {
          sprintf(z->mess,"missing element");
          return MERRTYP;
        }
      if (k=PKreada6(m,z,ind)) return k;
//$ FA(27/03/2001) - Substitute PUSH by call to code generator cgen() function
      CODER_WRITEOPCODE(kFloatneg)
//
      return 0;
    }
  return PKreadt(m,z,ind);
}

/* lecture d'une Expression A5 */
int PKreada5(mmachine m,manlyz z,int ind)
{
  int i,k;

  if (k=PKreada6(m,z,ind)) return k;
  while(1)
    {
      if (Mreadtok(z)) return 0;
      if (!strcmp(z->tok,"&")) i=kIntand;
      else if (!strcmp(z->tok,"|")) i=kIntor;
      else if (!strcmp(z->tok,"^")) i=kIntxor;
      else if (!strcmp(z->tok,">>")) i=kIntshr;
      else if (!strcmp(z->tok,"<<")) i=kIntshl;
      else
        {
          z->giveback=1;
          return 0;
        }
      if (Mreadtok(z))
        {
          sprintf(z->mess,"expression expected");
          return MERRTYP;
        }
      if (k=PKreada6(m,z,ind)) return k;
//$ FA(27/03/2001) - Substitute PUSH by call to code generator cgen() function
      CODER_WRITEOPCODE(i)
//
    }
}

/* lecture d'une Expression A4 */
int PKreada4(mmachine m,manlyz z,int ind)
{
  int i,k;

  if (k=PKreada5(m,z,ind)) return k;
  while(1)
    {
      if (Mreadtok(z)) return 0;
      if (!strcmp(z->tok,"*")) i=kIntmul;
      else if (!strcmp(z->tok,"/")) i=kIntdiv;
      else if (!strcmp(z->tok,"*.")) i=kFloatmul;
      else if (!strcmp(z->tok,"/.")) i=kFloatdiv;
      else
        {
          z->giveback=1;
          return 0;
        }
      if (Mreadtok(z))
        {
          sprintf(z->mess,"expression expected");
          return MERRTYP;
        }
      if (k=PKreada5(m,z,ind)) return k;
//$ FA(27/03/2001) - Substitute PUSH by call to code generator cgen() function
      CODER_WRITEOPCODE(i)
//
    }
}

/* lecture d'une Expression A3 */
int PKreada3(mmachine m,manlyz z,int ind)
{
  int i,k;

  if (k=PKreada4(m,z,ind)) return k;
  while(1)
    {
      if (Mreadtok(z)) return 0;
      if (!strcmp(z->tok,"+")) i=kIntadd;
      else if (!strcmp(z->tok,"-")) i=kIntsub;
      else if (!strcmp(z->tok,"+.")) i=kFloatadd;
      else if (!strcmp(z->tok,"-.")) i=kFloatsub;
      else
        {
          z->giveback=1;
          return 0;
        }
      if (Mreadtok(z))
        {
          sprintf(z->mess,"expression expected");
          return MERRTYP;
        }
      if (k=PKreada4(m,z,ind)) return k;
//$ FA(27/03/2001) - Substitute PUSH by call to code generator cgen() function
      CODER_WRITEOPCODE(i)
//
    }
}

/* lecture d'une Expression A2 */
int PKreada2(mmachine m,manlyz z,int ind)
{
  int i,k;

  if (k=PKreada3(m,z,ind)) return k;
  while(1)
    {
      if (Mreadtok(z)) return 0;
      if (!strcmp(z->tok,"==")) i=kInteq;
      else if (!strcmp(z->tok,"!=")) i=kIntne;
      else if (!strcmp(z->tok,"<")) i=kIntlt;
      else if (!strcmp(z->tok,">")) i=kIntgt;
      else if (!strcmp(z->tok,"<=")) i=kIntle;
      else if (!strcmp(z->tok,">=")) i=kIntge;
      else if (!strcmp(z->tok,"=.")) i=kFloateq;
      else if (!strcmp(z->tok,"!=.")) i=kFloatne;
      else if (!strcmp(z->tok,"<.")) i=kFloatlt;
      else if (!strcmp(z->tok,">.")) i=kFloatgt;
      else if (!strcmp(z->tok,"<=.")) i=kFloatle;
      else if (!strcmp(z->tok,">=.")) i=kFloatge;
      else
        {
          z->giveback=1;
          return 0;
        }
      if (Mreadtok(z))
        {
          sprintf(z->mess,"expression expected");
          return MERRTYP;
        }
      if (k=PKreada3(m,z,ind)) return k;
//$ FA(27/03/2001) - Substitute PUSH by call to code generator cgen() function
      CODER_WRITEOPCODE(i)
//
    }
}

/* lecture d'une Expression A1 */
int PKreada1(mmachine m,manlyz z,int ind)
{
  int k;

  if (!strcmp(z->tok,"!"))
    {
      if (Mreadtok(z))
        {
          sprintf(z->mess,"missing element");
          return MERRTYP;
        }
      if (k=PKreada1(m,z,ind)) return k;
//$ FA(27/03/2001) - Substitute PUSH by call to code generator cgen() function
      CODER_WRITEOPCODE(kBoolnot)
//
      return 0;
    }
  return PKreada2(m,z,ind);
}

/* lecture d'une Expression A' */
int PKreadap(mmachine m,manlyz z,int ind)
{
  int i,k,p1;

  if (k=PKreada1(m,z,ind)) return k;
  while(1)
    {
      if (Mreadtok(z)) return 0;
      if (!strcmp(z->tok,"&&")) i=kBooland;
      else if (!strcmp(z->tok,"||")) i=kBoolor;
      else
        {
          z->giveback=1;
          return 0;
        }

//$ FA(27/03/2001) - Substitute PUSH by call to code generator cgen() function
	  CODER_WRITEOPCODE(kDup)
//
      if (i==kBoolor)
        {
//$ FA(27/03/2001) - Substitute PUSH by call to code generator cgen() function
		  CODER_WRITEOPCODE(kBoolnot)
//
        }
//$ FA(27/03/2001) - Substitute PUSH by call to code generator cgen() function
	  CODER_WRITEOPCODE(kIffalse)
//$ FA(27/03/2001) - Get offset of last bytecode generated
	  CODER_WRITEHOLE(&p1)
//
      if (Mreadtok(z))
        {
          sprintf(z->mess,"expression expected");
          return MERRTYP;
        }
      if (k=PKreada1(m,z,ind)) return k;
//$ FA(27/03/2001) - Substitute PUSH by call to code generator cgen() function
	  CODER_WRITEOPCODE(i)
//
//$ FA(27/03/2001) - Backpatch p1 with offset of next bytecode
	  CODER_BACKPATCH(p1, CODER_OFFSET)
//
    }
}

/* lecture d'une Expression A */
int PKreada(mmachine m,manlyz z,int ind)
{
  int k;
  static int cnt = 0;

  if (k=PKreadap(m,z,ind)) return k;
  if (Mreadtok(z)) return 0;
  if (strcmp(z->tok,"::"))
    {
      z->giveback=1;
      return 0;
    }
  if (Mreadtok(z))
    {
      sprintf(z->mess,"expression expected");
      return MERRTYP;
    }
  if (k=PKreada(m,z,ind)) return k;
//$ FA(27/03/2001) - Substitute PUSH by call to code generator cgen() function
  CODER_WRITEOPCODE(kNewtuple2)
//
  return 0;
}

/* lecture d'une Expression P  */
int PKreadp(mmachine m,manlyz z,int ind)
{
  int k;

  if (Mreadtok(z)) return MERRTYP;
  while(1)
    {
      if (k=PKreada(m,z,ind)) return k;
      if (Mreadtok(z)) return 0;
      if (strcmp(z->tok,";"))
        {
          z->giveback=1;
          return 0;
        }
      if (Mreadtok(z)) return MERRTYP;
      if ( (!strcmp(z->tok,")"))||(!strcmp(z->tok,"}")) )
        {
          z->giveback=1;
          return 0;
        }
//$ FA(27/03/2001) - Substitute PUSH by call to code generator cgen() function
	  CODER_WRITEOPCODE(kDrop)
//
    }
}
