Esempio n. 1
0
        // adds all predeclared identifiers and methods
        private void addPredeclared()
        {
            // cbio
            // void read( out int val )
            string   name   = "cbio.read";
            CbType   typm   = CbType.Void;
            CbMethod method = new CbMethod(name, typm);

            method.ArgType.Add(CbType.Int);
            List <CbMethod> read = new List <CbMethod>();

            read.Add(method);
            // void write( int val )
            name   = "cbio.write";
            method = new CbMethod(name, typm);
            method.ArgType.Add(CbType.Int);
            List <CbMethod> writes = new List <CbMethod>();

            writes.Add(method);
            // void write( string val )
            method = new CbMethod(name, typm);
            method.ArgType.Add(CbType.String);
            writes.Add(method);
            Methods.Add(name, writes);
        }
Esempio n. 2
0
        // given an Ident or an Array node, look up the type representation
        private CbType lookUpType(AST node)
        {
            CbType result = CbType.Error;

            if (node.Tag == NodeType.Array)
            {
                CbType elemType = lookUpType(node[0]);
                result = CbType.Array(elemType);
            }
            else
            {
                // it has to be an Ident node
                result = lookUpIdenType(node);
                if (result == CbType.Error)
                {
                    // check if it's a struct
                    string name = ((AST_leaf)node).Sval;
                    if (Structs.ContainsKey(name))
                    {
                        result = Structs[name]; // it's a struct type
                    }
                    else
                    {
                        ReportError(node.LineNumber, "Unknown type {0}", name);
                    }
                }
            }
            node.Type = result; //annotate the node
            return(result);
        }
Esempio n. 3
0
 // Static method which returns a unique descriptor for an array type
 public static CbType Array(CbType elt)
 {
     if (arrayTypes.ContainsKey(elt))
     {
         return(arrayTypes[elt]);
     }
     return(arrayTypes[elt] = new CFArray(elt));
 }
Esempio n. 4
0
 public bool AddField(string name, CbType type)
 {
     if (Fields.ContainsKey(name))
     {
         return(false); // error -- duplicate field name
     }
     Fields[name] = new CbField(name, type, this);
     return(true); // success
 }
