private void CheckForUndeclaredIdent(ASTProgram root, CheckerInformation info) { UsedIdents usedIdents = new UsedIdents(info); root.GetUsedIdents(usedIdents); info.CurrentNamespace = null; //Check to see if each local outflow parameter was initialized foreach (string ident in info.ProcFuncs) { foreach (ASTParam param in info.ProcFuncs[ident].Params) { if (param.FlowMode == FlowMode.OUT && (!usedIdents.LocalInitialized.ContainsKey(ident) || !usedIdents.LocalInitialized[ident].Contains(param.Ident))) { throw new CheckerException("The outflow parameter '" + param.Ident + "' of the procedure/function '" + ident + "' was not initialized"); } } } //Check if each global outflow parameter was initialized foreach (string global in info.Globals) { if (info.Globals[global] is ASTParam) { ASTParam param = (ASTParam)info.Globals[global]; if (param.FlowMode == FlowMode.OUT && !usedIdents.GlobalInitialized.Contains(param.Ident)) { throw new CheckerException("The global outflow parameter '" + param.Ident + "' of the program was not initialized"); } } } }
public UsedIdents(CheckerInformation info) { AllowInit = true; this.info = info; GlobalInitialized = new List <string>(); LocalInitialized = new Dictionary <string, List <string> >(); }
public override int GenerateCode(int loc, IVirtualMachine vm, CheckerInformation info) { if (Type != Type.DECIMAL && Type != Type.INT32) { throw new IVirtualMachine.InternalError("Use of invalid (not existing) casting type " + Type.ToString()); } Type exprType = Expr.GetExpressionType(info); if (exprType != Type.DECIMAL && exprType != Type.INT32) { throw new IVirtualMachine.InternalError("Cannot cast from type " + exprType.ToString()); } loc = Expr.GenerateCode(loc, vm, info); if (Type != exprType) { if (Type == Type.DECIMAL && exprType == Type.INT32) { vm.IntToDecimal(loc++); } else if (Type == Type.INT32 && exprType == Type.DECIMAL) { vm.DecimalToInt(loc++); } else { throw new IVirtualMachine.InternalError("Invalid casting operation"); } } return(loc); }
public override int GenerateCode(int loc, IVirtualMachine vm, CheckerInformation info) { if (IsFuncCall) { if (info.ProcFuncs.ContainsIdent(Ident)) { ASTProcFuncDecl callee = info.ProcFuncs[Ident]; if (!callee.IsFunc) { throw new IVirtualMachine.InternalError("Calls inside expresssions can only be made to functions but never to procedures!"); } loc = ASTCmdCall.GenerateCallingCode(loc, vm, info, callee, OptInitOrExprList); return(loc); } else { throw new IVirtualMachine.InternalError("Call to unkown function '" + Ident + "'"); } } else { loc = GenerateLValue(loc, vm, info, false); vm.Deref(loc++); return(loc); } }
public override int GenerateCode(int loc, IVirtualMachine vm, CheckerInformation info) { //Get abstract declaration ASTProcFuncDecl callee = info.ProcFuncs[Ident]; loc = ASTCmdCall.GenerateCallingCode(loc, vm, info, callee, ExprList); return(loc); }
private void OptainNamespaceInformation(ASTProgram root, CheckerInformation info) { int globalAddress = 0; //Add global parameters foreach (ASTParam param in root.Params) { param.Address = globalAddress++; info.Globals.addDeclaration(param); } //Add Global Variables, Functions and Procedures //And add local variables and parameters of the Function and Procedures foreach (ASTCpsDecl declaration in root.Declarations) { if (declaration is ASTStoDecl) { //Add global storage identifier declaration.Address = globalAddress++; info.Globals.addDeclaration((ASTStoDecl)declaration); } else if (declaration is ASTProcFuncDecl) { ASTProcFuncDecl procFunc = (ASTProcFuncDecl)declaration; //Add function or procedure identifier declaration.Address = -1; info.ProcFuncs.addDeclaration(procFunc); Namespace <IASTStoDecl> ns = new Namespace <IASTStoDecl>(); info.Namespaces.Add(declaration.Ident, ns); //Relative address: The framepointer is one above the last parameter. Meaning the last parameter has the relative address -1 and the first -Params.Count int paramAddress = -procFunc.Params.Count; //Relative address: out copy, inout copy and local identifiers. Starting 3 addresses behind the frame pointer. int localAddress = 3; //Add local params of this function/procedure foreach (ASTParam localParam in procFunc.Params) { if (localParam.OptMechmode == MechMode.COPY && (localParam.FlowMode == FlowMode.OUT || localParam.FlowMode == FlowMode.INOUT)) { localParam.Address = localAddress++; localParam.AddressLocation = paramAddress++; } else { localParam.Address = paramAddress++; } ns.addDeclaration(localParam); } //Add local storage identifier of this function/procedure foreach (ASTCpsDecl localDeclaration in ((ASTProcFuncDecl)declaration).Declarations) { if (localDeclaration is ASTStoDecl) { localDeclaration.Address = localAddress++; ns.addDeclaration((ASTStoDecl)localDeclaration); } } } } }
public override int GenerateCode(int loc, IVirtualMachine vm, CheckerInformation info) { int copies = 0; foreach (ASTParam param in Params) { if (param.OptMechmode == MechMode.COPY && (param.FlowMode == FlowMode.INOUT || param.FlowMode == FlowMode.OUT)) { ++copies; } } vm.Enter(loc++, copies + Declarations.Count, 0); //CopyIn of inout copy parameters foreach (ASTParam param in Params) { if (param.OptMechmode == MechMode.COPY && param.FlowMode == FlowMode.INOUT) { vm.CopyIn(loc++, param.AddressLocation.Value, param.Address); } } //Generate body foreach (ASTCpsCmd cmd in Commands) { loc = cmd.GenerateCode(loc, vm, info); } //CopyOut of inout copy and out copy parameters bool omit = IsFunc; foreach (ASTParam param in Params) { if (omit) { omit = false; } else { if (param.OptMechmode == MechMode.COPY && (param.FlowMode == FlowMode.INOUT || param.FlowMode == FlowMode.OUT)) { vm.CopyOut(loc++, param.Address, param.AddressLocation.Value); } } } if (IsFunc) { //CopyOut return value //Can't use standard CopyOut, becuase it works with absolute target address and not with top of stack as needed! var paramIttr = Params.GetEnumerator(); paramIttr.MoveNext(); ASTParam result = paramIttr.Current; vm.LoadRel(loc++, result.Address); vm.Deref(loc++); vm.LoadRel(loc++, result.AddressLocation.Value); vm.Store(loc++); } //Return vm.Return(loc++, Params.Count - (IsFunc ? 1 : 0)); //For function the return size is one smaller, leaving the function expression result on the stack! return(loc); }
public static int GenerateCallingCode(int loc, IVirtualMachine vm, CheckerInformation info, ASTProcFuncDecl callee, List <ASTExpression> exprList) { //Allocate Return Location on Stack if (callee.IsFunc) { vm.Alloc(loc++, 1); } //Evaluate argument expressions var paramIttr = callee.Params.GetEnumerator(); //Omit return param for functions if (callee.IsFunc) { if (!paramIttr.MoveNext()) { throw new IVirtualMachine.InternalError("No return param found for function"); } } foreach (ASTExpression expr in exprList) { if (!paramIttr.MoveNext()) { throw new IVirtualMachine.InternalError("Too many arguments"); } ASTParam param = paramIttr.Current; if (param.OptMechmode != MechMode.COPY || (param.FlowMode == FlowMode.OUT || param.FlowMode == FlowMode.INOUT)) { bool modifiable = param.OptChangemode == ChangeMode.VAR; loc = expr.GenerateLValue(loc, vm, info, modifiable); //Load address on the stack } else { loc = expr.GenerateCode(loc, vm, info); //Load value on the stack } } if (paramIttr.MoveNext()) { throw new IVirtualMachine.InternalError("Too few arguments"); } //Address of the function is not known. //So it has to be stored that at this loc should be a call to the function/procedure. if (callee.Address >= 0) { vm.Call(loc, callee.Address); } else { if (!info.Calls.ContainsKey(callee.Ident)) { info.Calls.Add(callee.Ident, new List <int>()); } info.Calls[callee.Ident].Add(loc); } ++loc; return(loc); }
public override int GenerateLValue(int loc, IVirtualMachine vm, CheckerInformation info, bool hasToBeLValue = true) { if (IsFuncCall) { throw new IVirtualMachine.InternalError("The result of a function can't be an LValue"); } else { //Write address to the top of the stack if (info.CurrentNamespace != null && info.Namespaces.ContainsKey(info.CurrentNamespace) && info.Namespaces[info.CurrentNamespace].ContainsIdent(Ident)) { IASTStoDecl storage = info.Namespaces[info.CurrentNamespace][Ident]; if (hasToBeLValue) { AssertNotConstant(storage); } if (storage is ASTStoDecl || (storage is ASTParam && ((ASTParam)storage).OptMechmode == MechMode.COPY)) { //Local Identifier or parameter with mechmode COPY vm.LoadRel(loc++, storage.Address); } else if (storage is ASTParam) { //If mechmode is null: default = Mechmode.REF //Load parameter with mechmode REF vm.LoadRel(loc++, storage.Address); //Relative Address to fp vm.Deref(loc++); //Deref to get global Address //With another Deref the value is loaded } else { //Should never happen as long as no new type is added throw new IVirtualMachine.InternalError("Unknown Identifier Type"); } } else if (info.Globals.ContainsIdent(Ident)) { IASTStoDecl storage = info.Globals[Ident]; if (hasToBeLValue) { AssertNotConstant(storage); } vm.IntLoad(loc++, storage.Address); } else { throw new IVirtualMachine.InternalError("Access of undeclared Identifier " + Ident); } return(loc); } }
public void Check(ASTProgram root, CheckerInformation info) { //Fill namespaces with declaration identifiers //Throws an exception if an identifier is declared more then once in a namespace OptainNamespaceInformation(root, info); //Is any applied identifier declared and initialized? CheckForUndeclaredIdent(root, info); //Checks if the function parameters are valid CheckFunctionParameter(root, info); //TODO: Check: if only specified globals are accessed in procedures/functions //TODO: Check: Only const globals are allowed in functions //TODO: Check: Are only different parameters provided to a procedure as references (Never more then one reference to the same storage) //TODO: test05.iml: local constant variables should not be modifiable }
public override int GenerateCode(int loc, IVirtualMachine vm, CheckerInformation info) { int conditionLoc = loc; loc = Condition.GenerateCode(loc, vm, info); int condJumpLoc = loc++; //Placeholder for conditonal jump out of while loop foreach (ASTCpsCmd cmd in Commands) { loc = cmd.GenerateCode(loc, vm, info); } vm.UncondJump(loc++, conditionLoc); //Fill in placeholder vm.CondJump(condJumpLoc, loc); return(loc); }
static void Main(string[] args) { if (args.Length != 1) { Console.WriteLine("Compiler usage: iml <program>"); return; } //TestVirtualMachine.Test(); return; try { //Scanner Scanner scanner = new Scanner(); var list = scanner.Scan(new StreamReader(args[0])); Console.WriteLine("[" + String.Join(", ", list) + "]"); Console.WriteLine(); //Parser Parser parser = new Parser(); var tree = parser.Parse(list); //Converter var ast = tree.ToAbstractSyntax(); Console.WriteLine(ast.ToString()); Console.WriteLine(); if (!(ast is ASTProgram)) { throw new IVirtualMachine.InternalError("Generation of Abstract Syntax Tree failed."); } ASTProgram program = (ASTProgram)ast; //Checker CheckerInformation info = new CheckerInformation(); ScopeChecker contextChecker = new ScopeChecker(); contextChecker.Check(program, info); //Code Generator IVirtualMachine vm = new VirtualMachine(1000, 1000); program.GenerateCode(0, vm, info); Console.WriteLine(vm.ToString()); Console.WriteLine(); //Executuion vm.Execute(); } catch (Exception ex) { Console.WriteLine("Failed: " + ex.Message); //*Only for debuging of the compiler */ Console.WriteLine(ex.StackTrace); } }
private void CheckFunctionParameter(ASTProgram root, CheckerInformation info) { //Functions can only have one out/inout param (this has to be the first one) foreach (string ident in info.ProcFuncs) { if (info.ProcFuncs[ident].IsFunc) { var paramIttr = info.ProcFuncs[ident].Params.GetEnumerator(); paramIttr.MoveNext(); while (paramIttr.MoveNext()) { if (paramIttr.Current.FlowMode == FlowMode.OUT || paramIttr.Current.FlowMode == FlowMode.INOUT) { throw new CheckerException("A function can not have out/inout parameter."); } } } } }
public override int GenerateCode(int loc, IVirtualMachine vm, CheckerInformation info) { loc = Condition.GenerateCode(loc, vm, info); int condJumpLoc = loc++; //Placeholder foreach (ASTCpsCmd cmd in TrueCommands) { loc = cmd.GenerateCode(loc, vm, info); } int uncondJumpLoc = loc++; //Placeholder2 vm.CondJump(condJumpLoc, loc); //Fill in Placeholder foreach (ASTCpsCmd cmd in FalseCommands) { loc = cmd.GenerateCode(loc, vm, info); } vm.UncondJump(uncondJumpLoc, loc); //Fill in Placeholder2 return(loc); }
public override int GenerateCode(int loc, IVirtualMachine vm, CheckerInformation info) { loc = Expr.GenerateCode(loc, vm, info); var type = GetExpressionType(info); if (type == Type.BOOL) { //1 NE 1 == 0 //0 NE 1 == 1 vm.IntLoad(loc++, 1); vm.IntNE(loc++); } else { throw new IVirtualMachine.InternalError( "Cannot negate Non-Bool value " + Expr.ToString()); } return(loc); }
public override Type GetExpressionType(CheckerInformation info) { if (IsFuncCall) { if (info.ProcFuncs.ContainsIdent(Ident)) { ASTProcFuncDecl callee = info.ProcFuncs[Ident]; if (!callee.IsFunc) { throw new IVirtualMachine.InternalError("Calls inside expresssions can only be made to functions but never to procedures!"); } var paramIttr = callee.Params.GetEnumerator(); if (!paramIttr.MoveNext()) { throw new IVirtualMachine.InternalError("No return param found for function"); } return(paramIttr.Current.Type); } else { throw new IVirtualMachine.InternalError("Call to unkown function '" + Ident + "'"); } } else { if (info.CurrentNamespace != null && info.Namespaces.ContainsKey(info.CurrentNamespace) && info.Namespaces[info.CurrentNamespace].ContainsIdent(Ident)) { return(info.Namespaces[info.CurrentNamespace].GetIdent(Ident).Type); } if (info.Globals.ContainsIdent(Ident)) { return(info.Globals.GetIdent(Ident).Type); } throw new IVirtualMachine.InternalError("Use of unkwon identifier '" + Ident + "'"); } }
public override int GenerateCode(int loc, IVirtualMachine vm, CheckerInformation info) { loc = Expr.GenerateCode(loc, vm, info); var type = GetExpressionType(info); if (type == Type.INT32) { vm.IntInv(loc++); } else if (type == Type.DECIMAL) { vm.DecimalInv(loc++); } else { throw new IVirtualMachine.InternalError( "Cannot inverse " + type.ToString() + " value " + Expr.ToString()); } return(loc); }
public abstract int GenerateCode(int loc, IVirtualMachine vm, CheckerInformation info);
public int GenerateCode(int loc, IVirtualMachine vm, CheckerInformation info) { throw new IVirtualMachine.InternalError("ASTOptInit.GenerateCode was called. This should never happen!"); }
public override Type GetExpressionType(CheckerInformation info) { return(this.Type); }
public int GenerateCode(int loc, IVirtualMachine vm, CheckerInformation info) { return(loc); }
public override Type GetExpressionType(CheckerInformation info) { return(Expr.GetExpressionType(info)); }
public override Type GetExpressionType(CheckerInformation info) { return(Type.BOOL); }
public override int GenerateCode(int loc, IVirtualMachine vm, CheckerInformation info) { vm.IntLoad(loc++, Value ? 1 : 0); return(loc); }
public int GenerateCode(int loc, IVirtualMachine vm, CheckerInformation info) { //Allocate global storage vm.Alloc(loc++, info.Globals.Count); //Load input params foreach (ASTParam param in Params) { if (param.FlowMode == FlowMode.IN || param.FlowMode == FlowMode.INOUT) { //Load address where to save the input vm.IntLoad(loc++, param.Address); //Switch between types: switch (param.Type) { case Type.INT32: vm.IntInput(loc++, param.Ident); break; case Type.BOOL: vm.BoolInput(loc++, param.Ident); break; case Type.DECIMAL: vm.DecimalInput(loc++, param.Ident); break; } } } //Generate main code foreach (ASTCpsCmd cmd in Commands) { loc = cmd.GenerateCode(loc, vm, info); } //Add output code foreach (ASTParam param in Params) { if (param.FlowMode == FlowMode.OUT || param.FlowMode == FlowMode.INOUT) { //Load output value vm.IntLoad(loc++, param.Address); vm.Deref(loc++); //Switch between types: switch (param.Type) { case Type.INT32: vm.IntOutput(loc++, param.Ident); break; case Type.BOOL: vm.BoolOutput(loc++, param.Ident); break; case Type.DECIMAL: vm.DecimalOutput(loc++, param.Ident); break; } } } //Add stop as last command vm.Stop(loc++); //Generate functions/procedures foreach (string ident in info.ProcFuncs) { ASTProcFuncDecl procFunc = info.ProcFuncs[ident]; procFunc.Address = loc; //Add calls, now that the function/procedure address is known if (info.Calls.ContainsKey(ident) && info.Calls[ident] != null) { foreach (int callLoc in info.Calls[ident]) { vm.Call(callLoc, procFunc.Address); } } //Change current namespace info.CurrentNamespace = ident; //Generate code for function/procedure loc = procFunc.GenerateCode(loc, vm, info); //Reset namespace info.CurrentNamespace = null; } return(loc); }
public virtual int GenerateLValue(int loc, IVirtualMachine vm, CheckerInformation info, bool hasToBeLValue = true) { throw new IVirtualMachine.InternalError("Expression is no LValue"); }
public abstract Type GetExpressionType(CheckerInformation info);