//-----------------------------------------------------------
        private Type Visit(Call node, Table table)
        {
            var procName = node.AnchorToken.Lexeme;

            if (!GPTable.Contains(procName))
            {
                throw new SemanticError("The procedure " + procName + " is not defined", node.AnchorToken);
            }

            GlobalProcedure gp = GPTable[procName];

            var parameterList = gp.getParameters();

            if (node.Count() != parameterList.Length)
            {
                throw new SemanticError("Incorrect arity. Expecting " + parameterList.Length + " arguments, but found " + node.Count(), node.AnchorToken);
            }

            int i = 0;

            foreach (var parameter in gp.getParameters())
            {
                Type argumType = Visit((dynamic)node[i], table);
                if (argumType != parameter.LocalType)
                {
                    throw new SemanticError("Incorrect argument. Expecting a " + parameter.LocalType + ", but found a " + argumType, node[i].AnchorToken);
                }
                i++;
            }

            return(gp.ReturnType);
        }
        //-----------------------------------------------------------
        private Type Visit(ProcedureDeclaration node, Table table)
        {
            GlobalSymbolTable gstable = table as GlobalSymbolTable;

            if (table == null)
            {
                throw new TypeAccessException("Expecting a GlobalSymbolTable");
            }

            var procedureName = node.AnchorToken.Lexeme;

            if (gstable.Contains(procedureName))
            {
                throw new SemanticError("Duplicated procedure: " + procedureName, node.AnchorToken);
            }

            if (node[1] is SimpleType || node[1] is ListType)
            {
                GPTable[procedureName] = new GlobalProcedure(false, Visit((dynamic)node[1], table));
                var i = 0;
                foreach (var n in node)
                {
                    if (i != 1)
                    {
                        Visit((dynamic)n, GPTable[procedureName].LocalSymbols);
                    }
                    i++;
                }
            }
            else
            {
                GPTable[procedureName] = new GlobalProcedure(false);
                VisitChildren(node, GPTable[procedureName].LocalSymbols);
            }

            return(Type.VOID);
        }
        //-----------------------------------------------------------
        public SemanticAnalyzer()
        {
            GSTable = new GlobalSymbolTable();
            GPTable = new GlobalProcedureTable();

            GPTable["WrInt"] = new GlobalProcedure(true, Type.VOID);
            GPTable["WrInt"].LocalSymbols["i"] = new LocalSymbol(0, Type.INTEGER);

            GPTable["WrStr"] = new GlobalProcedure(true, Type.VOID);
            GPTable["WrStr"].LocalSymbols["s"] = new LocalSymbol(0, Type.STRING);

            GPTable["WrBool"] = new GlobalProcedure(true, Type.VOID);
            GPTable["WrBool"].LocalSymbols["b"] = new LocalSymbol(0, Type.BOOLEAN);

            GPTable["WrLn"] = new GlobalProcedure(true, Type.VOID);

            GPTable["RdInt"] = new GlobalProcedure(true, Type.INTEGER);

            GPTable["RdStr"] = new GlobalProcedure(true, Type.STRING);

            GPTable["AtStr"] = new GlobalProcedure(true, Type.STRING);
            GPTable["AtStr"].LocalSymbols["s"] = new LocalSymbol(0, Type.STRING);
            GPTable["AtStr"].LocalSymbols["i"] = new LocalSymbol(1, Type.INTEGER);

            GPTable["LenStr"] = new GlobalProcedure(true, Type.INTEGER);
            GPTable["LenStr"].LocalSymbols["s"] = new LocalSymbol(0, Type.STRING);

            GPTable["CmpStr"] = new GlobalProcedure(true, Type.INTEGER);
            GPTable["CmpStr"].LocalSymbols["s1"] = new LocalSymbol(0, Type.STRING);
            GPTable["CmpStr"].LocalSymbols["s2"] = new LocalSymbol(1, Type.STRING);

            GPTable["CatStr"] = new GlobalProcedure(true, Type.STRING);
            GPTable["CatStr"].LocalSymbols["s1"] = new LocalSymbol(0, Type.STRING);
            GPTable["CatStr"].LocalSymbols["s2"] = new LocalSymbol(1, Type.STRING);

            GPTable["LenLstInt"] = new GlobalProcedure(true, Type.INTEGER);
            GPTable["LenLstInt"].LocalSymbols["loi"] = new LocalSymbol(0, Type.LIST_OF_INTEGER);

            GPTable["LenLstStr"] = new GlobalProcedure(true, Type.INTEGER);
            GPTable["LenLstStr"].LocalSymbols["los"] = new LocalSymbol(0, Type.LIST_OF_STRING);

            GPTable["LenLstBool"] = new GlobalProcedure(true, Type.INTEGER);
            GPTable["LenLstBool"].LocalSymbols["lob"] = new LocalSymbol(0, Type.LIST_OF_BOOLEAN);

            GPTable["NewLstInt"] = new GlobalProcedure(true, Type.LIST_OF_INTEGER);
            GPTable["NewLstInt"].LocalSymbols["size"] = new LocalSymbol(0, Type.INTEGER);

            GPTable["NewLstStr"] = new GlobalProcedure(true, Type.LIST_OF_STRING);
            GPTable["NewLstStr"].LocalSymbols["size"] = new LocalSymbol(0, Type.INTEGER);

            GPTable["NewLstBool"] = new GlobalProcedure(true, Type.LIST_OF_BOOLEAN);
            GPTable["NewLstBool"].LocalSymbols["size"] = new LocalSymbol(0, Type.INTEGER);

            GPTable["IntToStr"] = new GlobalProcedure(true, Type.STRING);
            GPTable["IntToStr"].LocalSymbols["i"] = new LocalSymbol(0, Type.INTEGER);

            GPTable["StrToInt"] = new GlobalProcedure(true, Type.INTEGER);
            GPTable["StrToInt"].LocalSymbols["s"] = new LocalSymbol(0, Type.STRING);


            LoopNestingLevel = 0;
        }