public void checkDuplicateFuncs() {
    int i, j;

    for (i = 0; i < symbolTable.getLast() + 1; i++) {
      for (j = 0; j < symbolTable.getLast() + 1; j++) {
        if (i != j
            && symbolTable.table.get(i).tokenValue.equals(symbolTable.table.get(j).tokenValue)
            && symbolTable.table.get(i).datatype.equals(symbolTable.table.get(j).datatype)) {
          if (symbolTable.table.get(i).scope.equals("#func")
              && symbolTable.table.get(i).scope.equals(symbolTable.table.get(j).scope))
            this.setDuplicateFuncNameMessage();
        }
      }
    }
  }
  private Boolean checkDuplicateVars() {
    int i, j;
    Boolean ret = false;

    for (i = 0; i < symbolTable.getLast() + 1; i++) {
      for (j = 0; j < symbolTable.getLast() + 1; j++) {
        if (i != j
            && symbolTable.table.get(i).tokenValue.equals(symbolTable.table.get(j).tokenValue)) {
          if (symbolTable.table.get(i).scope.equals(symbolTable.table.get(j).scope)) {
            this.setDuplicateVarMessage();
            ret = true;
          }
        }
      }
    }
    return ret;
  }
  private void checkDeclarationStatements(ArrayList<String> DecStatements) {
    int i, j, k, in = 0;
    // ArrayList<String> errors = new ArrayList<String>();
    Boolean verifyIfDeclared = false;
    Boolean verifyAnotherVar = false;

    for (i = 0; i < DecStatements.size(); i = i + 4) {
      for (j = 0; j < symbolTable.getLast() + 1; j++) {
        // first check if left is a declared variable
        if (symbolTable.table.get(j).tokenValue.equals(DecStatements.get(i))
            && symbolTable.table.get(j).scope.equals(DecStatements.get(i + 2))) {
          verifyIfDeclared = true;
        }
        // after verifying validity of variable, check the assignment statement, TYPE CHECKING
        if (verifyIfDeclared == true) {
          for (k = 0; k < symbolTable.getLast() + 1; k++) {
            if (DecStatements.get(i + 1).equals(symbolTable.table.get(k).tokenValue)
                && DecStatements.get(i + 2).equals(symbolTable.table.get(k).scope)) {
              in = 1;
              if (DecStatements.get(i + 3).equals(symbolTable.table.get(k).datatype))
                verifyAnotherVar = true;
              else verifyAnotherVar = false;
            }
          }
          // to-be-assigned value is an actual value (not a variable)
          if (in != 1 && verifyAnotherVar == false) {
            Boolean checktype = checkType(DecStatements.get(i + 1), DecStatements.get(i + 3));
            if (checktype == false) this.setAssignmentMessage();
            else symbolTable.table.get(j).actualValue = DecStatements.get(i + 1);
          }
          if (in == 1 && verifyAnotherVar == false) {
            this.setAssignmentMessage();
          }
        }
      }
      if (verifyIfDeclared == false) {
        this.setUndeclaredVarMessage();
      }
    }
  }
 private void putsChecker(ArrayList<String> putsList) {
   int i, j;
   Boolean check = false;
   for (i = 0; i < putsList.size(); i = i + 2) {
     for (j = 0; j < symbolTable.getLast() + 1; j++) {
       if (symbolTable.table.get(j).tokenValue.equals(putsList.get(i))
           && symbolTable.table.get(j).scope.equals(putsList.get(i + 1))) {
         check = true;
       }
     }
     if (check == false) this.setUndeclaredVarMessage();
   }
 }
  private void checkOperations(ArrayList<String> allOperands) {
    int i, j;
    ArrayList<String> dts = new ArrayList<String>();
    String left_dt = new String();
    Boolean isInteger = false;
    Boolean compatible = true;

    for (i = 0; i < allOperands.size() - 1; i++) {
      for (j = 0; j < symbolTable.getLast() + 1; j++) {

        if (symbolTable.table.get(j).tokenValue.equals(allOperands.get(0))
            && symbolTable.table.get(j).scope.equals(allOperands.get(allOperands.size() - 1))) {
          left_dt = symbolTable.table.get(j).datatype;
        }
        if (i != 0) {
          try {
            Integer.parseInt(allOperands.get(i));
            isInteger = true;
          } catch (NumberFormatException e) {
            isInteger = false;
          }

          if (isInteger == false
              && symbolTable.table.get(j).tokenValue.equals(allOperands.get(i))
              && symbolTable.table.get(j).scope.equals(allOperands.get(allOperands.size() - 1))) {
            dts.add(symbolTable.table.get(j).datatype);
          } else if (isInteger == true) dts.add("#int");
        }
      }
    }

    for (i = 0; compatible == true && i < dts.size(); i++) {
      if (!dts.get(i).equals(left_dt)) {
        compatible = false;
        this.setIncompatibleMessage();
      }
    }
  }
  public void semAnt() {

    ArrayList<String> listOfDecStms = new ArrayList<String>();
    ArrayList<String> listOfFuncWIndex = new ArrayList<String>();
    ArrayList<String> listOfFunc = new ArrayList<String>();
    ArrayList<String> listOfFuncCalls = new ArrayList<String>();
    ArrayList<String> listOfPuts = new ArrayList<String>();
    ArrayList<String> listOfOperations = new ArrayList<String>();

    int i, j, exit = 0;

    // traverse in the list and store all necessary terminals
    for (i = 0; i < list.size(); i++) {

      if (list.get(0).equals("#main")) {
        exit = 1;
      }
      /** ********* storing of indeces of functions and main ******** */
      if (list.get(i).equals("#main")) {
        listOfFuncWIndex.add(Integer.toString(i));
        listOfFuncWIndex.add(list.get(i));
      }

      /** ********* storing of function information ******** */
      if (list.get(i).equals("#func")) {

        /** ********* storing of indeces of functions and main ******** */
        listOfFuncWIndex.add(Integer.toString(i + 1));
        listOfFuncWIndex.add(list.get(i + 1));

        String concat = new String();
        int numOfComma = 0;
        j = i + 1;
        // first store functionName
        listOfFunc.add(list.get(j));

        if (list.get(j + 2).equals(")")) numOfComma = -1;
        for (; !list.get(j).equals(")"); j++) {

          if (list.get(j).equals("#int")
              || list.get(j).equals("#char")
              || list.get(j).equals("#boolean")) {
            concat = concat + list.get(j) + "^" + list.get(j + 1) + "~";
          }
          if (list.get(j).equals(",")) numOfComma++;
        } // end of for loop
        listOfFunc.add(concat);
        listOfFunc.add(Integer.toString(numOfComma + 1));
      }
      /** ********* END OF: storing of function information ******** */

      /** ********* storing of declaration statements ******** */
      else if (list.get(i).equals("=")) {
        listOfOperations = new ArrayList<String>();

        if (!list.get(i + 1).equals("'") && !list.get(i + 2).equals(";")) {
          listOfOperations.add(list.get(i - 1));

          for (int q = i + 1; !list.get(q).equals(";"); q++) {
            if (!list.get(q).equals("=")
                && !list.get(q).equals("+")
                && !list.get(q).equals("-")
                && !list.get(q).equals("/")
                && !list.get(q).equals("%")
                && !list.get(q).equals("*")) {
              listOfOperations.add(list.get(q));
            }
          }
          listOfOperations.add(listOfFuncWIndex.get(listOfFuncWIndex.size() - 1));

          checkOperations(listOfOperations);
        }

        // check first if variable is of type #char, type char have special case: the use of ''
        int incrementer = 2;
        int valIncrementer = 1;
        int verifyIfIn = 0;

        if (list.get(i + 1).equals("'")) {
          incrementer = 4;
          valIncrementer = 2;
        }

        if (list.get(i + incrementer).equals(";")) {
          listOfDecStms.add(list.get(i - 1)); // left

          if (valIncrementer == 2) {
            listOfDecStms.add("~" + list.get(i + valIncrementer)); // right
          } else listOfDecStms.add(list.get(i + valIncrementer));

          listOfDecStms.add(listOfFuncWIndex.get(listOfFuncWIndex.size() - 1)); // left_DeclaredIn

          for (j = 0; j < symbolTable.getLast() + 1; j++) {
            if (symbolTable.table.get(j).tokenValue.equals(list.get(i - 1))
                && symbolTable
                    .table
                    .get(j)
                    .scope
                    .equals(listOfFuncWIndex.get(listOfFuncWIndex.size() - 1))) {
              // System.err.println(list.get(i-1));
              listOfDecStms.add(symbolTable.table.get(j).datatype);
              verifyIfIn = 1;
            }
          }
          if (verifyIfIn == 0) listOfDecStms.add("");
        }
      }
      /** *********END OF: storing of declaration statements ******** */
      if (list.get(i).equals("#puts")) {
        if (!list.get(i + 2).equals("\"")) {
          listOfPuts.add(list.get(i + 2));
          listOfPuts.add(listOfFuncWIndex.get(listOfFuncWIndex.size() - 1));
        }
      }

      int incrementer = 1;
      if (exit != 1) {
        incrementer = 2;
      }
      /** ********* storing of function call info ******** */
      if (list.get(i).equals("(")
          && !list.get(i - incrementer).equals("#func")
          && !list.get(i - 1).equals("#main")
          && !list.get(i - 1).equals("#puts")
          && !list.get(i - 1).equals("while")
          && !list.get(i - 1).equals("if")) {
        if (!list.get(i + 1).equals("#int")
            && !list.get(i + 1).equals("#char")
            && !list.get(i + 1).equals("#boolean")) {

          listOfFuncCalls.add(Integer.toString(i - 1)); // index of function call
          listOfFuncCalls.add(list.get(i - 1)); // name of function call
          listOfFuncCalls.add(listOfFuncWIndex.get(listOfFuncWIndex.size() - 1)); // caller

          String concat = new String();
          for (j = i; !list.get(j).equals(")") && j < list.size() - 1; j++) {
            if (!list.get(j).equals(",") && !list.get(j).equals("("))
              concat = concat + list.get(j) + "~";
          }
          listOfFuncCalls.add(concat); // func call arguments
        }
      } // end of for loop
      /** ********* END OF: storing of function call info ******** */
    }

    /** ****** adding the end index and last******* */
    listOfFuncWIndex.add(Integer.toString(list.size() - 1));
    listOfFuncWIndex.add("last");

    /**
     * ********* SEMANTIC PHASE START: checking of duplicate variables in a function/main *********
     */
    checkDuplicateVars();

    /** ********* SEMANTIC PHASE START: checking of declaration statements ********* */
    if (checkDuplicateVars() != true) checkDeclarationStatements(listOfDecStms);

    /** ********* SEMANTIC PHASE START: checking of duplicate functions ********* */
    checkDuplicateFuncs();

    /** ********* SEMANTIC PHASE START: checking validity of function calls ********* */
    checkValidFuncCalls(listOfFunc, listOfFuncCalls);

    putsChecker(listOfPuts);

    System.err.println("Dec statements:" + listOfDecStms);
    System.err.println("all funcs including main:" + listOfFuncWIndex);
    System.err.println("all funcs:" + listOfFunc);
    System.err.println("all func calls:" + listOfFuncCalls);
    System.err.println("all Operational:" + listOfOperations);
  }
  private void checkValidFuncCalls(ArrayList<String> allFuncs, ArrayList<String> allFuncCalls) {
    int i, j;
    Boolean validFunc = false;

    for (i = 0; i < allFuncCalls.size(); i = i + 4) {
      for (j = 0; j < allFuncs.size(); j = j + 3) {
        if (allFuncCalls.get(i + 1).equals(allFuncs.get(j))) {
          validFunc = true;

          if (allFuncCalls.get(i + 3).equals("") && allFuncs.get(j + 2).equals(Integer.toString(0)))
            System.err.println("func has 0 parameters");
          else if (allFuncCalls.get(i + 3).equals("")
              && !allFuncs.get(j + 2).equals(Integer.toString(0))) validFunc = false;
          else if (!allFuncCalls.get(i + 3).equals("")
              && !allFuncs.get(j + 2).equals(Integer.toString(0))) {
            int k, l;
            String split_parameters[] = allFuncs.get(j + 1).split("\\~");
            String split_arguments[] = allFuncCalls.get(i + 3).split("\\~");
            for (l = 0; l < split_parameters.length; l++) {
              System.err.println("SPLIT" + split_parameters[l]);
            }
            for (k = 0; k < split_arguments.length; k++) {
              int err = 0;
              try {
                Integer.parseInt(split_arguments[k]);
                err = 1;
              } catch (NumberFormatException e) {
                err = 0;
              }

              if ("'".equals(split_arguments[k]) || err == 1)
                this.setFuncParamtypeMismatchMessage();

              System.err.println("SPLIT" + split_arguments[k]);
            }

            // function call have the same no. of arguments as the function header; datatype and
            // variable matching
            if (l == k) {
              for (k = 0; k < split_arguments.length; k++) {
                for (l = 0; l < split_parameters.length; l++) {

                  int n = 0;
                  if (split_parameters[k].contains("#int")) n = 5;
                  else if (split_parameters[k].contains("#char")) n = 6;
                  else if (split_parameters[k].contains("#boolean")) n = 9;

                  if (split_arguments[k].equals(split_parameters[k].substring(n))) {
                    for (int m = 0; m < symbolTable.getLast() + 1; m++) {
                      if (symbolTable.table.get(m).tokenValue.equals(split_arguments[k])
                          && symbolTable.table.get(m).scope.equals(allFuncCalls.get(i + 2))) {
                        String dt = symbolTable.table.get(m).datatype;

                        if (!split_parameters[k].contains(dt))
                          this.setFuncParamtypeMismatchMessage();
                      }
                    }
                  } else this.setParameterMessage();
                }
              }

            } else this.setParameterMessage();
          }
        }
      }
      if (validFunc == false) this.setInvalidFuncMessage();
    }
  }