/* Generated By:JavaCC: Do not edit this line. JostarParser.java */
package jostarfront;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Iterator;
import java.io.FileReader;
import java.io.PrintWriter;
import java.io.File;

import coins.FatalError;
import coins.CompileError;
import coins.FlowRoot;
import coins.HirRoot;
import coins.IoRoot;
import coins.IrRoot;
import coins.SymRoot;
import coins.hir2lir.ConvToNewLIR;
import coins.casttohir.ToHirC;
import coins.casttohir.ToHirBase;
import coins.ir.IrList;
import coins.ir.hir.AssignStmt;
import coins.ir.hir.BlockStmt;
import coins.ir.hir.Exp;
import coins.ir.hir.ConstNode;
import coins.ir.hir.ElemNode;
import coins.ir.hir.ExpStmt;
import coins.ir.hir.ForStmt;
import coins.ir.hir.HIR;
import coins.ir.hir.IfStmt;
import coins.ir.hir.LoopStmt;
import coins.ir.hir.JumpStmt;
import coins.ir.hir.Program;
import coins.ir.hir.SetDataStmt;
import coins.ir.hir.Stmt;
import coins.ir.hir.SubpDefinition;
import coins.ir.hir.SubpDefinitionImpl;
import coins.ir.hir.SubpNode;
import coins.ir.hir.VarNode;
import coins.sym.Const;
import coins.sym.Elem;
import coins.sym.Label;
import coins.sym.NamedConst;
import coins.sym.IntConst;
import coins.sym.FloatConst;
import coins.sym.CharConst;
import coins.sym.StringConst;
import coins.sym.Param;
import coins.sym.PointerType;
import coins.sym.RegionType;
import coins.sym.StructType;
import coins.sym.Subp;
import coins.sym.SymTable;
import coins.sym.Sym;
import coins.sym.Type;
import coins.sym.Var;
import coins.sym.VectorType;
import coins.aflow.FlowResults;
import coins.aflow.RegisterFlowAnalClasses;
import coins.aflow.ShowFlow;
import coins.aflow.SubpFlow;
import coins.backend.BackEnd;
import coins.backend.SyntaxError;
import coins.backend.SyntaxErrorException;
import coins.backend.util.ImList;

public class JostarParser implements JostarParserConstants {
        private SymRoot  symRoot; //  root of symbol information
        private Sym sym;              // Sym object creator
        private HirRoot hirRoot;   // root of HIR information
        private HIR hir;                 // HIR object creator
        private IoRoot ioRoot;     // root of I/O information
    private int currentLine=0; // Line number of token that appeared as the first
        // ID of a statement. When currentLine is recorded as the line number
        // of a statement, then it is set to 0 so that it will be set by next ID.

        public static final int MAX_NEST = 10;
        private Var[] display = new Var[MAX_NEST];
        private PointerType[] ptrType = new PointerType[MAX_NEST];
        private Var[] saveVar = new Var[MAX_NEST];
        private Var[] returnValueVar = new Var[MAX_NEST];
        private PointerType voidPtrType;
        private int nestLevel = -1; //block()でnestLevel++が実行され、0となる


        public JostarParser(SymRoot sRoot, HirRoot hRoot, IoRoot iRoot, FileReader reader) {
                this(reader);
                symRoot = sRoot;
                sym = (Sym)symRoot.sym;
                hirRoot = hRoot;
                hir = (HIR)hirRoot.hir;
                ioRoot = iRoot;
                voidPtrType = sym.pointerType(symRoot.typeVoid);
                hirRoot.programRoot = hir.program(null, symRoot.symTableRoot, null, null);
        }

    /*getType()
     * @param t     データ型を表現する文字列
     * 文字列tをもとに、データ型を返していく。typeidなどで使う*/
    protected Type getType(String t) {
        if ( t.equals("i") ) {
            return symRoot.typeLongLong;
        } else if ( t.equals("i8") ) {
            return symRoot.typeShort;
        } else if ( t.equals("i16") ) {
            return symRoot.typeInt;
        } else if ( t.equals("i32") ) {
            return symRoot.typeLong;
        } else if ( t.equals("i64") ) {
            return symRoot.typeLongLong;
        } else if ( t.equals("v") ) {
            return symRoot.typeVoid;
        } else if ( t.equals("f") ) {
            return symRoot.typeLongDouble;
        } else if ( t.equals("f0") ) {
            return symRoot.typeFloat;
        } else if ( t.equals("f1") ) {
            return symRoot.typeDouble;
        } else if ( t.equals("f2") ) {
            return symRoot.typeLongDouble;
        } else if ( t.equals("u") ) {
            return symRoot.typeU_LongLong;
        } else if ( t.equals("u8") ) {
            return symRoot.typeU_Short;
        } else if ( t.equals("u16") ) {
            return symRoot.typeU_Int;
        } else if ( t.equals("u32") ) {
            return symRoot.typeU_Long;
        } else if ( t.equals("u64") ) {
            return symRoot.typeU_LongLong;
        } else if ( t.equals("b") ) {
            return symRoot.typeBool;
        } else if ( t.equals("s") ) {
            /*本来はVectorType型だが、仮にChar型とおく*/
            return symRoot.typeU_Char;
        } else {
            return symRoot.typeAddress;
        }
    }

    protected void initDisplay() {
        for (int i = 0; i < MAX_NEST; i++){
            display[i] = sym.defineVar(("display_"+i).intern(), voidPtrType);
            display[i].setStorageClass(Var.VAR_STATIC);
        }
    }