Esempio n. 5
0
        public override void Visit(AST_nonleaf node)
        {
            int children = node.NumChildren;

            switch (node.Tag)
            {
            case NodeType.Program:
                // do a multiple pre-pass over the declarations of structs, methods and consts
                prePass(node[2]);
                // now check that the using list is OK
                node[0].Accept(this);
                // now typecheck the bodies of method declarations
                node[2].Accept(this);
                break;

            case NodeType.Const:
                // get type of value
                node[2].Accept(this);
                CbType typact = node[2].Type;

                // look up declared type (can only be int or string)
                CbType typdec = lookUpIdenType(node[0]);

                if (typdec != CbType.Int && typdec != CbType.String)
                {
                    ReportError(node[0].LineNumber, "Constants can only be of type int or string");
                }
                else if (typact != CbType.Int && typact != CbType.String)
                {
                    ReportError(node[0].LineNumber, "Constants must be set to a number or string constant");
                }
                else if (typdec != typact)
                {
                    ReportError(node[0].LineNumber, "Mismatched constant type declaration ({0} = {1})", typdec, typact);
                }

                break;

            case NodeType.Struct:
                // Nothing to do ... this has been handled by the prePass method below
                break;

            case NodeType.Method:
                // We have to typecheck the method
                localSymbols.Empty();  // clear the symbol table
                node[2].Accept(this);
                string name = ((AST_leaf)(node[1])).Sval;

                CbMethod meth = getMethod(name, node[2], false);
                if (meth == null)
                {
                    ReportError(node[0].LineNumber, "Unknown method encountered: ({0})", name);
                }
                else
                {
                    // 1. initialize the symbol table with the formal parameters
                    CbType rettyp  = meth.ResultType;
                    AST    formals = node[2];
                    for (int i = 0; i < formals.NumChildren; i++)
                    {
                        SymTabEntry ste = localSymbols.Binding(((AST_leaf)formals[i][1]).Sval, node.LineNumber);
                        ste.Type = lookUpType(formals[i][0]);
                    }
                    // 2. visit the body of the method, type checking it
                    AST block = node[3];
                    LocalVar = 0;
                    block.Accept(this);
                    // check that return statements match return type of method
                    for (int i = 0; i < block.NumChildren; i++)
                    {
                        if (block[i].Tag == NodeType.Return && block[i].Type != rettyp)
                        {
                            ReportError(block[i].LineNumber, "Return statement type ({0}) doesn't match method return type ({1})", block[i].Type, rettyp);
                        }
                    }
                }

                // set ival to local number of variables in method
                ((AST_leaf)(node[1])).Ival = LocalVar;

                break;

            case NodeType.FieldDecl:
                // Nothing to do ... this has been handled by the prePass method below
                break;

            case NodeType.Formal:
                node.Type = lookUpType(node[0]);
                // Nothing else to do ... this has been handled by the prePass method below
                break;

            case NodeType.Array:
                node[0].Accept(this);
                break;

            case NodeType.LocalDecl:
                CbType typ = lookUpType(node[0]);
                // add identifiers to symbol table
                AST idList = node[1];
                // add number of local variables to local list
                LocalVar += idList.NumChildren;
                for (int i = 0; i < idList.NumChildren; i++)
                {
                    // check for duplicates
                    if (localSymbols.Lookup(((AST_leaf)idList[i]).Sval) != null)
                    {
                        ReportError(node[0].LineNumber, "Duplicate variable declaration: {0}", ((AST_leaf)idList[i]).Sval);
                    }
                    else
                    {
                        localSymbols.Binding(((AST_leaf)idList[i]).Sval, node.LineNumber).Type = typ;
                    }
                }
                break;

            case NodeType.Assign:
                // check left side
                node[0].Accept(this);
                // check right side
                node[1].Accept(this);

                // check that right and left hand sides have the same type
                if (node[0].Type != node[1].Type && node[0].Type != CbType.Error && node[1].Type != CbType.Error)
                {
                    ReportError(node[0].LineNumber, "Cannot convert from type {1} to {0}", node[0].Type, node[1].Type);
                }

                node.Type = node[0].Type;
                break;

            case NodeType.Call:
                node.Type = CbType.Error;
                // check parameters
                node[1].Accept(this);

                // find calling method name
                string mname = null;
                // check for cbio.write
                if (node[0].Tag == NodeType.Dot)
                {
                    if (node[0][0].Tag != NodeType.Ident || node[0][1].Tag != NodeType.Ident)
                    {
                        ReportError(node[0].LineNumber, "Invalid method call");
                    }
                    else
                    {
                        mname = ((AST_leaf)node[0][0]).Sval + "." + ((AST_leaf)node[0][1]).Sval;
                    }
                }
                else
                {
                    mname = ((AST_leaf)node[0]).Sval;
                }

                if (mname != null && node[1].Type != CbType.Error)
                {
                    // check for valid method call
                    CbMethod method = getMethod(mname, node[1], true);
                    if (method != null)
                    {
                        node.Type = method.ResultType;
                    }
                }
                break;

            case NodeType.PlusPlus:
                basicTypeCheck(node, null, false, false, CbType.Int);
                // no type declaration
                break;

            case NodeType.MinusMinus:
                basicTypeCheck(node, null, false, false, CbType.Int);
                // no type declaration
                break;

            case NodeType.If:
                int temp1, temp2;

                // check boolean parameter
                node[0].Accept(this);

                if (node[0].Type != CbType.Bool && node[0].Type != CbType.Error)
                {
                    ReportError(node[0].LineNumber, "Invalid boolean expression for if statement");
                }

                // store current # of local variables
                temp1    = LocalVar;
                LocalVar = 0;
                // now check the do statement
                node[1].Accept(this);
                temp2 = LocalVar;
                // now check for the else statement
                node[2].Accept(this);
                // add # of local variables of function to global variable
                if (temp2 > LocalVar)
                {
                    LocalVar = temp1 + temp2;
                }
                else
                {
                    LocalVar = temp1 + LocalVar;
                }

                // no type declaration
                break;

            case NodeType.While:
                // check boolean parameter
                node[0].Accept(this);
                // now check the do statement
                node[1].Accept(this);

                if (node[0].Type != CbType.Bool)
                {
                    ReportError(node[0].LineNumber, "Invalid boolean expression for while statement");
                }

                // no type declaration
                break;

            case NodeType.Read:
                // The two children should be the method 'cbio.read' and the variable v
                // don't visit LHS, just check that call is to cbio.read and type of parameter is int
                node[1].Accept(this);
                if (node[0].Tag != NodeType.Dot || node[1].Type != CbType.Int || node[0][0].Tag != NodeType.Ident || node[0][1].Tag != NodeType.Ident ||
                    ((AST_leaf)node[0][0]).Sval != "cbio" || ((AST_leaf)node[0][1]).Sval != "read")
                {
                    ReportError(node[0].LineNumber, "Invalid read method call");
                }
                break;

            case NodeType.Add:
                basicTypeCheck(node, CbType.Int, false, false, CbType.Int);
                break;

            case NodeType.Sub:
                basicTypeCheck(node, CbType.Int, false, false, CbType.Int);
                break;

            case NodeType.Mul:
                basicTypeCheck(node, CbType.Int, false, false, CbType.Int);
                break;

            case NodeType.Div:
                basicTypeCheck(node, CbType.Int, false, false, CbType.Int);
                break;

            case NodeType.Mod:
                basicTypeCheck(node, CbType.Int, false, false, CbType.Int);
                break;

            case NodeType.And:
                basicTypeCheck(node, CbType.Bool, false, false, CbType.Bool);
                break;

            case NodeType.Or:
                basicTypeCheck(node, CbType.Bool, false, false, CbType.Bool);
                break;

            case NodeType.Equals:
                basicTypeCheck(node, CbType.Bool, true, true, CbType.Int, CbType.String);
                break;

            case NodeType.NotEquals:
                basicTypeCheck(node, CbType.Bool, true, true, CbType.Int, CbType.String);
                break;

            case NodeType.LessThan:
                basicTypeCheck(node, CbType.Bool, false, false, CbType.Int, CbType.String);
                break;

            case NodeType.GreaterThan:
                basicTypeCheck(node, CbType.Bool, false, false, CbType.Int, CbType.String);
                break;

            case NodeType.LessOrEqual:
                basicTypeCheck(node, CbType.Bool, false, false, CbType.Int, CbType.String);
                break;

            case NodeType.GreaterOrEqual:
                basicTypeCheck(node, CbType.Bool, false, false, CbType.Int, CbType.String);
                break;

            case NodeType.UnaryMinus:
                basicTypeCheck(node, CbType.Int, false, false, CbType.Int);
                break;

            case NodeType.Dot:
                // visit left hand side
                node[0].Accept(this);

                string rhs = ((AST_leaf)node[1]).Sval;
                node.Type = CbType.Error;
                // semantic check for string.Length or arr.Length
                if (node[0].Type == CbType.String || node[0].Type is CbArray)
                {
                    if (rhs == "Length")
                    {
                        node.Type = CbType.Int;
                    }
                    else
                    {
                        ReportError(node[0].LineNumber, "Invalid usage of .Length");
                    }
                }
                else if (node[0].Type != CbType.Error)
                {
                    if (node[0].Type is CbStruct)
                    {
                        // check fields of struct
                        string structname = ((CbStruct)node[0].Type).Name;
                        IDictionary <string, CbField> fields = ((CbStruct)node[0].Type).Fields;
                        CbField field;
                        if (fields.TryGetValue(rhs, out field))
                        {
                            node.Type = field.Type;
                        }
                        else
                        {
                            ReportError(node[0].LineNumber, "Invalid field {0} of struct {1}", rhs, structname);
                        }
                    }
                    else
                    {
                        ReportError(node[0].LineNumber, "Invalid usage of dot on type {0}", node[0].Type);
                    }
                }
                break;

            case NodeType.NewStruct:
                // look up type
                node.Type = lookUpType(node[0]);
                break;

            case NodeType.NewArray:
                // visit array size
                node[1].Accept(this);

                node.Type = CbType.Error;
                // check array type
                if (node[1].Type != CbType.Int && node[1].Type != CbType.Error)
                {
                    ReportError(node[1].LineNumber, "Array size must be of type int");
                }
                else if (node[1].Type != CbType.Error)
                {
                    // declare type
                    node.Type = CbType.Array(lookUpType(node[0]));

                    // check for invalid type
                    if (node.Type == CbType.Error)
                    {
                        ReportError(node[0].LineNumber, "Invalid array type {0}", ((AST_leaf)node[0]).Sval);
                    }
                }
                break;

            case NodeType.Index:
                // visit LHS
                node[0].Accept(this);
                // visit RHS
                node[1].Accept(this);

                // perform error checking
                node.Type = CbType.Error;
                if (node[1].Type != CbType.Int && node[1].Type != CbType.Error)
                {
                    ReportError(node[0].LineNumber, "Array index type must be int, not {0}", node[1].Type);
                }
                else if (!(node[0].Type is CbArray) && node[0].Type != CbType.Error)
                {
                    ReportError(node[0].LineNumber, "Array indexing used on non-array type {0}", node[0].Type);
                }
                else if (node[0].Type != CbType.Error && node[1].Type != CbType.Error)
                {
                    node.Type = ((CbArray)node[0].Type).ElementType;
                }
                break;

            default:
                throw new Exception("{0} is not a tag compatible with an AST_nonleaf node");
            }
        }
