예제 #1
0
파일: compiler.cs 프로젝트: kevinmiles/rc24
        public void list(int[] bytecode)
        {
            StringBuilder sb = new StringBuilder();
            Dictionary <int, bluntFunction> RopCodes = new Dictionary <int, bluntFunction>();

            foreach (bluntFunction bf in opCodes.Values)
            {
                RopCodes.Add(bf.opCode, bf);
            }
            sb.Append("\r\npc\top\tmnemonic\r\n");

            //assumes valid bytecode

            for (int i = 1; i < bytecode.Length; i++)
            {
                try
                {
                    bluntFunction fn = RopCodes[bytecode[i]];
                    sb.Append("" + i + "\t" + bytecode[i] + "\t" + fn.name + " ");
                    for (int p = 1; p < fn.opLen; p++)
                    {
                        sb.Append(" " + bytecode[++i]);
                    }
                    sb.Append("\r\n");
                }
                catch (Exception)
                {
                    sb.Append("ERROR" + bytecode[i] + "\r\n");
                }
            }
            Console.Write(sb.ToString());
        }
예제 #2
0
파일: compiler.cs 프로젝트: kevinmiles/rc24
        public string listMethods(Dictionary <String, bluntFunction> methods)
        {
            StringBuilder ret = new StringBuilder();

            foreach (string name in methods.Keys)
            {
                bluntFunction f = methods[name];

                if (f.fparams.Length > 0)
                {
                    ret.Append(f.fparams[0].typeName + " ");
                }
                ret.Append(name + "(");
                bool first = true;
                for (int i = 1; i < f.fparams.Length; i++)
                {
                    bluntParam p = f.fparams[i];
                    if (p.ptype != vtype.constant)
                    {
                        if (!first)
                        {
                            ret.Append(", ");
                        }
                        first = false;

                        ret.Append(p.typeName + " " + p.name);
                    }
                }
                //f.fparams[0].ptype

                ret.Append(")\r\n");
            }

            return(ret.ToString());
        }
예제 #3
0
파일: compiler.cs 프로젝트: kevinmiles/rc24
 public void compileChildren(astNode n, bluntFunction fn, int idx, Dictionary <String, bluntVar> locals, Dictionary <String, bluntLabel> labels)
 {
     if (n.children != null)
     {
         for (int i = 0; i < n.children.Count; i++)
         {
             compile(n.children[i], fn, i, locals, labels);
         }
     }
 }
예제 #4
0
파일: compiler.cs 프로젝트: kevinmiles/rc24
        // pass 1
        public void getMethods(astNode n)
        {
            //get declared function signatures and local stack space
            if (n.type == "FN DECL")
            {
                int nParams = (n.children.Count - 2) / 2 + 1;

                bluntParam[] pTypes = new bluntParam[nParams];
                //return type
                pTypes[0] = getParam(n.children[0]);
                bluntFunction lf = new bluntFunction(n.name, pTypes, -1);

                for (int p = 1; p < nParams; p++)
                {
                    astNode ptype = n.children[(p << 1) - 1];
                    pTypes[p] = getParam(ptype);

                    astNode param = n.children[(p << 1)];
                    pTypes[p].name = param.name;
                    lf.locals.Add(param.name, new bluntVar(p - 1, pTypes[p].ptype, ptype.name)
                    {
                        typename = pTypes[p].objectType
                    });
                }
                getLabels(n, lf.labels);
                lf.locals.Add("@@ret_addr_place_holder", new bluntVar(nParams - 1, vtype.num, null));
                lf.locals.Add("@@stack_frame_place_holder", new bluntVar(nParams, vtype.num, null));
                lf.locals.Add("@@function_frame_place_holder", new bluntVar(nParams + 1, vtype.num, null));

                //find stack usage for local vars
                getLocals(n.children[n.children.Count - 1], lf);

                lf.localStackUsage = lf.locals.Count - (nParams - 1);
                lf.functionType    = fType.SCRIPT;
                if (functions.ContainsKey(lf.mangledName))
                {
                    compilerError(n, "function " + n.name + " with same parameters already declared");
                }
                else
                {
                    functions.Add(lf);
                }
                n.context = lf;
            }
            else if (n.children != null)
            {
                foreach (var child in n.children)
                {
                    getMethods(child);
                }
            }
        }
