//(c) 2007 Ralph Sommerer. All rights reserved.
//V2.0beta July 6, 2007
String.prototype.trimBeg=function(){
  return this.replace(/^\s+/,"")
}
String.prototype.startsWith=function(p){
  return(this.substr(0,p.length)==p)
}
Array.prototype.last=function(){
  return this[this.length-1]
}
//Scanner
function Scan(s){
  this.str=s.trimBeg()
}
function find(i,o){
  for(var n in o){
    if(o[n]==i)return n
  }
  return "??("+i+")"
}
Scan._kw={
  "ARRAY":1,"BEGIN":1,"BY":1,"CASE":1,"CONST":1,
  "DIV":1,"DO":1,"ELSE":1,"ELSIF":1,"END":1,"EXIT":1,"FOR":1,
  "IF":1,"IMPORT":1,"IN":1,"IS":1,"LOOP":1,"MOD":1,"MODULE":1,
  "OR":1,"OF":1,"POINTER":1,"PROCEDURE":1,"RECORD":1,"REPEAT":1,"RETURN":1,
  "THEN":1,"TO":1,"TYPE":1,"UNTIL":1,"VAR":1,"WHILE":1,"WITH":1
};
Scan._jskw={
  "break":1,"case":1,"catch":1,"continue":1,"default":1,"delete":1,
  "do":1,"else":1,"false":1,"finally":1,"for":1,"function":1,  "if":1,"in":1,
  "instanceof":1,  "new":1,"null":1,"return":1,"switch":1,"this":1,
  "throw":1,"true":1,"try":1,"typeof":1,"var":1,"void":1,"while":1,"with":1,
  /*!!!*/"toString":-1
};
//Scan._id={"NIL":1,"TRUE":1,"FALSE":1};
Scan._xid=/([a-zA-Z_]\w*)/;
Scan._xnum=/(\d+)/;
Scan._xnumx=/(\d[0-9A-F]*(X|H))/;
Scan._xnumr=/(\d+\.\d*((E|D)(\+|\-)?\d+)?)/;
Scan.init=function(i){
  var k=Scan._kw;
  for(var n in k)k[n]=i++
}
Scan.KW=50;
Scan.init(Scan.KW);
Scan._kw["toString"]=-1;
/*!!!*/
Scan.Err=-2;
Scan.EOS=-1;
Scan.Id=1;
Scan.Num=2;
Scan.Str=3;
Scan.ASSIGN=4;
Scan.LEQ=5;
Scan.GEQ=6;
Scan.LT=7;
Scan.GT=8;
Scan.EQ=9;
Scan.NEQ=10;
Scan.PLUS=11;
Scan.MINUS=12;
Scan.TIMES=13;
Scan.DIV=14;
Scan.AND=15;
Scan.PERIOD=16;
Scan.COLON=17;
Scan.OPAR=18;
Scan.CPAR=19;
Scan.OBRAK=20;
Scan.CBRAK=21;
Scan.OBRACE=22;
Scan.CBRACE=23;
Scan.SEMICOL=24;
Scan.COMMA=25;
Scan.TILDE=26;
Scan.BAR=27;
Scan.ELLIPSIS=28;
Scan.HAT=29;
//Scan._symE=":<>";
Scan._eqC=[Scan.ASSIGN,Scan.LEQ,Scan.GEQ];
Scan._neqC=[Scan.COLON,Scan.LT,Scan.GT];
Scan._sym="()[]{};,+-*/&=#^~|";
Scan._symC=[Scan.OPAR,Scan.CPAR,Scan.OBRAK,Scan.CBRAK,Scan.OBRACE,Scan.CBRACE,
Scan.SEMICOL,Scan.COMMA,Scan.PLUS,Scan.MINUS,Scan.TIMES,Scan.DIV,Scan.AND,
Scan.EQ,Scan.NEQ,Scan.HAT,Scan.TILDE,Scan.BAR];
Scan._sym0=["???","id","num","str","assign",
"leq","geq","lt","gt","eq","neq",
"plus","minus","times","div","and","period","colon",
"opar","cpar","obrak","cbrak","obrace","cbrace","semicol","comma",
"tilde","bar","ellips","hat"];
Scan._Sym=function(i){
  return (i<Scan.KW?Scan._sym0[i]+"("+i+")":find(i,Scan._kw))
}
Scan.prototype.sym=function()
{
  var s=this.str;
  if(s.length==0)return Scan.EOS;
  if(s.search(Scan._xid)==0){
    var id=this.id=RegExp.$1;
    this.eat(id.length);
    var kw;
    if((kw=Scan._kw[id])>=Scan.KW)return kw;
    if(Scan._jskw[id]>0)this.id='_'+id;
    return Scan.Id;
  }else if(s.search(Scan._xnumr)==0){
    var num=RegExp.$1;
    var len=num.length;
    if(num.charAt(len-1)=='.'&&s.charAt(len)=='.'){
      this.num=parseInt(num.substr(0,len-1));
      this.eat(len-1);
      this.numtyp='intT'
    }else{
      this.eat(num.length);
      this.num=parseFloat(num)
    }
    this.numtyp='floatT'
    return Scan.Num;
  }else if(s.search(Scan._xnumx)==0||s.search(Scan._xnum)==0){
    var num=RegExp.$1;
    this.eat(num.length);
    var h=num.charAt(num.length-1);
    this.num=parseInt(num,(h=='X'||h=='H'?16:10));
    this.numtyp=(h=='X'||h=='H'?'hexT':'intT');
    //I,H,C
    return Scan.Num;
  }else{
    var x=s.charAt(0);
    if((i=":<>".indexOf(x))>=0){
      if(s.charAt(1)=='='){
        this.eat(2);
        return Scan._eqC[i]
      }
      this.eat(1);
      return Scan._neqC[i];
    }else if((i=Scan._sym.indexOf(x))>=0){
      if(i==0&&s.startsWith("(*")){
        this.eat(s.indexOf("*)")+2);
        return this.sym()
      }
      this.eat(1);
      return Scan._symC[i];
    }else if(x=='\''||x=='\"'){
      this.id=s.substring(1,s.indexOf(x,1));
      this.eat(this.id.length+2);
      return Scan.Str;
    }else if(x=='.'){
      if(s.charAt(1)=='.'){
        this.eat(2);
        return Scan.ELLIPSIS
      }
      this.eat(1);
      return Scan.PERIOD;
    }
    //else
    this.eat(1);
    return Scan.Err;
  }
}
Scan.prototype.eat=function(n){
  this.str=this.str.substr(n).trimBeg()
}
//Parser
function Parse(cd)
{
  this.cd=cd;
  this.mods={};
}
Parse.prototype.compile=function(scn)
{
  this.scn=scn;
  this.cd.reset();
  this.lev=0;
  this.next();
  this.module()
}
Parse.prototype.next=function(){
  this.sym=this.scn.sym()/*;deb(" "+Scan._Sym(this.sym))*/
}
Parse.prototype.error=function(m){
  if(!this.err){
    this.err=m
  }else{
    this.err+="<br>"+m
  }
}
Parse.prototype.eat=function(sy){
  if(this.sym==sy)this.next();
  else this.error(Scan._Sym(sy)+" expected")
}
Parse.prototype.code=function(){
  return this.cd.toString()
}
Parse.prototype.module=function()
{
  this.top=Parse.scope0;
  //module
  this.eat(Scan._kw.MODULE);
  this.ident();
  var md=this.mod=this.id;
  this.cd.put("function "+md+"(){");
  var m;
  this.push(m=new Obj('M',md));
  this.eat(Scan.SEMICOL);
  if(this.sym==Scan._kw.IMPORT){
    this.next();
    this.impList()
  }
  this._body(md,Scan.PERIOD);
  this.cd.put("}"+md+"();");
  this.addMod(m)
}
Parse.prototype.impList=function()
{
  this.imp();
  while(this.sym==Scan.COMMA){
    this.next();
    this.imp()
  }
  this.eat(Scan.SEMICOL)
}
Parse.prototype.imp=function()
{
  if(this.sym==Scan.Id){
    var m;
    this.ident();
    this.add(m=new Obj('M',this.id));
    if(this.sym==Scan.ASSIGN){
      this.next();
      this.ident();
      m.id0=this.id
    }
    var id=m.id0?m.id0:m.id;
    if(id=="HOST")m.dsc=[];
    else m.dsc=this.mods[id]?this.mods[id].dsc:null;
    //m.dsc=(id!="HOST"?this.mods[id].dsc:[]);//error
    if(!m.dsc)this.error("no such module ("+id+")")
  }else{
    this.error("id expected")
  }
}
Parse.prototype._body=function(n,sy)
{
  this.declSeq();
  //this.dump();
  if(this.sym==Scan._kw.BEGIN){
    this.next();
    this.stmtSeq()
  }
  this.eat(Scan._kw.END);
  if(this.sym==Scan.Id&&this.scn.id==n){
    this.next();
    this.eat(sy)
  }
  else this.error("id "+n+" expected")
}
Parse.prototype.stmtSeq=function()
{
  this.stmt();
  while(this.sym==Scan.SEMICOL){
    this.next();
    this.cd.put(";");
    this.stmt()
  }
}
Parse.prototype.ident=function(md)
{
  var n=null;
  if(this.sym==Scan.Id){
    this.id=this.scn.id;
    if(md)this.add(n=new Obj(md,this.id));
    this.next();
  }else{
    this.error("id expected ("+Scan._Sym(this.sym)+")");
    if(md)n=new Obj(md,"??")
  }
  return n
}
Parse.prototype.qualid=function()
{
  var m=null;
  this.ident();
  //debB('#fc0',this.id);
  if(this.sym==Scan.PERIOD&&(m=this.find(this.id))&&m.md=='M'){
    //m=this.find(this.id);
    this.next();
    this.ident()
    return m
  }
  //debB('#f42',"no");
  return null
}
Parse.prototype.identDef=function(md)
{
  this.mk=null;
  this.ident(md);
  if(this.sym==Scan.TIMES){
    this.next();
    this.mk=(this.lev==1?this.mod:null);
    if(md)this.top.dsc.last().mk=this.mk;
    //export
    if(!this.mk)this.error("export error")
  }
}
Parse.prototype.type=function()
{
  var t=null,m;
  var sy=this.sym;
  if(sy==Scan.Id){
    m=this.qualid();
    t=this.findT(this.id,m);
    //debB('#0ff',dumpT(t));
    //debB('#ff8',this.id);
    if(!t&&m&&m.id=="HOST")m.dsc.push(t=new Obj('T',this.id,"HOST"));
    if(!t){
      this.error("no such type ("+this.id+")");
      t=Obj.noT
    }
  }else{
    this.next();
    if(sy==Scan._kw.ARRAY){
      t=new Obj('A');
      t.dim=[];
      this.exprList(t.dim);
      this.eat(Scan._kw.OF);
      t.typ=this.type()
    }else if(sy==Scan._kw.RECORD){
      this.push(t=new Obj('R'));
      if(this.sym==Scan.OPAR){
        this.next();
        m=this.qualid();
        t.typ=this.findT(this.id,m);
        if(!t.typ)this.error("no such type ("+(m?m.id+'.':"")+this.id+")");
        this.eat(Scan.CPAR)
      }
      this.fldList();
      while(this.sym==Scan.SEMICOL){
        this.next();
        this.fldList()
      }
      this.pop();
      this.eat(Scan._kw.END)
    }else if(sy==Scan._kw.POINTER){
      t=new Obj('^');
      this.eat(Scan._kw.TO);
      if(this.sym==Scan.Id){
        m=this.qualid();
        t.typ=this.findT(this.id,m);
        if(!t.typ){
          this.add(t.typ=new Obj('?',this.id))
        }
      }else{
        t.typ=this.type()
      }
    }else if(sy==Scan._kw.PROCEDURE){
      t=this.procTyp()
    }
  }
  return t
}
Parse.prototype.procTyp=function()
{
  //this.eat(Scan._kw.PROCEDURE);
  var p=new Obj('X');
  this.push(p);
  if(this.sym==Scan.OPAR)this.fmPars();
  this.pop();
  return p
}
Parse.prototype.fldList=function()
{
  if(this.sym==Scan.Id){
    var i=this.mark();
    this.idList();
    this.eat(Scan.COLON);
    this.setT(i,this.type())
  }
}
Parse.prototype.declSeq=function()
{
  this.lev++;
  while(true){
    var sy=this.sym;
    if(sy==Scan._kw.CONST){
      this.next();
      this.constDecl();
    }else if(sy==Scan._kw.TYPE){
      this.next();
      this.typDecl();
    }else if(sy==Scan._kw.VAR){
      this.next();
      this.varDecl();
    }else{
      break;
    }
  }
  while(this.sym==Scan._kw.PROCEDURE){
    this.next();
    this.procDecl()
  }
  this.lev--
}
Parse.prototype.constDecl=function()
{
  var c;
  while(this.sym==Scan.Id){
    this.identDef();
    //'C'
    this.add(c=new Obj('C',this.id,this.mk));
    this.eat(Scan.EQ);
    c.v=this.expr();
    this.cd.putI(c.id_("var")+"=",c.v,";");
    this.eat(Scan.SEMICOL)
  }
}
Parse.prototype.typDecl=function()
{
  var t;
  while(this.sym==Scan.Id){
    this.identDef();
    t=this.find(this.id);
    if(!t||t.md!='?')this.add(t=new Obj('T',this.id,this.mk));
    else{
      t.md='T';
      t.mk=this.mk
    }
    this.eat(Scan.EQ);
    t.typ=this.type();
    //debB('#f8f',":"+dumpT(t)+":"+t.md);
    var f=t.frm();
    if(f&&f.md=='^'&&f.typ.md=='?'){
      f=f.typ;
      if(!f.alias)f.alias=[];
      f.alias.push(t)
    }
    //debB('#ff0',dumpT(t));debLn();
    this.cd.putT(t);
    this.eat(Scan.SEMICOL)
  }
}
Parse.prototype.varDecl=function()
{
  while(this.sym==Scan.Id){
    var i=this.mark();
    this.idList();
    this.eat(Scan.COLON);
    this.setT(i,this.type());
    this.cd.vars(this.top.dsc,i);
    this.eat(Scan.SEMICOL)
  }
}
Parse.prototype.list=function(d)
{
  var s="";
  for(var i=0;i<d.length;++i)s+=","+d[i].id;
  return s.substr(1)
}
Parse.prototype.procDecl=function()
{
  var r=null,c=this.cd;
  if(this.sym==Scan.OPAR){
    /*O2:PROC(VAR r:R)P*()-->M.R.prototype.P=fun(){var r=this;*/
    this.next();
    if(this.sym==Scan._kw.VAR)this.next();
    this.ident();
    r=new Obj('V',this.id);
    this.eat(Scan.COLON);
    this.ident();
    r.typ=this.findT(this.id);
    this.eat(Scan.CPAR)
  }
  this.identDef();
  var pc;
  this.push(this.add(pc=new Obj('P',this.id,this.mk)));
  c.put(c.fn(pc,r)+"(");
  if(this.sym==Scan.OPAR){
    this.fmPars();
  }
  this.eat(Scan.SEMICOL);
  c.put(this.list(pc.dsc));
  c.put("){");
  this.push(new Obj('l'));
  //locals
  if(r){
    c.put("var "+r.id+"=this;");
    this.add(r)
  }
  this.declSeq();
  this._body(pc.id,Scan.SEMICOL);
  c.put("};");
  this.pop();
  this.pop()
}
Parse.prototype.fmPars=function()
{
  this.eat(Scan.OPAR);
  if(this.sym!=Scan.CPAR){
    this.fpSec();
    while(this.sym==Scan.SEMICOL){
      this.next();
      this.fpSec()
    }
  }
  this.eat(Scan.CPAR);
  if(this.sym==Scan.COLON){
    this.next();
    var m=this.qualid();
    this.top.typ=this.findT(this.id,m)
  }else{
    //  this.top.typ=Obj.noT
  }
}
Parse.prototype.fpSec=function()
{
  var v='V';
  if(this.sym==Scan._kw.VAR){
    this.next();
    v='W'//varpar
  }
  var i=this.mark();
  this.ident(v);
  while(this.sym==Scan.COMMA){
    this.next();
    this.ident(v);
  }
  this.eat(Scan.COLON);
  this.setT(i,this.fmType())
}
Parse.prototype.fmType=function()
{
  var t0=null,ta,t;
  while(this.sym==Scan._kw.ARRAY){
    if(!t0){
      t0=ta=new Obj('A')
    }else{
      t0.typ=new Obj('A');
      t0=t0.typ
    }
    this.next();
    this.eat(Scan._kw.OF)
  }
  if(this.sym==Scan._kw.PROCEDURE){
    this.next();
    t=this.procTyp()
  }else{
    var m=this.qualid();
    t=this.findT(this.id,m)
  }
  if(t0){
    t0.typ=t;
    t=ta
  }
  return t
}
Parse.prototype.idList=function()
{
  this.identDef('V');
  //ident();
  while(this.sym==Scan.COMMA){
    this.next();
    this.identDef('V')
  }
}
Parse.prototype.stmt=function()
{
  var e;
  var c=this.cd;
  if(this.sym==Scan._kw.IF){
    this.next();
    e=this.expr();
    this.eat(Scan._kw.THEN);
    c.putI("if(",e,"){");
    this.stmtSeq();
    while(this.sym==Scan._kw.ELSIF){
      this.next();
      e=this.expr();
      this.eat(Scan._kw.THEN);
      c.putI("}else if(",e,"){");
      this.stmtSeq()
    }
    if(this.sym==Scan._kw.ELSE){
      this.next();
      c.put("}else{");
      this.stmtSeq()
    }
    this.eat(Scan._kw.END);
    c.put("}")
  }else if(this.sym==Scan._kw.CASE){
    this.next();
    e=this.expr();
    this.eat(Scan._kw.OF);
    c.putI("switch(",e,"){");
    this.case_()
    while(this.sym==Scan.BAR){
      this.next();
      this.case_()
    }
    if(this.sym==Scan._kw.ELSE){
      this.next();
      c.put("default:");
      this.stmtSeq()
    }
    this.eat(Scan._kw.END);
    c.put("}")
  }else if(this.sym==Scan._kw.WHILE){
    this.next();
    e=this.expr();
    this.eat(Scan._kw.DO);
    c.putI("while(",e,"){");
    this.stmtSeq();
    this.eat(Scan._kw.END);
    c.put("}")
  }else if(this.sym==Scan._kw.REPEAT){
    c.put("do{");
    this.next();
    this.stmtSeq();
    this.eat(Scan._kw.UNTIL);
    e=this.expr();
    c.putI("}while(!(",e,"));")
  }else if(this.sym==Scan._kw.FOR){
    /*O2*/
    var e0,e1,e2=null;
    this.next();
    this.ident();
    var n=this.find(this.id);
    if(!n)this.error(this.id+" not found");
    this.eat(Scan.ASSIGN);
    var e0=this.expr();
    this.eat(Scan._kw.TO);
    var e1=this.expr();
    if(this.sym==Scan._kw.BY){
      this.next()
      e2=this.expr();
      //const
      if(e2.md!='C')this.error("for inc not const ("+e2.md+")");
    }
    this.eat(Scan._kw.DO);
    c.putFor(n,e0,e1,e2);
    this.stmtSeq();
    this.eat(Scan._kw.END);
    c.put("}")
  }else if(this.sym==Scan._kw.LOOP){
    c.put("while(true){");
    this.next();
    this.stmtSeq();
    this.eat(Scan._kw.END);
    c.put("}")
  }else if(this.sym==Scan._kw.WITH){
    this.next();
    this.guard();
    this.eat(Scan._kw.DO);
    this.stmtSeq();
    while(this.sym==Scan.BAR)/*O2*/
    {
      this.next();
      this.eat(Scan._kw.DO);
      this.stmtSeq()
    }
    if(this.sym==Scan._kw.ELSE){
      this.next();
      this.stmtSeq()
    }
    /*O2*/
    this.eat(Scan._kw.END)
  }else if(this.sym==Scan._kw.EXIT){
    this.next();
    c.put("break")
  }else if(this.sym==Scan._kw.RETURN){
    this.next();
    c.put("return");
    if(this.sym!=Scan.SEMICOL&&this.sym!=Scan.BAR&&this.sym<Scan.KW){
      e=this.expr();
      c.putI("(",e,")")
    }
  }else if(this.sym==Scan.Id){
    e=this.desig();
    if(this.sym==Scan.ASSIGN){
      this.next();
      //e.op2(Scan.ASSIGN,e,this.expr());
      e.assign(e,this.expr());
      c.put(e)
    }else{
      this.call(e);
      c.put(e)
    }
  }
}
Parse.prototype.guard=function()
{
  this.qualid();
  this.eat(Scan.COLON);
  this.qualid()
}
Parse.prototype.call=function(e)
{
  var el=[];
  if(this.sym==Scan.OPAR){
    this.next();
    if(this.sym!=Scan.CPAR)this.exprList(el);
    this.eat(Scan.CPAR)
  }
  e.call(this.findQ(e),e,el,this)
}
Parse.prototype.deref=function(o,n)
{
  if(!o){
    /*debB('#f44',"null");*/return null;
  }
  //debB('#fc8'," T:"+o.id_()+":"+dumpT(o));
  var f=o.frm(),d;
  if(!f&&o.mk=="HOST")return new Obj('H',n,"HOST");
  if(f.md=='^')return this.deref(f.typ,n);
  //if(f.typ)debB('#c8f'," T:"+f.typ.id_()+":"+dumpT(f.typ));
  if(f.md=='R')return((d=f.find(n))?d:this.deref(f.typ,n));
  this.error("no record ("+o.id+")");
  return null
}
Parse.prototype.desig=function()
{
  var m=this.qualid();
  var id=this.id;
  var n=this.find(id,m);
  if(!n&&m&&m.id=="HOST"){
    m.dsc.push(n=new Obj('H',id,"HOST"));
    n.typ=Obj.hostT
  }
  //debB('#4f2',' '+id+'='+(n?n.id+":"+n.md+":"+(n.typ?n.typ.id:"??"):'??'));
  var e=(n?new Itm(n.id_(),n.typ,n.md):new Itm(id,Obj.noT,'V'));
  while(true){
    if(this.sym==Scan.PERIOD){
      this.next();
      this.ident();
      n=this.deref(e.typ,this.id);
      if(!n){
        this.error("no such field ("+this.id+")");
        n={
          'typ':Obj.noT,'id':'??'
        }
      }
      //new Itm(n.id,n.typ,'V')
      e.op2(Scan.PERIOD,e,new Itm(n.id,n.typ,n.md));
      e.typ=n.typ;
      e.md=n.md;
      e.dz=n.id
    }else if(this.sym==Scan.OBRAK){
      this.next();
      var f=e.typ.frm();
      if(f.md!='A')this.error("no array");
      //new Itm("",f.typ,'V');
      var el=[];
      this.exprList(el);
      e.arr(e,el,n.typ);
      e.md='V';
      e.az=""+el.last();
      this.eat(Scan.CBRAK)
    }else if(this.sym==Scan.HAT){
      this.next()
      e.typ=e.typ.typ;
      e.mod='V'
    }else if(this.sym==Scan.OPAR&&n&&n.typ&&(n.md=='V'||n.md=='W')&&(n.typ.md!='X')){
      this.next();
      m=this.qualid();
      e.typ=this.findT(this.id,m);
      if(!e.typ){
        this.error("no such type ("+this.id+")");
        e.typ=Obj.noT
      }
      //e.chk(e,n.typ)
      this.eat(Scan.CPAR)
    }else{
      break;
    }
  }
  return e
}
Parse.prototype.exprList=function(a)
{
  a.push(this.expr());
  while(this.sym==Scan.COMMA){
    this.next();
    a.push(this.expr())
  }
}
Parse.prototype.expr=function()
{
  var e=this.simExpr();
  while(this.sym>=Scan.LEQ&&this.sym<=Scan.NEQ||this.sym==Scan._kw.IN||this.sym==Scan._kw.IS){
    var op=this.sym;
    this.next();
    e.op2(op,e,this.simExpr())
  }
  return e;
}
Parse.prototype.simExpr=function()
{
  var neg=false;
  if(this.sym==Scan.PLUS||this.sym==Scan.MINUS){
    neg=(this.sym==Scan.MINUS);
    this.next()
  }
  var e=this.term();
  if(neg)e.op(Scan.MINUS,e);
  while(this.sym==Scan.PLUS||this.sym==Scan.MINUS||this.sym==Scan._kw.OR){
    var op=this.sym;
    this.next();
    e.op2(op,e,this.term())
  }
  return e
}
Parse.prototype.term=function()
{
  var e=this.factor();
  while(this.sym>=Scan.TIMES&&this.sym<=Scan.AND||this.sym==Scan._kw.DIV||this.sym==Scan._kw.MOD){
    var op=this.sym;
    this.next();
    e.op2(op,e,this.factor())
  }
  return e
}
Parse._defId={
  "NIL":"null","TRUE":"true","FALSE":"false"
};
Parse.prototype.factor=function()
{
  var e;
  if(this.sym==Scan.Id){
    var d=Parse._defId[this.scn.id];
    if(d){
      e=new Itm(d,(d=="null"?Obj.noT:Obj.boolT),'C');
      this.next()
    }
    else e=this.desig();
    if(this.sym==Scan.OPAR)this.call(e);
  }else if(this.sym==Scan.Num){
    e=new Itm(this.scn.num,Obj[this.scn.numtyp],'C');
    this.next()
  }else if(this.sym==Scan.Str){
    e=new Itm("\""+this.scn.id.replace(/\\/g,"\\\\")+"\"",Obj.strT,'C');
    this.next()
  }else if(this.sym==Scan.OBRACE){
    e=this.set_()
  }else if(this.sym==Scan.OPAR){
    this.next();
    e=this.expr();
    e.op(Scan.OPAR,e);
    this.eat(Scan.CPAR)
  }else if(this.sym==Scan.TILDE){
    this.next();
    e=this.factor();
    e.op(Scan.TILDE,e)
  }
  return e
}
Parse.prototype.range=function(fn)
{
  var e=this.expr(),e0=null;
  if(this.sym==Scan.ELLIPSIS){
    this.next();
    e0=this.expr();
  }
  if(fn)fn(e,e0)
  return e
}
function rcase(e,f){
  var i=e.v;
  e.v="case "+(i++)+":";
  if(f){
    while(i<=f.v){
      e.v+="case "+(i++)+":"
    }
  }
}
Parse.prototype.case_=function()
{
  if(this.sym!=Scan.BAR&&this.sym!=Scan.ELSE&&this.sym!=Scan.END){
    var c=this.cd;
    var e=this.range(rcase);
    c.put(e);
    while(this.sym==Scan.COMMA){
      this.next();
      e=this.range(rcase);
      c.put(e);
    }
    this.eat(Scan.COLON);
    this.stmtSeq();
    this.cd.put(";break;")
  }
}
function rset(e,f){
  e.setop(e,f)
}
Parse.prototype.set_=function()
{
  var e;
  this.eat(Scan.OBRACE);
  if(this.sym!=Scan.CBRACE){
    e=this.range(rset);
    while(this.sym==Scan.COMMA){
      this.next();
      var e0=this.range(rset);
      e.op2(Scan.PLUS,e,e0)
    }
  }else{
    e=new Itm(0,Obj.setT,'C')
  }
  this.eat(Scan.CBRACE);
  return e
}
//Scope
Parse.prototype.push=function(o)
{
  o.down=this.top;
  this.top=o
}
Parse.prototype.pop=function()
{
  var o=this.top;
  this.top=o.down;
  delete o.down;
  return o
}
Parse.prototype.addMod=function(m)
{
  var d=m.dsc;
  m.dsc=[];
  for(var i=0;i<d.length;++i){
    if(d[i].mk)m.dsc.push(d[i])
  }
  this.mods[m.id]=m
}
function dumpT(t)
{
  if(t)return("["+(t.id?t.id_():"_")+(t.mk?'*':"")+":"+t.md+dumpT(t.typ)+"]");
  return ""
}
function dumpD(o,t)
{
  var s="";
  for(var i=0;i<o.dsc.length;++i){
    var p=o.dsc[i];
    s+=("&nbsp;"+p.id+":"+p.md);
    if(p.md=='P')s+="("+dumpD(p,false)+")";
    if(p.md=='V'&&p.typ&&p.typ.md=='X')s+="("+dumpD(p.typ,false)+")";
    if(p.md=='R')s+="{"+dumpD(p,false)+"}";
    if(t&&p.typ)s+=(dumpT(p.typ))
  }
  return s
}
Parse.prototype.dump=function()
{
  var s="<br>";
  var o=this.top;
  while(o){
    s+=(o.id+":"+o.md);
    s+=dumpD(o,true);
    s+="<br>";
    o=o.down
  }
  debLn("<br>====="+s);
}
Parse.prototype.findQ=function(n)
{
  var s=n.toString(),i=s.indexOf('.');
  if(i>0)return this.find(s.substr(i+1),this.find(s.substr(0,i)));
  return this.find(s)
}
Parse.prototype.find=function(n,m)
{
  var c=(m?m:this.top);
  while(c){
    for(var i=0;i<c.dsc.length;++i){
      if(c.dsc[i].id==n)return c.dsc[i]
    }
    c=c.down
  }
  return null
}
Parse.prototype.findT=function(n,m)
{
  var t=this.find(n,m);
  return(t&&t.md=='T'?t:null)
}
Parse.prototype.add=function(o)
{
  this.top.dsc.push(o);
  return o
}
Parse.prototype.mark=function()
{
  return this.top.dsc.length;
}
Parse.prototype.setT=function(i,t)
{
  //if(!t)debB('#f00',"No type!!!");
  var d=this.top.dsc;
  while(i<d.length)d[i++].typ=t
}
//
function addObj(d,md,ids,t)
{
  var o=null;
  for(var i=0;i<ids.length;++i){
    d.push(o=new Obj(md,ids[i]));
    o.typ=t
  }
}
//Obj
function Obj(md,id,mk)
{
  this.md=md;
  this.id=(id?id:'_');
  this.mk=mk;
  this.typ=null;
  this.dsc=[]
}
Obj.prototype.find=function(n)
{
  var d=this.dsc;
  for(var i=0;i<d.length;++i){
    if(d[i].id==n)return d[i]
  }
  return null
}
Obj.prototype.frm=function()
{
  var t=this;
  while(t&&t.id!='_'){
    /*debB("#8fc",t.id+":"+t.md+' ');*/t=t.typ
  };
  return t
}
Obj.prototype.init=function()
{
  var t=this;
  var f=t.frm();
  if(!f)return "null";
  if(f.md=='B')return(f==Obj.boolT?"false":"0");
  else if (f.md=='R')return "new "+t.id_()+"()"
  else if (f.md=='A'){
    var ff=f.typ.frm(),z;
    if(Obj.isNumT(ff))z="_narr(0,";
    else if(ff==Obj.boolT)z="_narr(false,";
    else z="_arr(function(){return "+f.typ.init()+"},"
    return z+t.dim.join()+")"
  }
  return "null"
}
Obj.prototype.id_=function(p)
{
  return (this.mk&&this.mk!="HOST"?this.mk+"."+this.id:(p?p+' ':"")+this.id)
}
Obj.noT=new Obj('T',"??");
Obj.hostT=new Obj('T',"??","HOST");
Obj.intT=Obj.hexT=new Obj('B');
//"int"
Obj.boolT=new Obj('B');
//"bool"
Obj.floatT=new Obj('B');
//"float"
Obj.setT=new Obj('B');
//"set"
Obj.strT=new Obj("string");
//"string"
Obj.isNumT=function(t){
  return t==Obj.intT||t==Obj.floatT||t==Obj.setT
}
Parse.scope0=new Obj('0',"_");
addObj(Parse.scope0.dsc,'T',["INTEGER","SHORTINT","LONGINT","CHAR"],Obj.intT),
addObj(Parse.scope0.dsc,'T',["REAL","LONGREAL"],Obj.floatT);
addObj(Parse.scope0.dsc,'T',["BOOLEAN"],Obj.boolT);
addObj(Parse.scope0.dsc,'T',["SET"],Obj.setT);
//Item
function Itm(v,t,m)
{
  this.v=v;
  //val
  this.typ=t;
  this.md=m
}
Itm.prototype.toString=function()
{
  if(this.md=='W'){
    var f=this.typ.frm();
    if(f.md!='R'&&f.md!='A')return this.v+"()"
  }
  return this.v
}
Itm.prototype.op=function(op,x)
{
  if(x.md=='C'){
    if(op==Scan.MINUS){
      this.v=(x.typ==Obj.setT?~x.v:-x.v)
    }else if(op==Scan.OPAR){
      this.v=x.v
    }else if(op==Scan.TILDE){
      this.v=!x.v
    }
    this.md='C'
  }else{
    if(op==Scan.MINUS){
      this.v=(x.typ==Obj.setT?"~":"-")+x.v
    }else if(op==Scan.OPAR){
      this.v="("+x.v+")"
    }else if(op==Scan.TILDE){
      this.v="!"+x.v
    }
    this.md='V'
  }
  this.typ=x.typ
}
Itm.rel=['=','<=','>=','<','>','==','!='];
Itm.num=['+','-','*','/','&&','.'];
Itm.bin=['|','&~','&','^','&&','.'];
Itm.prototype.op2=function(op,x,y)
{
  var s;
  if(op<Scan.KW){
    if(op<=Scan.NEQ)s=Itm.rel[op-Scan.ASSIGN];
    else{
      if(x.typ==Obj.setT){
        s=Itm.bin[op-Scan.PLUS];
        if(op==Scan.MINUS)x.op(Scan.OPAR,x)
      }else{
        s=Itm.num[op-Scan.PLUS];
      }
    }
  }else if(op==Scan._kw.OR){
    s='||'
  }else if(op==Scan._kw.DIV||op==Scan._kw.MOD){
    this.v='Math.floor('+x+(op==Scan._kw.DIV?'/':'%')+y+')';
    this.md='V';
    return
  }else if(op==Scan._kw.IS){
    s=' instanceof '
  }
  this.v=x+s+y;
  this.md='V'
}
Itm.prototype.assign=function(x,y)
{
  var md=x.md;
  this.md='V';
  this.typ=x.typ;
  /*!!*/
  //debB('#ff0',"ass:"+x.v+":"+x.md+";");
  if(md=='W'){
    var f=x.typ.frm();
    if(f.md!='R'&&f.md!='A'){
      this.v=x.v+"("+y+")";
      return
    }
  }
  this.op2(Scan.ASSIGN,x,y)
}
Itm.prototype.arr=function(x,a,t)
{
  this.v=x+"["+a.join("][")+"]";
  this.typ=t;
  this.md='V'
}
Itm.prototype.call=function(n,x,a,prs)
{
  //debB('#f80'," "+x+(n?":"+n.id:":-"));
  if(JS.stdFn(this,x,a))return;
  var dsc;
  if(x.md=='H'){
    /*deb("HOST");*/dsc=null;
  }
  else{
    if(n&&n.md=='V')n=n.typ.frm();
    dsc=(n?n.dsc:x.typ.dsc);
    if(dsc.length!=a.length){
      prs.error("arg mismatch");
      return
    }
  }
  var a0=[];
  for(var i=0;i<a.length;++i)a0.push(this.arg(a[i],dsc?dsc[i]:null));
  this.v=x+"("+a0.join()+")";
  this.typ=x.typ;
  this.md='V'
}
Itm.prototype.setop=function(x,y)
{
  if(y){
    if(x.md=='C'&&y.md=='C'){
      this.v=(-1<<x.v)&~(-2<<y.v);
      this.md='C'
    }
    else this.v="("+(x.md=='C'?(-1<<x.v):"-1<<("+x+")")+"&~"+(y.md=='C'?(-2<<y.v):"((-2)<<("+y+"))")+")";
    this.md='V'
  }else{
    this.v=(x.md=='C'?(1<<x.v):"(1<<("+x+"))");
    this.md=x.md
  }
  this.typ=Obj.setT
}
//a[]..[x][y]->a[]..[x],y
//p...q.r-> p...q,"r"
function undesig(d,z,dot)
{
  return d.substr(0,d.length-z.length-(dot?1:2))+","+(dot?'\"'+z+'\"':z)
}
/*
function undesig(d,z,n){return [d.substr(0,z.length-n),z]}
*/
Itm.prototype.arg=function(a,p)//a:Itm=arg,p:Itm=formal par
{
  if(p){
    //debB('#0cf',p.id+":"+dumpT(p.typ));
    var f=(p.typ?p.typ.frm():Obj.noT);
    if(!f)f=Obj.noT;
    if(p.md=='W'){
      if(a.dz||a.az)return "_vp("+undesig(a.v,a.dz?a.dz:a.az,a.dz)+")"
      else if(f.md!='R'&&f.md!='A'&&a.md!='W')return "function($){return $?"+a.v+"=$:"+a.v+"}";
    }else{
      //V
      if(f.md=='R')return p.typ.init()+"._cp("+a.v+")";
      else if(f.md=='A')return "_cpa("+p.typ.init()+","+a.v+")";
      else if(a.md=='W')return a.v+"()";
    }
  }else{
    //debB('#f63',"p is null");
  }
  return a.v
}
//code
function JS(){
  this.c=""
}
JS.prototype.reset=function(){
  this.c=""
}
JS.prototype.toString=function(){
  return this.c
}
JS.prototype.put=function(c){
  this.c+=c
}
JS.prototype.fn=function(o,r)
{
  if(r)return r.typ.id_()+".prototype."+o.id+"=function";
  return (o.mk?o.mk+"."+o.id+"=function":"function "+o.id)
}
JS.prototype.ext=function(t,b)
{
  var s="",f=t.frm();
  for(var i=0;i<f.dsc.length;++i){
    var d=f.dsc[i],g=d.typ.frm();
    s+=","+(g.md=='R'?'#':(g.md=='A'?""+g.dim.length:""))+d.id
  }
  return "_ext("+t.id_()+(b?","+b.id_():"")+",\""+s.substr(1)+"\");"
}
JS.prototype.putT=function(t)
{
  if(t.typ&&t.typ.md=='T'){
    this.c+=t.id_("var")+"="+t.typ.id_()+";"
  }else{
    var f=t.frm();
    //base call unnecessary: if(f.md=='R')this.c+=this.fn(t)+"(){"+(f.typ?f.typ.id+".call(this);":"")+this.flds(f)+"}";
    if(f.md=='R'){
      this.c+=this.fn(t)+"(){"+this.flds(f)+"};"+(true||f.typ?this.ext(t,f.typ):"");
      if(t.alias)for(var i=0;i<t.alias.length;++i)this.c+=t.alias[i].id_()+"="+t.id_()+";";
    }
  }
}
JS.prototype.flds=function(o)
{
  var d=o.dsc,s="";
  for(var i=0;i<d.length;++i)s+=";this."+d[i].id+"="+d[i].typ.init();
  //t.typ.frm().init()
  return s.substr(1)
}
JS.prototype.putI=function(p,e,s)
{
  this.c+=p+e+s
}
JS.prototype.vars=function(d,i0)
{
  if(i0<d.length){
    var s="",m="";
    while(i0<d.length){
      var di=d[i0++];
      if(!di.typ)continue;
      var f=di.typ.frm();
      if(di.mk)m+=di.id_()+"="+di.typ.init()+";"
      else s+=","+di.id+(f&&(f.md=='R'||f.md=='A')?"="+di.typ.init():"")
    }
    this.c+=(s.length>0?"var "+s.substr(1)+";":"")+m
  }
}
/*
function scalar(t)
{
  t=t.frm();return(t.md!='R'&&t.md!='A')
}
JS.assign=function(e,f,arg)
{
  if(e.md=='V'&&f.md=='V'){
    if(scalar(e.typ))this.c+=e+"="+f;
    else this.c+="_cpy("+e+","+f+")"
  }else if(e.md=='W'){
    if(f.md=='W')this.c+=e+"="+f;
  }
}
*/
JS.prototype.putFor=function(n,e0,e1,e2)
{
  var v=n.id_();
  var s="for("+v+"="+e0+";";
  var b=(!e2?1:e2.v);
  if(b>0)s+=v+"<="+e1+";"+v+(b>1?"+="+b:"++");
  else s+=v+">="+e1+";"+v+(b<1?"-="+b:"--");
  this.c+=s+"){"
}
//MIN(T) MAX(t) SIYE(T) ODD ORD CAP CHR LEN SHORT LONG ABS ENTIER
//INC DEC INCL EXCL NEW ASH
//STRING CHRARR
JS.updV=function(op,a0,a1)
{
  return a0.v+"("+a0.v+"()"+op+a1+")"
}
JS._fnx={
  "ABS":"Math.abs(#)","CAP":"((#)&0x5f)","CHR":"((#)&0xff)",
  "ENTIER":"Math.floor(#)","LONG":"(#)","ODD":"((#)&1)","ORD":"(#)",
  "SHORT":"((#)&0xffff)","STRING":"(#).join('')","CHRARR":"_charr(#)"
};
JS.stdFn=function(e,x,a)
{
  var id=x.v,s,op=null;
  var a0=a[0],a1=(a.length>1?a[1]:null);
  switch(id){
    case "NEW":
    e.assign(a[0],new Itm("new "+a[0].typ.id_()+"()"));
    break;
    case "ASH":
    e.v="("+a0+"<<"+(a1?"("+a1+")":"1")+")";
    break;
    case "INC":
    if(a0.md=='V')e.v=a0+(a1?"+="+a1:"++");
    else e.v=JS.updV('+',a0,(a1?a1:"1"));
    //e.v=a0.v+"("+a0.v+"()+"+(a1?a1:"1")+")";break;
    break;
    case "DEC":
    if(a0.md=='V')e.v=a0+(a1?"-="+a1:"--");
    else e.v=JS.updV('+',a0,(a1?a1:"1"));
    //else e.v=a0.v+"("+a0.v+"()-"+(a1?a1:"1")+")";break;
    break;
    case "INCL":
    op="|=";
    case "EXCL":
    if(!op)op="&=~";
    s=(a1.md=='C'?1<<a1.v:"(1<<("+a1+"))");
    if(a0.md=='V')e.v=a0+op+s;
    else e.v=JS.updV(op,a0,s);
    break;
    default:
    var d=JS._fnx[id];
    if(d){
      e.v=d.replace(/#/g,a0);
      return true
    }
    return false
  }
  return true
}
//
//runtime functions
function _vp(a,i){
  return function($){
    return $?a[i]=$:a[i]
  }
}
//function _ext(t,b){t.prototype=new b();t.constructor=t}
function _ext(t,b,v){
  if(v){
    t.prototype=new b()/*;t.constructor=t*/
  }
  else {
    v=b;
    b=null
  }
  t._v=(b?b._v+',':"")+v;
  t._cp=_cp;
  t.prototype._cp=function(f){
    return t._cp(this,f)
  }
}
function _cp(p,q)
{
  var v=this._v,s="";
  var a=v.split(',');
  for(var i=0;i<a.length;++i){
    var k=a[i],c=k.charAt(0);
    if(c=='#'){
      k=k.substr(1);
      s+="p."+k+"._cp(q."+k+");"
    }
    else if(c>='1'&c<='9'){
      k=k.substr(1);
      s+="_cpa(p."+k+",q."+k+","+c+");"
    }
    else s+="p."+k+"=q."+k+";";
  }
  this._cp=new Function("p","q",s+"return this");
  return this._cp(p,q)
}
function _cpa(t,s,n)
{
  if(n>1){
    for(var i=0;i<t.length;++i)_cpa(t[i],s[i],n-1)
  }else if(t[0]._cp){
    for(var i=0;i<t.length;++i)t[i]._cp(s[i]);
  }else{
    for(var i=0;i<t.length;++i)t[i]=s[i];
  }
  return t
}
function _narr(v,a,b,c)
{
  var n=[];
  for(var i=0;i<a;++i)n.push(b?_narr(v,b,c):v);
  return n
}
function _arr(f,a,b,c)
{
  var n=[];
  for(var i=0;i<a;++i)n.push(b?_arr(f,b,c):f());
  return n
}
function _charr(s)
{
  var a=[];
  for(var i=0;i<s.length;++i)a.push(s.charAt(i));
  return a
}
//
function findScriptType(scp,typ)
{
  var code=[];
  for(var i=0;i<scp.length;++i){
    if(scp[i].type.toLowerCase()==typ){
      code.push(scp[i].text)
    }
  }
  return code
}
function addScript(par,code)
{
  var scp=document.createElement("script");
  scp.text=code;
  par.appendChild(scp)//this will also execute the code
}
function compileAll(typ,comp)
{
  var scp=document.getElementsByTagName("script");
  if(scp.length>0){
    var par=scp[0].parentNode;
    var code=findScriptType(scp,typ);
    for(var i=0;i<code.length;++i){
      debLn("<pre>"+code[i]+"</pre>");
      addScript(par,comp(code[i]))
    }
  }
}
function Oberon(){}
Oberon.Init=function()
{
  Oberon.parse=new Parse(new JS());
  compileAll("text/x-oberonscript",Oberon.Compile);
}
Oberon.Compile=function(c)
{
  var p=Oberon.parse;
  p.compile(new Scan(c));
  if(p.err)debLn("<div class='err'><span>ERROR</span>: "+p.err+"</div>");
  debLn();
  debLn(prt(p.code()));
  return p.code()
}
function prt(js)
{
  var out=new OutStream();
  new PrettyScript(true).toHtml(new InStream(js),out);
  return out.html()
}
function $(s){
  return document.getElementById(s)
}
function deb(s){
  var l=$('_dbg');
  if(!l){
    l=document.createElement("div");
    l.id='_dbg';
    document.body.appendChild(l)
  }
  l.innerHTML+=s
}
function debLn(s){
  deb((s?s:"")+"<br/>")
}
function debB(c,s){
  deb("<span style='background-color:"+c+"'>"+s+"</span>")
}