  final public void program() throws ParseException {
    BlockStmt lBlockStatement;
    Subp lMain;
    SubpDefinition lMainDef;
    int i = 0;
        initDisplay();

        //---- Build HIR ----//

    label_1:
    while (true) {
      switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
      case UNDEFINEDID:
        ;
        break;
      default:
        jj_la1[0] = jj_gen;
        break label_1;
      }
      dahlObjectClass();
            i++;
    }
    jj_consume_token(MAIN);
        // mainプログラムの準備
        // See defineSubp of Sym.java.
        lMain = sym.defineSubp("main".intern(), symRoot.typeInt);
        lMain.setVisibility(Sym.SYM_PUBLIC);
        symRoot.symTableCurrent.pushSymTable(lMain);
        lMain.closeSubpHeader();
    lBlockStatement = block("main", null);
        lMainDef = hir.subpDefinition(lMain, symRoot.symTableCurrent);
        ((Program)hirRoot.programRoot).addSubpDefinition(lMainDef);
        lMainDef.setHirBody(lBlockStatement); // 実行文のブロックをmainに接続
        symRoot.symTableCurrent.popSymTable();   // mainの記号表を閉じる。

        /*main手続きはダールオブジェクトクラスの中へ入れ子にする
         * dahlObjectClassを参照*/
        while(i > 0) {
            symRoot.symTableCurrent.popSymTable();
            i--;
        }
    jj_consume_token(0);
        if (((HIR)hirRoot.programRoot).finishHir()) {
        } else {
        }
  }

  final public void dahlObjectClass() throws ParseException {
    Token id;
    BlockStmt lBlockStatement;
    Subp lSubp;
    id = jj_consume_token(UNDEFINEDID);
        lSubp = sym.defineSubp(id.image.substring(0, id.image.length()-1).intern(), symRoot.typeInt);
        lSubp.setVisibility(Sym.SYM_PUBLIC);
        symRoot.symTableCurrent.pushSymTable(lSubp);
        lSubp.closeSubpHeader();
    lBlockStatement = block(id.image.substring(0, id.image.length()-1), null);
        SubpDefinition lDef = hir.subpDefinition(lSubp, symRoot.symTableCurrent);
        lDef.setHirBody(lBlockStatement);
        ((Program)hirRoot.programRoot).addSubpDefinition(lDef);
        /*symRoot.symTableCurrent.popSymTable();はmain手続きの後で付ける
         * こうすることで、動的アロケータを実装するために、
         * クラスの中にmainを入れ子にできる
         * 前
         * SClass:{
         * }
         * 
         * main:{
         *   a:new SClass;
         * }
         * 
         * 後
         * main_INCLUDE_GUARD = false
         * SClass:{
         *      main:{
         *        a:new SClass; //dynamic allocator (動的アロケータ)
         *      }
         *      if (!main_INCLUDE_GUARD) {
         *        main();
         *        main_INCLUDE_GUARD = true;
         *      }
         * }
         * */

  }

  final public BlockStmt block(String name, IrList paramList) throws ParseException {
    Stmt stmt;
    BlockStmt lBlockStatement;
    jj_consume_token(LPAREN);
        /*空のブロックを用意*/
        lBlockStatement = hir.blockStmt(null);
    label_2:
    while (true) {
      switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
      case DIJKSTRACONCAT:
      case COROUTINDETACH:
      case COROUTINCALL:
      case COROUTINRESUME:
      case HOARE:
      case SELECT:
      case WHILE:
      case GOTO:
      case RETURN:
      case FOR:
      case EMPTYSTATEMENT:
      case UNDEFINEDID:
      case PROCEDUREID:
      case SELECTTHIS:
      case SELECTORID:
      case ARRAYID:
      case DEFINEDID:
        ;
        break;
      default:
        jj_la1[1] = jj_gen;
        break label_2;
      }
      statement(lBlockStatement);
    }
    jj_consume_token(RPAREN);
        lBlockStatement.addLastStmt(hir.returnStmt(hir.constNode(symRoot.intConst0)));
        {if (true) return lBlockStatement;}
    throw new Error("Missing return statement in function");
  }

  final public void statement(BlockStmt lBlockStatement) throws ParseException {
    switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
    case EMPTYSTATEMENT:
      jj_consume_token(EMPTYSTATEMENT);
      break;
    case UNDEFINEDID:
      variableDeclaration(lBlockStatement);
      break;
    case HOARE:
      hoareStatement(lBlockStatement);
      break;
    case PROCEDUREID:
      procedureCall();
      break;
    case DEFINEDID:
      variableAssignment(lBlockStatement);
      break;
    case SELECT:
      selectiveDeclaration(lBlockStatement);
      break;
    case SELECTTHIS:
    case SELECTORID:
    case ARRAYID:
      dijkstraSelection(lBlockStatement);
      break;
    case WHILE:
      whileStatement(lBlockStatement);
      break;
    case FOR:
      forStatement(lBlockStatement);
      break;
    case GOTO:
      gotoStatement();
      break;
    case RETURN:
      returnStatement();
      break;
    case DIJKSTRACONCAT:
      dijkstraConcatnation();
      break;
    case COROUTINDETACH:
      jj_consume_token(COROUTINDETACH);
      jj_consume_token(46);
      jj_consume_token(47);
      break;
    case COROUTINCALL:
      jj_consume_token(COROUTINCALL);
      jj_consume_token(46);
      jj_consume_token(DEFINEDID);
      jj_consume_token(47);
      break;
    case COROUTINRESUME:
      jj_consume_token(COROUTINRESUME);
      jj_consume_token(46);
      jj_consume_token(DEFINEDID);
      jj_consume_token(47);
      break;
    default:
      jj_la1[2] = jj_gen;
      jj_consume_token(-1);
      throw new ParseException();
    }
  }

  final public void dijkstraConcatnation() throws ParseException {
    jj_consume_token(DIJKSTRACONCAT);
    switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
    case DEFINEDID:
      jj_consume_token(DEFINEDID);
      break;
    case STRING:
      jj_consume_token(STRING);
      break;
    default:
      jj_la1[3] = jj_gen;
      jj_consume_token(-1);
      throw new ParseException();
    }
  }

  final public void variableDeclaration(BlockStmt lBlockStatement) throws ParseException {
    Token id;
    Type t;
    /*<UNDEFINEDID> = "variable:"で、変数名の最後に:が付く
         * その:を取り除くため、substringメソッドを使う*/
        id = jj_consume_token(UNDEFINEDID);
    typeDeclaration(id.image.substring(0, id.image.length()-1), lBlockStatement, id);
  }

  final public void typeDeclaration(String name, BlockStmt lBlockStatement, Token id) throws ParseException {
    Exp lExp;
    Var lVar;
    Stmt lAssignStatement;
    switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
    case DEFINEDID:
      setContainingElement(name, lBlockStatement, id);
      break;
    case PROCEDUREID:
      procedureDeclaration(name);
      break;
    case ARRAYID:
      arrayDeclaration(name, lBlockStatement, id);
      break;
    case NEW:
      NygaardObjectGenerator(name);
      break;
    case LPAREN:
      labelDeclaration(name);
      break;
    default:
      jj_la1[4] = jj_gen;
      jj_consume_token(-1);
      throw new ParseException();
    }
  }

  final public void setContainingElement(String name, BlockStmt lBlockStatement, Token id) throws ParseException {
    Type lType;
    Exp lExp, lVarNode;
    Var lVar;
    Stmt lStmt;
    /*elment ∈ set
         *:= assignment() ∈ typeId()
         *:= 12 ∈ i
         *:= 12->i
         *:= x:12->i
         *:= x:i = 12; 
         * */
    
        lType = typeId();
    lExp = assignment(lType);
        /*変数の定義と値の代入*/
        if (lType == symRoot.typeU_Char) {
            /*文字列型(s型)であるときは、
             * 文字列の長さをgetLength()で取得して、
             * その長さが項目数であるようなChar配列型をlTypeとして書き換える*/
            StringConst st = (StringConst) lExp.getConstSym();
            lType = sym.vectorType(symRoot.typeU_Char, st.getLength());
        }
        lVar = sym.defineVar(name.intern(), lType);
        if (lVar == null) {
            /*変数の再定義エラー
             * defineVarはcoins/Sym.javaによると、
             * 同じ名前の変数を登録しようとすると、nullを返す*/
            ioRoot.msgError.put("Variable '" +name+ "' is already defined. :line " +id.beginLine+ " column " +id.beginColumn);
        } else {
            lVar.setVisibility(Sym.SYM_PUBLIC);
            ioRoot.dbgHir.print(2, "variableDeclaration", lVar.toString() +
                            " " + lType.toString());
            lVarNode = hir.varNode(lVar);
            lStmt = hir.assignStmt(lVarNode, lExp);
            lBlockStatement.addLastStmt(lStmt);
        }
  }

  final public Type typeId() throws ParseException {
    Token token;
    token = jj_consume_token(DEFINEDID);
        String t = token.image;
        {if (true) return getType(t);}
    throw new Error("Missing return statement in function");
  }

  final public void procedureDeclaration(String name) throws ParseException {
    Token type;
    Type returnType;
    Subp lProcedure;
    BlockStmt lBlockStatement;
        IrList paramList;
        Param aParam;
    type = jj_consume_token(PROCEDUREID);
        returnType = getType( type.image.substring(0, type.image.length()-1) );
        if (name != null) {
            /*<PROCEDUREID> = "i("で、iの最後に(が付く
             * その(を取り除くため、substringメソッドを使う*/
            lProcedure = sym.defineSubp(name.intern(), returnType);
        } else {
            /*SelectiveDeclarationで呼び出した場合、
             * typeは型ではなく、自己関手の名前となる
             * 注：これはprocedureDeclarationを再利用するための苦肉の策*/
            lProcedure = sym.defineSubp(type.image.substring(0, type.image.length()-1).intern(), symRoot.typeInt);
        }
        symRoot.symTableCurrent.pushSymTable(lProcedure);
        paramList = hir.irList();
    parameterBlock(lProcedure, paramList);
        lProcedure.closeSubpHeader();
        ioRoot.dbgHir.print(2, "subpDeclaration", lProcedure.toString());
    lBlockStatement = block(name, paramList);
        lProcedure.setVisibility(Sym.SYM_PUBLIC);
        SubpDefinition lDef = hir.subpDefinition(lProcedure, symRoot.symTableCurrent);
        lDef.setHirBody(lBlockStatement);
        ((Program)hirRoot.programRoot).addSubpDefinition(lDef);
        symRoot.symTableCurrent.popSymTable();
  }

  final public void parameterBlock(Subp lSubprogram, IrList paramList) throws ParseException {
    switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
    case UNDEFINEDID:
      parameterDeclaration(lSubprogram, paramList);
      break;
    default:
      jj_la1[5] = jj_gen;
      ;
    }
    label_3:
    while (true) {
      switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
      case 48:
        ;
        break;
      default:
        jj_la1[6] = jj_gen;
        break label_3;
      }
      jj_consume_token(48);
      parameterDeclaration(lSubprogram, paramList);
    }
    jj_consume_token(47);
  }

  final public void parameterDeclaration(Subp lSubprogram, IrList paramList) throws ParseException {
    Type t;
    Token id, type;
    String s;
    id = jj_consume_token(UNDEFINEDID);
        /*<UNDEFINEDID> = "parameter:"で、パラメーター名の最後に:が付く
         * その:を取り除くため、substringメソッドを使う*/
        s = id.image.substring(0, id.image.length()-1);
    switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
    case DEFINEDID:
      t = typeId();
      break;
    case PROCEDUREID:
      procedureDeclaration(s);
            t = symRoot.typeAddress;
      break;
    case ARRAYID:
      type = jj_consume_token(ARRAYID);
      jj_consume_token(49);
            t = getType( type.image.substring(0, type.image.length()-1) );
            VectorType vType = sym.vectorTypeUnfixed(t, 0);
            t = sym.pointerType(vType);
      break;
    default:
      jj_la1[7] = jj_gen;
      jj_consume_token(-1);
      throw new ParseException();
    }
        Param lParam = sym.defineParam(s.intern(), t);
        lSubprogram.addParam(lParam);
        ioRoot.dbgHir.print(2, "paramDeclaration", lParam.toString() +
                " " + t.toString());

        paramList.add(lParam);
  }

  final public void arrayDeclaration(String name, BlockStmt lBlockStatement, Token id) throws ParseException {
    Type t;
    Token type, num;
    Exp lExp, lVarNode;
    Var lVar;
    Stmt lStmt;
    type = jj_consume_token(ARRAYID);
    num = jj_consume_token(NUM);
    jj_consume_token(49);
        t = sym.vectorType( getType( type.image.substring(0, type.image.length()-1) ), Long.parseLong(num.image) );
        lVar = sym.defineVar(name.intern(), t);
        lVar.setVisibility(Sym.SYM_PUBLIC);
  }

  final public void NygaardObjectGenerator(String name) throws ParseException {
    StructType t;
    Var lVar;
    IrList lElemList;
    Sym lTag;
    Token className;
    jj_consume_token(NEW);
    className = jj_consume_token(DEFINEDID);
        /*カルテシアン積型(cartesian product type)のtを作る*/
        lElemList = hir.irList();
        lElemList.add( sym.defineElem("hoho".intern(), getType("i")) );
        lTag = symRoot.symTableCurrent.generateTag(className.image.intern());
        t = sym.structType(lElemList, lTag);
        symRoot.symTableCurrent.pushSymTable(t);
        /*pushSymTableとpopSymTableの間に、カルテシアン積型の追加要素を入れる*/
        symRoot.symTableCurrent.popSymTable();
        lVar = sym.defineVar(name.intern(), t);
        if (lVar == null) {
            /*変数の再定義エラー
             * defineVarはcoins/Sym.javaによると、
             * 同じ名前の変数を登録しようとすると、nullを返す*/
            ioRoot.msgRecovered.put("Variable '" +name+ "' is already defined. :line " +className.beginLine+ " column " +className.beginColumn);
        } else {
            lVar.setVisibility(Sym.SYM_PUBLIC);
        }
  }

  final public void hoareStatement(BlockStmt lBlockStatement) throws ParseException {
    Exp lExp;
    Token className;
    SymTable lSymTable;
    BlockStmt lBlockStatement2;
    Subp lSubp;
    SubpDefinition lSubpDef;
    jj_consume_token(HOARE);
    jj_consume_token(UNDEFINEDID);
    lExp = expression(symRoot.typeLongLong);
    jj_consume_token(47);
    jj_consume_token(LPAREN);
    label_4:
    while (true) {
      jj_consume_token(50);
      className = jj_consume_token(DEFINEDID);
                lSubp = sym.defineSubp(className.image.intern(), symRoot.typeInt);
                lSubp.setVisibility(Sym.SYM_PUBLIC);
                symRoot.symTableCurrent.pushSymTable(lSubp);
                lSubp.closeSubpHeader();
      lBlockStatement2 = block(className.image, null);
                lSubpDef = hir.subpDefinition(lSubp, symRoot.symTableCurrent);
                ((Program)hirRoot.programRoot).addSubpDefinition(lSubpDef);
                lSubpDef.setHirBody(lBlockStatement2);
                symRoot.symTableCurrent.popSymTable();
      switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
      case 50:
        ;
        break;
      default:
        jj_la1[8] = jj_gen;
        break label_4;
      }
    }
    jj_consume_token(RPAREN);
  }

  final public void selectiveDeclaration(BlockStmt lBlockStatement) throws ParseException {
    Subp lProcedure;
    jj_consume_token(SELECT);
    switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
    case UNDEFINEDID:
      variableDeclaration(lBlockStatement);
      break;
    case PROCEDUREID:
      procedureDeclaration(null);
      break;
    default:
      jj_la1[9] = jj_gen;
      jj_consume_token(-1);
      throw new ParseException();
    }
  }

  final public Exp dijkstraSelection(BlockStmt lBlockStatement) throws ParseException {
    switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
    case ARRAYID:
      arrayAssignment();
        {if (true) return null;}
      break;
    case SELECTTHIS:
    case SELECTORID:
      switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
      case SELECTTHIS:
        jj_consume_token(SELECTTHIS);
        break;
      case SELECTORID:
        jj_consume_token(SELECTORID);
        break;
      default:
        jj_la1[10] = jj_gen;
        jj_consume_token(-1);
        throw new ParseException();
      }
      switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
      case PROCEDUREID:
        functor(lBlockStatement);
        break;
      case DEFINEDID:
        variableAssignment(lBlockStatement);
        break;
      case SELECTTHIS:
      case SELECTORID:
      case ARRAYID:
        dijkstraSelection(lBlockStatement);
        break;
      default:
        jj_la1[11] = jj_gen;
        jj_consume_token(-1);
        throw new ParseException();
      }
        {if (true) return null;}
      break;
    default:
      jj_la1[12] = jj_gen;
      jj_consume_token(-1);
      throw new ParseException();
    }
    throw new Error("Missing return statement in function");
  }

  final public void functor(BlockStmt lBlockStatement) throws ParseException {
    procedureCall();
  }

  final public void variableAssignment(BlockStmt lBlockStatement) throws ParseException {
    Exp lExp;
    Stmt lStmt;
    Token id;
    Sym lSym;
    Type lType;
    id = jj_consume_token(DEFINEDID);
        lSym = (Var)symRoot.symTableCurrent.search(id.image.intern());
        if (lSym != null) {
            lType = lSym.getSymType();
        } else {
            lType = symRoot.typeLongLong;
        }
    switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
    case 53:
      lExp = assignment(lType);
            Exp lVarNode = hir.varNode((Var)lSym);
            lStmt = hir.assignStmt(lVarNode, lExp);
            lBlockStatement.addLastStmt(lStmt);
      break;
    case 51:
      jj_consume_token(51);
      break;
    case 52:
      jj_consume_token(52);
      break;
    default:
      jj_la1[13] = jj_gen;
      jj_consume_token(-1);
      throw new ParseException();
    }
  }

  final public void arrayAssignment() throws ParseException {
    Exp lExp;
    jj_consume_token(ARRAYID);
    expression(symRoot.typeLongLong);
    jj_consume_token(49);
    lExp = assignment(symRoot.typeLongLong);
  }

  final public Exp assignment(Type lType) throws ParseException {
    Exp lExp;
    jj_consume_token(53);
    lExp = expression(lType);
        {if (true) return lExp;}
    throw new Error("Missing return statement in function");
  }

  final public Exp procedureCall() throws ParseException {
     Token id;
     Exp lExp;
     IrList lParamList;
    id = jj_consume_token(PROCEDUREID);
         String lSubpName = id.image.substring(0, id.image.length()-1).intern();
                               currentLine = id.beginLine;
                              Subp lSubp = (Subp)symRoot.symTableCurrent.search(lSubpName, Sym.KIND_SUBP);
                              if (lSubp == null) {
                                ioRoot.msgRecovered.put("undeclared subprogram " +lSubpName+ ". :line "  +id.beginLine+ " column " +id.beginColumn);
                                lSubp = sym.defineSubp(lSubpName, symRoot.typeInt);
                              }
                              lParamList = hir.irList();
    switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
    case THIS:
    case PROCEDUREID:
    case SELECTTHIS:
    case SELECTORID:
    case DEFINEDID:
    case NUM:
    case REALNUM:
    case STRING:
    case 60:
    case 61:
      lExp = expression(symRoot.typeLongLong);
        lParamList.add(lExp);
      label_5:
      while (true) {
        switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
        case 48:
          ;
          break;
        default:
          jj_la1[14] = jj_gen;
          break label_5;
        }
        jj_consume_token(48);
        lExp = expression(symRoot.typeLongLong);
            lParamList.add(lExp);
      }
      break;
    default:
      jj_la1[15] = jj_gen;
      ;
    }
    jj_consume_token(47);
         {if (true) return hir.functionExp(hir.exp(HIR.OP_ADDR, hir.subpNode(lSubp)), lParamList);}
    throw new Error("Missing return statement in function");
  }

  final public void labelDeclaration(String label) throws ParseException {
    jj_consume_token(LPAREN);
    jj_consume_token(RPAREN);
  }

  final public void whileStatement(BlockStmt lBlockStatement) throws ParseException {
    BlockStmt lBlockStatement2;
    Exp condition;
    jj_consume_token(WHILE);
    condition = formula(symRoot.typeLongLong);
    jj_consume_token(47);
    lBlockStatement2 = block("while", null);
        LoopStmt wStmt = hir.whileStmt(condition, lBlockStatement2);
        lBlockStatement.addLastStmt(wStmt);
  }

  final public void forStatement(BlockStmt lBlockStatement) throws ParseException {
    BlockStmt lBlockStatement2;
    Exp condition;
    jj_consume_token(FOR);
    variableDeclaration(lBlockStatement);
    jj_consume_token(EMPTYSTATEMENT);
    condition = formula(symRoot.typeLongLong);
    jj_consume_token(EMPTYSTATEMENT);
    switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
    case PROCEDUREID:
      procedureCall();
      break;
    case DEFINEDID:
      variableAssignment(lBlockStatement);
      break;
    case SELECTTHIS:
    case SELECTORID:
    case ARRAYID:
      dijkstraSelection(lBlockStatement);
      break;
    default:
      jj_la1[16] = jj_gen;
      jj_consume_token(-1);
      throw new ParseException();
    }
    jj_consume_token(47);
    lBlockStatement2 = block("for", null);
  }

  final public void gotoStatement() throws ParseException {
    jj_consume_token(GOTO);
    jj_consume_token(DEFINEDID);
  }

  final public void returnStatement() throws ParseException {
    jj_consume_token(RETURN);
    switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
    case THIS:
    case PROCEDUREID:
    case SELECTTHIS:
    case SELECTORID:
    case DEFINEDID:
    case NUM:
    case REALNUM:
    case STRING:
    case 60:
    case 61:
      expression(symRoot.typeLongLong);
      break;
    case EMPTYSTATEMENT:
      jj_consume_token(EMPTYSTATEMENT);
      break;
    default:
      jj_la1[17] = jj_gen;
      jj_consume_token(-1);
      throw new ParseException();
    }
  }

  final public Exp formula(Type lType) throws ParseException {
                        Exp lExp, lExp2; int op;
    lExp = expression(lType);
    op = comparisonOperator();
    lExp2 = expression(lType);
                             lExp = hir.exp(op, lExp, lExp2);
                             ioRoot.dbgHir.print(2, "makeConditionalExp", lExp.toString());
                             {if (true) return lExp;}
    throw new Error("Missing return statement in function");
  }

  final public int comparisonOperator() throws ParseException {
    switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
    case 54:
      jj_consume_token(54);
                         {if (true) return HIR.OP_CMP_EQ;}
      break;
    case 55:
      jj_consume_token(55);
                         {if (true) return HIR.OP_CMP_NE;}
      break;
    case 56:
      jj_consume_token(56);
                        {if (true) return HIR.OP_CMP_GT;}
      break;
    case 57:
      jj_consume_token(57);
                        {if (true) return HIR.OP_CMP_GE;}
      break;
    case 58:
      jj_consume_token(58);
                        {if (true) return HIR.OP_CMP_LT;}
      break;
    case 59:
      jj_consume_token(59);
                        {if (true) return HIR.OP_CMP_LE;}
      break;
    default:
      jj_la1[18] = jj_gen;
      jj_consume_token(-1);
      throw new ParseException();
    }
    throw new Error("Missing return statement in function");
  }

  final public Exp expression(Type lType) throws ParseException {
    Exp lExp, lExp2;
    lExp = term(lType);
    label_6:
    while (true) {
      switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
      case 60:
      case 61:
        ;
        break;
      default:
        jj_la1[19] = jj_gen;
        break label_6;
      }
      switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
      case 60:
        jj_consume_token(60);
        lExp2 = term(lType);
                                    lExp = hir.exp(HIR.OP_ADD, lExp, lExp2);
        break;
      case 61:
        jj_consume_token(61);
        lExp2 = term(lType);
                                     lExp = hir.exp(HIR.OP_SUB, lExp, lExp2);
        break;
      default:
        jj_la1[20] = jj_gen;
        jj_consume_token(-1);
        throw new ParseException();
      }
    }
                                        {if (true) return lExp;}
    throw new Error("Missing return statement in function");
  }

  final public Exp term(Type lType) throws ParseException {
    Exp lExp, lExp2;
    lExp = factor(lType);
    label_7:
    while (true) {
      switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
      case 50:
      case 62:
        ;
        break;
      default:
        jj_la1[21] = jj_gen;
        break label_7;
      }
      switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
      case 50:
        jj_consume_token(50);
        lExp2 = factor(lType);
                                      lExp = hir.exp(HIR.OP_MULT, lExp, lExp2);
        break;
      case 62:
        jj_consume_token(62);
        lExp2 = factor(lType);
                                      lExp = hir.exp(HIR.OP_DIV, lExp, lExp2);
        break;
      default:
        jj_la1[22] = jj_gen;
        jj_consume_token(-1);
        throw new ParseException();
      }
    }
                                       {if (true) return lExp;}
    throw new Error("Missing return statement in function");
  }

  final public Exp factor(Type lType) throws ParseException {
    Exp lExp;
    Token num, str;
    IntConst lConst;
    FloatConst fConst;
    Const sConst;
    switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
    case 60:
      jj_consume_token(60);
      lExp = factor(lType);
                                   {if (true) return lExp;}
      break;
    case 61:
      jj_consume_token(61);
      lExp = factor(lType);
                                   {if (true) return hir.exp(HIR.OP_NEG, lExp);}
      break;
    case PROCEDUREID:
    case SELECTTHIS:
    case SELECTORID:
    case DEFINEDID:
      lExp = variable();
                              {if (true) return lExp;}
      break;
    case THIS:
      jj_consume_token(THIS);
                     lConst = sym.intConst("12".intern(), symRoot.typeInt);
                                    {if (true) return hir.constNode(lConst);}
      break;
    case NUM:
      num = jj_consume_token(NUM);
            lConst = sym.intConst(num.image.intern(), lType);
            {if (true) return hir.constNode(lConst);}
      break;
    case REALNUM:
      num = jj_consume_token(REALNUM);
            fConst = sym.floatConst(num.image.intern(), lType);
            {if (true) return hir.constNode(fConst);}
      break;
    case STRING:
      str = jj_consume_token(STRING);
            sConst = sym.stringConst(str.image.intern());
            {if (true) return hir.constNode(sConst);}
      break;
    default:
      jj_la1[23] = jj_gen;
      jj_consume_token(-1);
      throw new ParseException();
    }
    throw new Error("Missing return statement in function");
  }

  final public Exp variable() throws ParseException {
            Token id; Exp lExp;
    switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
    case PROCEDUREID:
      lExp = procedureCall();
      break;
    case SELECTTHIS:
    case SELECTORID:
      switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
      case SELECTTHIS:
        jj_consume_token(SELECTTHIS);
        break;
      case SELECTORID:
        jj_consume_token(SELECTORID);
        break;
      default:
        jj_la1[24] = jj_gen;
        jj_consume_token(-1);
        throw new ParseException();
      }
      lExp = variable();
      break;
    case DEFINEDID:
      id = jj_consume_token(DEFINEDID);
                if (currentLine == 0) {
                             currentLine = id.beginLine;
                }
                Sym lSym = (Var)symRoot.symTableCurrent.search(id.image.intern());
                if (!(lSym instanceof Var)) {
                    ioRoot.msgRecovered.put("undeclared variable " +id.image+ ". :line "  +id.beginLine+ " column " +id.beginColumn);
                    lSym = sym.defineVar(id.image.intern(), symRoot.typeInt);
                }
                Exp lVarNode = hir.varNode((Var)lSym);
      switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
      case 63:
        jj_consume_token(63);
        lExp = expression(symRoot.typeLongLong);
        jj_consume_token(49);
                                 if (lSym.getSymType() instanceof PointerType)
                                       lExp = hir.subscriptedExp(hir.contentsExp(lVarNode), lExp);
                                  else
                                       lExp = hir.subscriptedExp(lVarNode, lExp);
        break;
      default:
        jj_la1[25] = jj_gen;
                                  if (lSym.getSymType() instanceof VectorType)
                                       lExp = hir.exp(HIR.OP_ADDR, lVarNode);
                                   else
                                       lExp = lVarNode;
      }
      break;
    default:
      jj_la1[26] = jj_gen;
      jj_consume_token(-1);
      throw new ParseException();
    }
        ioRoot.dbgHir.print(4, "makeVariable",lExp.toString());
        {if (true) return lExp;}
    throw new Error("Missing return statement in function");
  }

  final public Exp callExpr() throws ParseException {
               Token id; Exp lExp;
    id = jj_consume_token(DEFINEDID);
                     String lSubpName = id.image.intern();
                               currentLine = id.beginLine;
                              Subp lSubp = (Subp)symRoot.symTableCurrent.search(lSubpName, Sym.KIND_SUBP);
                              if (lSubp == null) {
                                ioRoot.msgRecovered.put("undeclared subprogram " + lSubpName+ ". :line "  +id.beginLine+ " column " +id.beginColumn);
                                lSubp = sym.defineSubp(lSubpName, symRoot.typeInt);
                              }
                              IrList lParamList = hir.irList();
    jj_consume_token(46);
    switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
    case THIS:
    case PROCEDUREID:
    case SELECTTHIS:
    case SELECTORID:
    case DEFINEDID:
    case NUM:
    case REALNUM:
    case STRING:
    case 60:
    case 61:
      lExp = expression(symRoot.typeLongLong);
                                                               lParamList.add(lExp);
      label_8:
      while (true) {
        switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
        case 48:
          ;
          break;
        default:
          jj_la1[27] = jj_gen;
          break label_8;
        }
        jj_consume_token(48);
        lExp = expression(symRoot.typeLongLong);
                                                               lParamList.add(lExp);
      }
      break;
    default:
      jj_la1[28] = jj_gen;
      ;
    }
    jj_consume_token(47);
                            {if (true) return hir.functionExp(hir.exp(HIR.OP_ADDR, hir.subpNode(lSubp)), lParamList);}
    throw new Error("Missing return statement in function");
  }

  Exp makeExp(String ident) throws ParseException {
        Elem elem = null;
        Var frameVar = null;
        Sym s = null;
        // serchElem(ident)
        loop:
        for( SymTable t=symRoot.symTableCurrent; t!=null; t=t.getParent() ) {
                s = t.searchLocal("frame_".intern(), Sym.KIND_VAR);
                IrList elemList = null;
                if(s!=null) {
                        Var v = (Var)s;
                        Type type = v.getSymType();
                        if (type instanceof StructType){
                                elemList = ((StructType)type).getElemList();
                        }
                        Iterator it = elemList.iterator();
                        while(it.hasNext()){
                                elem = (Elem)it.next();
                                if(elem.getName() == ident){
                                        frameVar = v;
                                        break loop;
                                }
                        }
                }
        }
        if (frameVar != null){
                int refLevel = ((Integer)frameVar.getWork()).intValue();
                Exp pExp;
                ElemNode elemNode = hir.elemNode(elem);
                if (refLevel != nestLevel) {
                        pExp = hir.convExp(ptrType[refLevel], hir.varNode(display[refLevel]));
                        return  hir.pointedExp(pExp, elemNode);
                } // else
                pExp = hir.varNode(frameVar);
                return hir. qualifiedExp(pExp, elemNode);
        }
        return null;
  }

  /** Generated Token Manager. */
  public JostarParserTokenManager token_source;
  SimpleCharStream jj_input_stream;
  /** Current token. */
  public Token token;
  /** Next token. */
  public Token jj_nt;
  private int jj_ntk;
  private int jj_gen;
  final private int[] jj_la1 = new int[29];
  static private int[] jj_la1_0;
  static private int[] jj_la1_1;
  static {
      jj_la1_init_0();
      jj_la1_init_1();
   }
   private static void jj_la1_init_0() {
      jj_la1_0 = new int[] {0x40000000,0xc7c48f00,0xc7c48f00,0x0,0x80090000,0x40000000,0x0,0x80000000,0x0,0xc0000000,0x0,0x80000000,0x0,0x0,0x0,0x80020000,0x80000000,0x84020000,0x0,0x0,0x0,0x0,0x0,0x80020000,0x0,0x0,0x80000000,0x0,0x80020000,};
   }
   private static void jj_la1_init_1() {
      jj_la1_1 = new int[] {0x0,0xf,0xf,0x408,0xc,0x0,0x10000,0xc,0x40000,0x0,0x3,0xf,0x7,0x380000,0x10000,0x3000043b,0xf,0x3000043b,0xfc00000,0x30000000,0x30000000,0x40040000,0x40040000,0x3000043b,0x3,0x80000000,0xb,0x10000,0x3000043b,};
   }

  /** Constructor with InputStream. */
  public JostarParser(java.io.InputStream stream) {
     this(stream, null);
  }
  /** Constructor with InputStream and supplied encoding */
  public JostarParser(java.io.InputStream stream, String encoding) {
    try { jj_input_stream = new SimpleCharStream(stream, encoding, 1, 1); } catch(java.io.UnsupportedEncodingException e) { throw new RuntimeException(e); }
    token_source = new JostarParserTokenManager(jj_input_stream);
    token = new Token();
    jj_ntk = -1;
    jj_gen = 0;
    for (int i = 0; i < 29; i++) jj_la1[i] = -1;
  }

  /** Reinitialise. */
  public void ReInit(java.io.InputStream stream) {
     ReInit(stream, null);
  }
  /** Reinitialise. */
  public void ReInit(java.io.InputStream stream, String encoding) {
    try { jj_input_stream.ReInit(stream, encoding, 1, 1); } catch(java.io.UnsupportedEncodingException e) { throw new RuntimeException(e); }
    token_source.ReInit(jj_input_stream);
    token = new Token();
    jj_ntk = -1;
    jj_gen = 0;
    for (int i = 0; i < 29; i++) jj_la1[i] = -1;
  }

  /** Constructor. */
  public JostarParser(java.io.Reader stream) {
    jj_input_stream = new SimpleCharStream(stream, 1, 1);
    token_source = new JostarParserTokenManager(jj_input_stream);
    token = new Token();
    jj_ntk = -1;
    jj_gen = 0;
    for (int i = 0; i < 29; i++) jj_la1[i] = -1;
  }

  /** Reinitialise. */
  public void ReInit(java.io.Reader stream) {
    jj_input_stream.ReInit(stream, 1, 1);
    token_source.ReInit(jj_input_stream);
    token = new Token();
    jj_ntk = -1;
    jj_gen = 0;
    for (int i = 0; i < 29; i++) jj_la1[i] = -1;
  }

  /** Constructor with generated Token Manager. */
  public JostarParser(JostarParserTokenManager tm) {
    token_source = tm;
    token = new Token();
    jj_ntk = -1;
    jj_gen = 0;
    for (int i = 0; i < 29; i++) jj_la1[i] = -1;
  }

  /** Reinitialise. */
  public void ReInit(JostarParserTokenManager tm) {
    token_source = tm;
    token = new Token();
    jj_ntk = -1;
    jj_gen = 0;
    for (int i = 0; i < 29; i++) jj_la1[i] = -1;
  }

  private Token jj_consume_token(int kind) throws ParseException {
    Token oldToken;
    if ((oldToken = token).next != null) token = token.next;
    else token = token.next = token_source.getNextToken();
    jj_ntk = -1;
    if (token.kind == kind) {
      jj_gen++;
      return token;
    }
    token = oldToken;
    jj_kind = kind;
    throw generateParseException();
  }