예제 #5
0
파일: compiler.cs 프로젝트: kevinmiles/rc24
 public void getLocals(astNode n, bluntFunction fn)
 {
     //get local stack space
     if (n.type == "ID" && fn.locals != null)
     {
         if (!fn.labels.ContainsKey(n.name) && !fn.locals.ContainsKey(n.name))
         {
             fn.locals.Add(n.name, new bluntVar(fn.locals.Count, vtype.num, null));
         }
     }
     else if (n.children != null)
     {
         foreach (var child in n.children)
         {
             getLocals(child, fn);
         }
     }
 }
예제 #6
0
파일: compiler.cs 프로젝트: kevinmiles/rc24
        //pass 2 get types
        public void inferTypes(astNode n, Dictionary <String, bluntVar> locals, Dictionary <String, bluntLabel> labels)
        {
            switch (n.type)
            {
            case "ID":
                if (labels.ContainsKey(n.name))
                {
                    n.typename = "label";
                }
                else if (locals.ContainsKey(n.name))
                {
                    n.typename = locals[n.name].typename;
                }
                if (n.typename == null)
                {
                    compilerError(n, "Variable " + n.name + " used without being assigned");
                }
                break;

            case "CONST": n.typename = "num"; break;

            case "STRING": n.typename = "string"; break;

            case "LABEL": n.typename = "label"; break;

            case "FN":
                if (n.name == "=")    //assignments are where type is defined
                {
                    string  varname = n.children[0].name;
                    astNode valNode = n.children[1];
                    inferTypes(valNode, locals, labels);
                    //check type is not changed if var already defined
                    if (locals[varname].typename != null)
                    {
                        if (locals[varname].typename != valNode.typename)
                        {
                            compilerError(n.children[0], "Variable type changed");
                        }
                    }
                    else
                    {
                        locals[varname].typename = n.children[1].typename;
                    }
                    n.typename = n.children[1].typename;
                    //assign needs some thought
                    n.name = "=__num_vref_num";
                }
                else
                {
                    //get types of all parameters
                    if (n.children != null)
                    {
                        foreach (var child in n.children)
                        {
                            inferTypes(child, locals, labels);
                        }
                    }
                    // now find matching function and hence return type
                    // the parser can't tell the difference between a 'code' parameter and any other type
                    // so we can't simply look up mangled name
                    bluntFunction func = null;
                    bool          functionNameFound = false;
                    foreach (bluntFunction fn in functions.Values)
                    {
                        if (fn.name == n.name)     //&& fn.fparams.Length - 1 == n.children.Count)
                        {
                            functionNameFound = true;
                            bool match     = true;
                            int  constants = 0;
                            for (int i = 1; i < fn.fparams.Length; i++)
                            {
                                var p = fn.fparams[i];
                                if (p.ptype == vtype.constant)
                                {
                                    constants++;
                                    continue;
                                }
                                if (n.children.Count < i - 1 - constants - 1)
                                {
                                    match = false;
                                    break;
                                }
                                if (p.typeName == "code" || p.typeName == n.children[i - 1 - constants].typename)
                                {
                                }
                                else
                                {
                                    match = false;
                                }
                            }
                            if (fn.fparams.Length - 1 != n.children.Count + constants)
                            {
                                match = false;
                            }
                            if (match)
                            {
                                func = fn;
                                for (int i = 1; i < fn.fparams.Length; i++)
                                {
                                    if (fn.fparams[i].ptype == vtype.constant)
                                    {
                                        astNode cons = new astNode()
                                        {
                                            val = fn.fparams[i].constantValue.ToString(), type = "CONST", typename = "const"
                                        };
                                        n.children.Insert(i - 1, cons);
                                    }
                                }
                                break;
                            }
                        }
                    }
                    if (func == null)
                    {
                        if (functionNameFound)
                        {
                            compilerError(n, "Wrong parameters for function " + n.name);
                        }
                        else
                        {
                            compilerError(n, "Unknown function " + n.name);
                        }
                    }
                    else
                    {
                        n.typename = func.fparams[0].typeName;
                        n.name     = func.mangledName;
                    }

                    /*
                     * if (functions.ContainsKey(n.name))
                     * {
                     *  bluntFunction fn = functions[n.name];
                     *  if (fn.fparams.Length - 1 != n.children.Count) compilerError(n, "Wrong number of function parameters for function " + n.name);
                     *  for (int i = 1; i < fn.fparams.Length; i++)
                     *  {
                     *      var p = fn.fparams[i];
                     *      if (p.typeName == "code" || p.typeName == n.children[i-1].typename)
                     *      {
                     *
                     *      }
                     *      else compilerError(n, "Wrong type of parameter "+i +" for function " + n.name);
                     *  }
                     *  n.typename = fn.fparams[0].typeName;
                     *  n.name = fn.mangledName;
                     *
                     * }
                     * else compilerError(n, "Unknown function "+ n.name);
                     */
                }
                break;

            case "FN DECL":
                //process body of function
                inferTypes(n.children[n.children.Count - 1], ((bluntFunction)n.context).locals, ((bluntFunction)n.context).labels);

                break;

            default:
                if (n.children != null)
                {
                    foreach (var child in n.children)
                    {
                        inferTypes(child, locals, labels);
                    }
                    n.typename = n.children[0].typename;
                }
                break;
            }
        }