Esempio n. 6
0
 // Do not call directly -- use CbType.Array(elt) instead
 public CFArray(CbType elt)
 {
     ElementType = elt;
 }
Esempio n. 7
0
 public CFMethod(string nm, CbClass owner, CbType rt) : base(owner)
 {
     Name = nm;  ResultType = rt;
 }
Esempio n. 8
0
 public CFMethod( string nm, CbClass owner, CbType rt )
     : base(owner)
 {
     Name = nm;  ResultType = rt;
 }
Esempio n. 9
0
        // check if child nodes are equal to "tleaf" value, then set the node type equal to "tnode"
        private void basicTypeCheck(AST_nonleaf node, CbType tnode, bool arrays, bool structs, params CbType[] tleaves)
        {
            int children = node.NumChildren;

            node.Type = CbType.Error;
            bool   err      = false;
            bool   suppress = false;
            CbType typ      = null;

            // determine if type of first child matches accepted list
            node[0].Accept(this);
            if (node[0].Type == CbType.Error)
            {
                typ      = CbType.Error;
                suppress = true;
            }
            else if (arrays && node[0].Type is CbArray || structs && node[0].Type is CbStruct)
            {
                typ = node[0].Type;
            }
            else
            {
                foreach (CbType tleaf in tleaves)
                {
                    if (node[0].Type == tleaf)
                    {
                        typ = tleaf;
                        break;
                    }
                }
                if (typ == null)
                {
                    err = true;
                }
            }

            // determine if types of other children match the first
            for (int i = 1; i < children; i++)
            {
                node[i].Accept(this);
                if (node[i].Type == CbType.Error)
                {
                    suppress = true;
                }
                if (node[i].Type != typ)
                {
                    err = true;
                }
            }

            if (err && !suppress)
            {
                if (children > 1)
                {
                    ReportError(node[0].LineNumber, "Cannot perform {0} operation on types '{1}' and '{2}'", node.Tag, node[0].Type, node[1].Type);
                }
                else
                {
                    ReportError(node[0].LineNumber, "Cannot perform {0} operation on type '{1}'", node.Tag, node[0].Type);
                }
                return;
            }

            if (tnode != null)
            {
                node.Type = tnode;
            }

            return;
        }
