/**********************************************************************
         *                     Functions and Subroutines
         * *******************************************************************/

        //-----------------------------------------------------------
        public Type Visit(Function node)
        {
            string functionKeyword = node.AnchorToken.Lexeme;

            if (!Tables.ContainsKey(functionKeyword))
            {
                Tables.Add(functionKeyword, new List <SymbolTable>());
            }
            Tables[functionKeyword].Add(new SymbolTable());
            progUnit = functionKeyword;

            var    functionTable = Tables[progUnit].Last();
            string funcName      = node[1].AnchorToken.Lexeme;

            functionTable[funcName] =
                new SymbolEntry(typeMapper[node[0].AnchorToken.Category]);
            return(Type.VOID);
        }
        //-----------------------------------------------------------
        public Type Visit(Parameter node)
        {
            var paramAssgn   = node[0];
            var variableName = paramAssgn[0].AnchorToken.Lexeme;
            var currentTable = Tables[progUnit].Last();

            if (IdHasBeenFound(variableName))
            {
                if (!currentTable.Contains(variableName))
                {
                    currentTable[variableName] =
                        new SymbolEntry(GetIdType(variableName));
                }
                else
                {
                    if (currentTable[variableName].IsConstant)
                    {
                        throw new SemanticError(
                                  "A variable can only be used in one parameter: "
                                  + variableName,
                                  paramAssgn[0].AnchorToken);
                    }
                }

                currentTable[variableName].IsConstant = true;
                var expectedType = currentTable[variableName].SymbolType;
                var foundType    = Visit((dynamic)paramAssgn[1]);

                if (expectedType != foundType)
                {
                    throw new SemanticError(
                              "Expecting type " + expectedType
                              + " in assignment statement.",
                              paramAssgn[0].AnchorToken);
                }
            }
            else
            {
                throw new SemanticError(
                          "Undeclared variable: " + variableName,
                          paramAssgn[0].AnchorToken);
            }
            return(Type.VOID);
        }
        //-----------------------------------------------------------
        public Type Visit(Declaration node)
        {
            var currentTable = Tables[progUnit].Last();

            foreach (var decl in node)
            {
                var variableName = decl.AnchorToken.Lexeme;
                if (currentTable.Contains(variableName))
                {
                    throw new SemanticError(
                              "Duplicated variable: " + variableName,
                              decl.AnchorToken);
                }
                else
                {
                    currentTable[variableName] =
                        new SymbolEntry(typeMapper[node.AnchorToken.Category]);

                    if (decl.HasChildren())
                    {
                        var declArray = decl[0];
                        if (declArray.NodeChildrenCount() > 2)
                        {
                            throw new SemanticError(
                                      "An array can have 2 dimensions at most: "
                                      + variableName,
                                      decl.AnchorToken);
                        }

                        for (int i = 0; i < declArray.NodeChildrenCount(); i++)
                        {
                            if (Visit((dynamic)declArray[i]) != Type.INTEGER)
                            {
                                throw new SemanticError(
                                          "Only integers can be used as Array dimensions.",
                                          declArray[i].AnchorToken);
                            }

                            if (declArray[i].AnchorToken.Category == TokenCategory.IDENTIFIER)
                            {
                                var dimName = declArray[i].AnchorToken.Lexeme;
                                if (!currentTable.Contains(dimName))
                                {
                                    throw new SemanticError(
                                              "Undeclared dimension: " + dimName,
                                              declArray[i].AnchorToken);
                                }

                                if (!currentTable[dimName].IsConstant)
                                {
                                    throw new SemanticError(
                                              "Cannot use non-constant variables as"
                                              + " array dimensions.",
                                              declArray[i].AnchorToken);
                                }
                            }

                            currentTable[variableName].Params
                            .Add(declArray[i].AnchorToken.Lexeme);
                        }
                    }
                }
            }
            return(Type.VOID);
        }