예제 #7
0
파일: compiler.cs 프로젝트: kevinmiles/rc24
        public void compile(astNode n, bluntFunction fn, int idx, Dictionary <String, bluntVar> locals, Dictionary <String, bluntLabel> labels)
        {
            if (n.type == "CompilationUnit")
            {
                compileChildren(n, fn, idx, locals, labels);
            }
            else if (n.type == "ID")//load id on stack
            {
                // if external var put different op codes to get val or ptr
                // how does assign know to call setter
                // special case for assign

                if (!locals.ContainsKey(n.name))
                {
                    //   locals.Add(n.name, new bluntVar(locals.Count, vtype.num,null));
                }
                if (fn != null && fn.fparams[idx + 1].ptype == vtype.vref)
                {
                    prog[pc++] = opCodes["@push var ref"].opCode;
                    prog[pc++] = locals[n.name].offset; //reference to var on stack
                }
                else
                {
                    prog[pc++] = opCodes["@push var val"].opCode;
                    prog[pc++] = locals[n.name].offset; //var value on stack
                }
            }
            else if (n.type == "CONST")
            {
                prog[pc++] = opCodes["@push immediate"].opCode;
                prog[pc++] = int.Parse(n.val);  //val on stack
            }
            else if (n.type == "LABEL")
            {
                labels[n.name].address = pc;
            }
            else if (n.type == "ARRAY")//load id on stack
            {
                // stack should have array ptr then index
                // should know size of array items
                compileChildren(n, fn, idx, locals, labels);
                prog[pc++] = opCodes["@get_array_item"].opCode;
            }
            else if (n.type == "STRING")
            {
                //store string constant somewhere avoiding duplicates
                if (!StringConstants.ContainsKey(n.val))
                {
                    StringConstants.Add(n.val, new List <int>());
                }
                prog[pc++] = opCodes["@push immediate"].opCode;
                // save pc for linking stage when location of string is known
                StringConstants[n.val].Add(pc++);
            }
            else if (n.type == "FN")
            {
                //get param names and call in correct order
                //and combine duplicates to arrays for varags stuff
                //if single item and not array put it in one
                //if already correct type eg code[] leave as is

                //should become list of fnpc/id/const/label
                List <bluntLabel> opParams = new List <bluntLabel>();
                //list of unamed
                List <astNode> unNamedParams = new List <astNode>();
                Dictionary <String, List <astNode> > namedParams = new Dictionary <String, List <astNode> >();

                if (n.children != null)
                {
                    for (int i = 0; i < n.children.Count; i++)
                    {
                        astNode parameter = n.children[i];
                        if (parameter.name == null || parameter.name == "")
                        {
                            unNamedParams.Add(parameter);
                        }
                        else
                        {
                            if (!namedParams.ContainsKey(parameter.name))
                            {
                                namedParams.Add(parameter.name, new List <astNode>());
                            }
                            namedParams[parameter.name].Add(parameter);
                        }
                    }
                }

                bluntFunction fnn;
                if (functions.ContainsKey(n.name))
                {
                    fnn = functions[n.name];
                }
                else
                {
                    compilerError(n, "Unknown function " + n.name);
                    return;
                }


                if (fnn.name == "return")
                {
                    compileChildren(n, fnn, idx, locals, labels);
                    prog[pc++] = functions["@ret user fn"].opCode;
                    prog[pc++] = fn.fparams.Length - 1;
                    return;
                }

                int nparams = 0;
                if (n.children != null)
                {
                    nparams = n.children.Count;
                    for (int i = 0; i < n.children.Count; i++)
                    {
                        astNode paramNode = n.children[i];
                        //if param should be a lambda
                        if (fnn.fparams[i + 1].ptype == vtype.code)
                        {
                            //bodge to check for lambda ptr
                            astNode pNode = paramNode.children[0];
                            //if parameter is already lambda ptr - just copy ptr

                            if (pNode != null && pNode.type == "ID" && locals[pNode.name].type == vtype.code)
                            {
                                compile(paramNode, fnn, i, locals, labels);
                            }
                            else
                            {
                                prog[pc++] = opCodes["@push lambda ptr"].opCode; //put ptr to lambda on stack
                                prog[pc++] = pc + 2;                             //put stack base here as well - not known at compile time
                                prog[pc++] = opCodes["@jump"].opCode;            //jump
                                int lenPc = pc++;
                                //  prog[pc++]=0;//no stack used for locals - could this be used for something else?
                                compile(paramNode, fnn, i, locals, labels);
                                prog[pc++]  = opCodes["@ret user fn"].opCode; //return
                                prog[pc++]  = 0;                              //TODO allow for anon functions with parameters
                                prog[lenPc] = pc - lenPc;
                            }
                        }
                        else if (fnn.fparams[i + 1].ptype == vtype.label)
                        {
                            //always part of op code
                            string labelName = paramNode.getLeftBottomLeaf().name;

                            if (!labels.ContainsKey(labelName))
                            {
                                labels.Add(labelName, new bluntLabel(0));
                            }
                            opParams.Add(labels[labelName]);
                        }
                        else
                        {
                            compile(paramNode, fnn, i, locals, labels);
                        }
                    }
                }
                if (fnn.functionType == fType.SCRIPT)
                {
                    prog[pc++] = opCodes["@call user fn"].opCode;
                    fnn.callees.Add(pc);//allow forward function declarations
                    prog[pc++] = fnn.opCode;
                    prog[pc++] = nparams;
                    prog[pc++] = fnn.localStackUsage;
                }
                else
                {
                    prog[pc++] = fnn.opCode;
                    //add any opcode parameters
                    foreach (bluntLabel l in opParams)
                    {
                        l.callees.Add(pc++);
                    }
                }

                //ideally pick version of op with or without return as reqd
                if (!fnn.retEmptyStack)
                {
                    if (n.parent.type == "CompilationUnit" || n.parent.type == "FN DECL" || n.parent.type == "BLOCK")
                    {
                        prog[pc++] = opCodes["@dec sp"].opCode;                                                                                              //clear stack
                    }
                }
                else
                {
                    if (!(n.parent.type == "CompilationUnit" || n.parent.type == "FN DECL" || n.parent.type == "BLOCK"))
                    {
                        prog[pc++] = opCodes["@inc sp"].opCode;                                                                                                 //leave value on stack
                    }
                }
            }
            else if (n.type == "FN DECL")
            {
                int           stackLocals = pc; //start of code block
                bluntFunction lf          = (bluntFunction)n.context;
                lf.opCode = stackLocals;

                //create code block
                compile(n.children[n.children.Count - 1], lf, idx, lf.locals, lf.labels);
                //             lf.localStackUsage = fnLocals.Count - nParams;
                //	prog[pc++]=0;//return
                prog[pc++] = opCodes["@ret user fn"].opCode;
                prog[pc++] = lf.fparams.Length - 1;

                foreach (bluntLabel label in lf.labels.Values)
                {
                    foreach (int addr in label.callees)
                    {
                        prog[addr] = label.address - addr;
                    }
                }
            }
            else
            {
                compileChildren(n, fn, idx, locals, labels);
            }

            //update all label references - highly non optimal place to do it !!
        }