Esempio n. 10
0
 public CbMethod(string nm, CbType rt)
 {
     Name       = nm;
     ResultType = rt;
     ArgType    = new List <CbType>();
 }
Esempio n. 11
0
 // No need to invoke this constructor ... use the AddField method
 // of CbStruct instead
 public CbField(string nm, CbType t, CbStruct owner)
 {
     Name = nm;  Type = t;  Owner = owner;
 }
Esempio n. 12
0
 // No need to invoke this constructor ... use the AddField method
 // of CbStruct instead
 public CbField( string nm, CbType t, CbStruct owner )
 {
     Name = nm;  Type = t;  Owner = owner;
 }
Esempio n. 13
0
 // Do not call directly -- use CbType.Array(elt) instead
 public CbArray( CbType elt )
 {
     ElementType = elt;
 }
Esempio n. 14
0
 // Static method which returns a unique descriptor for an array type
 public static CbType Array( CbType elt )
 {
     if (arrayTypes.ContainsKey(elt))
     return arrayTypes[elt];
     return (arrayTypes[elt] = new CbArray(elt));
 }
Esempio n. 15
0
 public bool AddField( string name, CbType type )
 {
     if (Fields.ContainsKey(name))
     return false;  // error -- duplicate field name
     Fields[name] = new CbField(name, type, this);
     return true;  // success
 }
