public Node scan() throws SyntaxException, LexException, SemanticException {
   Node res = syntaxAnalyser.parse();
   ArrayList<Node> tree = syntaxAnalyser.getTree();
   ArrayList<Node> variables = new ArrayList<Node>();
   tree.forEach(
       (node) -> {
         if (node.getTag() == Tag.VARIABLES) variables.add(node);
       });
   setVariablesType(variables);
   ArrayList<Node> sequence = new ArrayList<Node>();
   tree.forEach(
       (node) -> {
         if (node.getTag() == Tag.SEQUENCE) sequence.add(node);
       });
   sequence.forEach(
       (node) -> {
         node.getChildren()
             .forEach(
                 (node1) -> {
                   try {
                     check(node1.getChildren().get(0));
                   } catch (SemanticException e) {
                     e.printStackTrace();
                     System.exit(1);
                   }
                 });
       });
   return res;
 }
 public void printVariablesType() {
   syntaxAnalyser
       .getVariables()
       .forEach(
           (key, value) -> {
             System.out.println(key + ", " + value);
           });
 }
 private void setVariablesType(ArrayList<Node> variables) {
   variables.forEach(
       (v) -> {
         Node type = v.getChildren().get(1);
         Node listId = v.getChildren().get(0);
         listId
             .getChildren()
             .forEach(
                 (id) -> {
                   int tag = 0;
                   if (type.getTag() == Tag.REAL) {
                     tag = Tag.REAL_NUM;
                   } else {
                     if (type.getTag() == Tag.INTEGER) {
                       tag = Tag.INT_NUM;
                     } else {
                       tag = Tag.BOOL_NUM;
                     }
                   }
                   syntaxAnalyser.setVariableType(new Word(id.getStrValue(), id.getTag()), tag);
                 });
       });
 }
  public int check(Node root) throws SemanticException {
    if (root.getType() == 0) {
      switch (root.getTag()) {
        case Tag.STRUCTERED_STATEMENT:
          int tag = root.getChildren().get(0).getTag();
          if (tag == Tag.BEGIN) {
            root.getChildren()
                .get(1)
                .getChildren()
                .forEach(
                    (node) -> {
                      try {
                        check(node.getChildren().get(0));
                      } catch (SemanticException e) {
                        e.printStackTrace();
                        System.exit(1);
                      }
                    });
          } else {
            if (tag == Tag.WHILE) {
              if (check(root.getChildren().get(1)) != Tag.BOOL_NUM) {
                throw new SemanticException(
                    "Semantic error in line "
                        + root.getNumLine()
                        + ", unexpected type, expected type 'boolean'.");
              }
              check(
                  root.getChildren()
                      .get(3)
                      .getChildren()
                      .get(0)); // Проверяем statement->(simple-statement | structured-statement)
            } else {
              if (tag == Tag.WRITELN) {
                check(root.getChildren().get(1));
              } else {
                if (check(root.getChildren().get(1)) != Tag.BOOL_NUM) {
                  throw new SemanticException(
                      "Semantic error in line "
                          + root.getNumLine()
                          + ", unexpected type, expected type 'boolean'.");
                }
                check(root.getChildren().get(3).getChildren().get(0));
                if (root.getChildren().size() > 4) {
                  check(root.getChildren().get(5).getChildren().get(0));
                }
              }
            }
          }
          break;
        case Tag.SIMPLE_STATEMENT:
          int tagId = check(root.getChildren().get(0));
          int tagExpr = check(root.getChildren().get(2));
          if (!checkTags(tagId, tagExpr)) {
            throw new SemanticException(
                "Semantic error in line " + root.getNumLine() + ", unexpected type.");
          }
          root.setType(tagId);
          break;
        case Tag.ID:
          root.setType(
              syntaxAnalyser.getVariables().get(new Word(root.getStrValue(), root.getTag())));
          break;
        case Tag.EXPRESSION:
          if (root.getChildren().size() > 1) {
            int tag1 = check(root.getChildren().get(0));
            int tag2 = check(root.getChildren().get(2));
            if (!checkTagsExpr(tag1, tag2)) {
              throw new SemanticException(
                  "Semantic error in line " + root.getNumLine() + ", unexpected type.");
            }
            root.setType(Tag.BOOL_NUM);
          } else {
            root.setType(check(root.getChildren().get(0)));
          }
          break;
        case Tag.SIMPLE_EXPRESSION:
          if (root.getChildren().size() <= 2) {
            int index = 0;
            if (root.getChildren().get(0).getTag() != Tag.TERM) {
              index = 1;
            }
            root.setType(check(root.getChildren().get(index)));
          } else {
            for (Node node : root.getChildren()) {
              if (node.getTag() == Tag.TERM) {
                int type = check(node);
                if (type == Tag.BOOL_NUM) {
                  throw new SemanticException(
                      "Semantic error in line " + root.getNumLine() + ", unexpected type.");
                }
                if (type == Tag.REAL_NUM) {
                  root.setType(type);
                }
              }
            }
            if (root.getType() == 0) {
              root.setType(Tag.INT_NUM);
            }
          }
          break;
        case Tag.TERM:
          if (root.getChildren().size() == 1) {
            root.setType(check(root.getChildren().get(0)));
          } else {
            int index = 0;
            for (Node node : root.getChildren()) {
              if (node.getTag() == Tag.FACTOR) {
                int type = check(node);
                if (type == Tag.BOOL_NUM) {
                  throw new SemanticException(
                      "Semantic error in line " + root.getNumLine() + ", unexpected type.");
                }
                if (type == Tag.REAL_NUM) {
                  root.setType(type);
                }
              }
              if (node.getTag() == Tag.DIV) {
                root.setType(Tag.REAL_NUM);
              }
              if (node.getTag() == Tag.IDIV || node.getTag() == Tag.IMOD) {
                if (root.getChildren().get(index - 1).getType() != Tag.INT_NUM
                    || check(root.getChildren().get(index + 1)) != Tag.INT_NUM) {
                  throw new SemanticException(
                      "Semantic error in line " + root.getNumLine() + ", unexpected type.");
                }
              }
              index++;
            }
            if (root.getType() == 0) {
              root.setType(Tag.INT_NUM);
            }
          }
          break;
        case Tag.FACTOR:
          if (root.getChildren().get(0).getTag() == Tag.LEFT_PARENTHESIS) {
            root.setType(check(root.getChildren().get(1)));
          } else {
            if (root.getChildren().get(0).getTag() == Tag.ID) {
              root.setType(check(root.getChildren().get(0)));
            } else {
              if (root.getChildren().get(0).getTag() == Tag.SQRT) {
                root.setType(check(root.getChildren().get(1)));
              } else {
                root.setType(root.getChildren().get(0).getType());
              }
            }
          }
          break;
      }
    }

    return root.getType();
  }