/** Get the next Token. */
  final public Token getNextToken() {
    if (token.next != null) token = token.next;
    else token = token.next = token_source.getNextToken();
    jj_ntk = -1;
    jj_gen++;
    return token;
  }

/** Get the specific Token. */
  final public Token getToken(int index) {
    Token t = token;
    for (int i = 0; i < index; i++) {
      if (t.next != null) t = t.next;
      else t = t.next = token_source.getNextToken();
    }
    return t;
  }

  private int jj_ntk() {
    if ((jj_nt=token.next) == null)
      return (jj_ntk = (token.next=token_source.getNextToken()).kind);
    else
      return (jj_ntk = jj_nt.kind);
  }

  private java.util.List jj_expentries = new java.util.ArrayList();
  private int[] jj_expentry;
  private int jj_kind = -1;

  /** Generate ParseException. */
  public ParseException generateParseException() {
    jj_expentries.clear();
    boolean[] la1tokens = new boolean[64];
    if (jj_kind >= 0) {
      la1tokens[jj_kind] = true;
      jj_kind = -1;
    }
    for (int i = 0; i < 29; i++) {
      if (jj_la1[i] == jj_gen) {
        for (int j = 0; j < 32; j++) {
          if ((jj_la1_0[i] & (1<<j)) != 0) {
            la1tokens[j] = true;
          }
          if ((jj_la1_1[i] & (1<<j)) != 0) {
            la1tokens[32+j] = true;
          }
        }
      }
    }
    for (int i = 0; i < 64; i++) {
      if (la1tokens[i]) {
        jj_expentry = new int[1];
        jj_expentry[0] = i;
        jj_expentries.add(jj_expentry);
      }
    }
    int[][] exptokseq = new int[jj_expentries.size()][];
    for (int i = 0; i < jj_expentries.size(); i++) {
      exptokseq[i] = (int[])jj_expentries.get(i);
    }
    return new ParseException(token, exptokseq, tokenImage);
  }

  /** Enable tracing. */
  final public void enable_tracing() {
  }

  /** Disable tracing. */
  final public void disable_tracing() {
  }

}