Esempio n. 16
0
 public CbMethod( string nm, CbType rt )
 {
     Name = nm;
     ResultType = rt;
     ArgType = new List<CbType>();
 }
Esempio n. 17
0
        // Makes two shallow passes over the declarations inside a class to obtain
        // the names and types of all consts, methods and structs declared at the
        // top level; without this info, typechecking cannot begin.
        private void prePass(AST node)
        {
            addPredeclared();

            AST_kary decls = node as AST_kary;

            if (decls == null || decls.Tag != NodeType.DeclList)
            {
                throw new Exception("Bad argument passed to prePass");
            }
            // make one pass over the declarations just to enter the names of structs into
            // the Structs table
            int arity = decls.NumChildren;

            for (int i = 0; i < arity; i++)
            {
                AST ch = decls[i];
                if (ch.Tag != NodeType.Struct)
                {
                    continue; // it was not a struct declaration
                }
                string name = ((AST_leaf)(ch[0])).Sval;
                if (Structs.ContainsKey(name))
                {
                    ReportError(ch[0].LineNumber, "Duplicate declaration of struct {0}", name);
                }
                else
                {
                    Structs.Add(name, new CbStruct(name));
                }
            }
            // now make a second pass over the declarations to
            // 1. add const declarations to the Consts table
            // 2. add method declarations to the Methods table
            // 3. fill in the field details for each struct in the Structs table
            for (int i = 0; i < arity; i++)
            {
                AST    ch = decls[i];
                string name;
                CbType typ;
                int    argsize;

                switch (ch.Tag)
                {
                case NodeType.Struct:
                    CbStruct str;
                    name = ((AST_leaf)(ch[0])).Sval;

                    // find existing struct
                    Structs.TryGetValue(name, out str);     // do error checking

                    AST fldlst = ch[1];
                    AST fld;
                    AST idlst;

                    argsize = fldlst.NumChildren;
                    int idsize;
                    // iterate through the field list
                    for (int j = 0; j < argsize; j++)
                    {
                        // get field declaration
                        fld = fldlst[j];
                        // find declaration type
                        typ = lookUpType(fld[0]);
                        // get list of variables declared
                        idlst  = fld[1];
                        idsize = idlst.NumChildren;
                        // add all declared variables to the struct
                        for (int k = 0; k < idsize; k++)
                        {
                            str.AddField(((AST_leaf)(idlst[k])).Sval, typ);
                        }
                    }
                    break;

                case NodeType.Const:
                    // Add the name and type of this constant to the Consts table
                    name = ((AST_leaf)(ch[1])).Sval;

                    typ = lookUpType(ch[0]);
                    if (Consts.ContainsKey(name))
                    {
                        ReportError(ch[0].LineNumber, "Duplicate declaration of const {0}", name);
                    }
                    else
                    {
                        Consts.Add(name, typ);
                    }
                    break;

                case NodeType.Method:
                    name = ((AST_leaf)(ch[1])).Sval;
                    ch[2].Accept(this);
                    // check for duplicate method
                    CbMethod existing = getMethod(name, ch[2], false);
                    if (existing != null)
                    {
                        ReportError(ch[0].LineNumber, "Duplicate declaration of method {0}", name);
                        break;
                    }

                    CbType typm = CbType.Void;
                    // create new CbMethod
                    if (ch[0] != null)
                    {
                        typm = lookUpType(ch[0]);
                    }
                    CbMethod method = new CbMethod(name, typm);

                    // add argument list (full signature) to CbMethod
                    AST args = ch[2];
                    for (int j = 0; j < args.NumChildren; j++)
                    {
                        method.ArgType.Add(lookUpType(args[j][0]));
                    }
                    // get list of overloaded methods sharing same name
                    List <CbMethod> methods;
                    if (!Methods.TryGetValue(name, out methods)) // if none exist create new list
                    {
                        methods = new List <CbMethod>();
                    }
                    // add method to list
                    methods.Add(method);
                    // replace old list of methods with this name with new list
                    Methods[name] = methods;
                    break;

                default:
                    throw new Exception("Unexpected node type " + ch.Tag);
                }
            }
        }
Esempio n. 18
0
 public CbField(string nm, CbType t, CbClass owner)
 {
     Name = nm;  Type = t;  Owner = owner;
 }
Esempio n. 19
0
        // check if child nodes are equal to "tleaf" value, then set the node type equal to "tnode"
        private void basicTypeCheck( AST_nonleaf node, CbType tnode, bool arrays, bool structs, params CbType[] tleaves)
        {
            int children = node.NumChildren;
            node.Type = CbType.Error;
            bool err = false;
            bool suppress = false;
            CbType typ = null;

            // determine if type of first child matches accepted list
            node[0].Accept(this);
            if (node[0].Type == CbType.Error)
            {
            typ = CbType.Error;
            suppress = true;
            }
            else if (arrays && node[0].Type is CbArray || structs && node[0].Type is CbStruct)
            typ = node[0].Type;
            else
            {
            foreach (CbType tleaf in tleaves)
            {
                if (node[0].Type == tleaf)
                {
                    typ = tleaf;
                    break;
                }
            }
            if (typ == null)
                err = true;
            }

            // determine if types of other children match the first
            for (int i = 1; i < children; i++)
            {
            node[i].Accept(this);
            if (node[i].Type == CbType.Error)
                suppress = true;
            if (node[i].Type != typ)
                err = true;
            }

            if (err && !suppress)
            {
            if (children > 1)
                ReportError(node[0].LineNumber, "Cannot perform {0} operation on types '{1}' and '{2}'", node.Tag, node[0].Type, node[1].Type);
            else
                ReportError(node[0].LineNumber, "Cannot perform {0} operation on type '{1}'", node.Tag, node[0].Type);
            return;
            }

            if(tnode != null)
            node.Type = tnode;

            return;
        }
Esempio n. 20
0
 public CbField( string nm, CbType t, CbClass owner )
 {
     Name = nm;  Type = t;  Owner = owner;
 }