public override void OutALocalLvalue(ALocalLvalue node) { if (folding) { AALocalDecl local = data.LocalLinks[node]; if (local.GetConst() == null) { if (!isANewExp) { errors.Add( new ErrorCollection.Error(node.GetName(), LocRM.GetString("ErrorText61"), false), true); throw new ParserException(null, null); } } if (local.GetInit() == null)//An error will be given earlier throw new ParserException(null, null); local.GetInit().Apply(this); } }
public override void OutALocalLvalue(ALocalLvalue node) { node.GetName().Text = finalTrans.data.LocalLinks[node].GetName().Text; }
public override void CaseALocalLvalue(ALocalLvalue node) { InALocalLvalue(node); if (node.GetName() != null) { node.GetName().Apply(this); } OutALocalLvalue(node); }
public override void OutALocalLvalue(ALocalLvalue node) { AALocalDecl decl = data.LocalLinks[node]; PType type = data.LvalueTypes[node] = decl.GetType(); if (decl.GetOut() != null && !Util.IsBulkCopy(type) && !assignedToOutParams.Contains(decl) && !(node.Parent() is AAssignmentExp && node == ((AAssignmentExp)node.Parent()).GetLvalue())) { errors.Add(new ErrorCollection.Error(node.GetName(), currentSourceFile, LocRM.GetString("ErrorText97") + node.GetName().Text + LocRM.GetString("ErrorText98"))); } }
public override void CaseALocalLvalue(ALocalLvalue node) { if (setUses) { PStm parentStm = Util.GetAncestor<PStm>(node); AALocalDecl decl = finalTrans.data.LocalLinks[node]; AAssignmentExp assignment = Util.GetAncestor<AAssignmentExp>(node); bool isUsage = true; if (assignment != null) { if (Util.IsAncestor(node, assignment.GetLvalue())) { AArrayLvalue arrayLvalue = Util.GetAncestor<AArrayLvalue>(node); isUsage = false; while (arrayLvalue != null) { if (Util.IsAncestor(node, arrayLvalue.GetIndex())) { isUsage = true; break; } arrayLvalue = Util.GetAncestor<AArrayLvalue>(arrayLvalue.Parent()); } if (!isUsage) { //If we have a bulk copy here, it is really only a partial assignment, and so we should not add it as an assignment if (!Util.IsBulkCopy(decl.GetType())) assigns[parentStm] = finalTrans.data.LocalLinks[node]; } } } if (isUsage) { if (!uses[parentStm].Contains(decl)) uses[parentStm].Add(decl); } } if (fixRefferences) { AALocalDecl decl = finalTrans.data.LocalLinks[node]; while (renamedLocals.ContainsKey(decl)) { decl = renamedLocals[decl]; } finalTrans.data.LocalLinks[node] = decl; node.GetName().Text = decl.GetName().Text; } base.CaseALocalLvalue(node); }
public override void CaseAMethodDecl(AMethodDecl node) { if (firstMethodCall) StatementRemover.Parse(node); firstMethodCall = false; before.Clear(); after.Clear(); uses.Clear(); intersectingLocals.Clear(); definedLocals.Clear(); renamedLocals.Clear(); assigns.Clear(); changes = false; //Make uses setUses = true; base.CaseAMethodDecl(node); setUses = false; //Build a list of what's visible do { changes = false; base.CaseAMethodDecl(node); } while (changes); setSpans = true; base.CaseAMethodDecl(node); setSpans = false; //Join locals of same type, unless they are both parameters or they are listed as intersecting for (int i = 0; i < definedLocals.Count; i++) { for (int j = i + 1; j < definedLocals.Count; j++) { AALocalDecl decl1 = definedLocals[i]; AALocalDecl decl2 = definedLocals[j]; if (Util.TypeToString(decl1.GetType()) == Util.TypeToString(decl2.GetType()) && !intersectingLocals.Contains(new Pair(decl1, decl2))) { if (Util.GetAncestor<AABlock>(decl1) == null && Util.GetAncestor<AABlock>(decl2) == null) continue; AALocalDecl replacement = decl1; AALocalDecl replaced = decl2; //Dont replace the parameter if (Util.GetAncestor<AABlock>(replaced) == null) { replacement = decl2; replaced = decl1; i--; } j--; renamedLocals.Add(replaced, replacement); definedLocals.Remove(replaced); foreach (Pair pair in intersectingLocals) { if (pair.Local1 == replaced) pair.Local1 = replacement; if (pair.Local2 == replaced) pair.Local2 = replacement; } //Assign defaults if (replaced.GetInit() == null) { ALocalLvalue lvalue = new ALocalLvalue(new TIdentifier(replaced.GetName().Text)); finalTrans.data.LocalLinks[lvalue] = replaced; finalTrans.data.LvalueTypes[lvalue] = replaced.GetType(); List<PStm> statements = AssignDefault(lvalue); PStm pStm = Util.GetAncestor<PStm>(replaced); AABlock pBlock = (AABlock) pStm.Parent(); foreach (PStm statement in statements) { pBlock.GetStatements().Insert(pBlock.GetStatements().IndexOf(pStm), statement); } pBlock.RemoveChild(pStm); } else { //Make an assignment expression instead ALocalDeclStm declStm = (ALocalDeclStm)replaced.Parent(); ALocalLvalue lvalue = new ALocalLvalue((TIdentifier)replaced.GetName().Clone()); finalTrans.data.LvalueTypes[lvalue] = replaced.GetType(); AAssignmentExp exp = new AAssignmentExp(new TAssign("=", lvalue.GetName().Line, lvalue.GetName().Pos), lvalue, replaced.GetInit()); AExpStm expStm = new AExpStm(declStm.GetToken(), exp); declStm.ReplaceBy(expStm); finalTrans.data.LvalueTypes[lvalue] = replacement.GetType(); finalTrans.data.ExpTypes[exp] = replacement.GetType(); finalTrans.data.LocalLinks[lvalue] = replacement; } } } } //Unique names List<string> names = new List<string>(); //Avoid clash with methods/fields/structs names.AddRange(finalTrans.data.Methods.Select(declItem => declItem.Decl.GetName().Text)); names.AddRange(finalTrans.data.Fields.Select(declItem => declItem.Decl.GetName().Text)); names.AddRange(finalTrans.data.Structs.Select(declItem => declItem.Decl.GetName().Text)); foreach (AALocalDecl local in definedLocals) { string name = local.GetName().Text; int version = 1; while (names.Contains(name)) { version++; name = local.GetName().Text + version; } local.GetName().Text = name; names.Add(name); } //Move defined locals to the start of the method foreach (AALocalDecl formal in node.GetFormals()) { definedLocals.Remove(formal); } AABlock block = (AABlock)node.GetBlock(); for (int i = 0; i < block.GetStatements().Count; i++) { ALocalDeclStm stm; if (block.GetStatements()[i] is ALocalDeclStm) { stm = (ALocalDeclStm)block.GetStatements()[i]; definedLocals.Remove((AALocalDecl)stm.GetLocalDecl()); continue; } //Add the rest at i if (definedLocals.Count == 0) break; AALocalDecl decl = definedLocals[0]; definedLocals.RemoveAt(0); if (decl.GetInit() == null) { ALocalLvalue lvalue = new ALocalLvalue(new TIdentifier(decl.GetName().Text)); finalTrans.data.LocalLinks[lvalue] = decl; finalTrans.data.LvalueTypes[lvalue] = decl.GetType(); List<PStm> statements = AssignDefault(lvalue); PStm pStm = Util.GetAncestor<PStm>(decl); AABlock pBlock = (AABlock) pStm.Parent(); foreach (PStm statement in statements) { pBlock.GetStatements().Insert(pBlock.GetStatements().IndexOf(pStm), statement); } pBlock.RemoveChild(pStm); } else { //Make an assignment expression before moving stm = (ALocalDeclStm)decl.Parent(); ALocalLvalue lvalue = new ALocalLvalue(new TIdentifier(decl.GetName().Text)); finalTrans.data.LvalueTypes[lvalue] = decl.GetType(); AAssignmentExp exp = new AAssignmentExp(new TAssign("="), lvalue, decl.GetInit()); AExpStm expStm = new AExpStm(new TSemicolon(";"), exp); stm.ReplaceBy(expStm); finalTrans.data.LvalueTypes[lvalue] = decl.GetType(); finalTrans.data.ExpTypes[exp] = decl.GetType(); finalTrans.data.LocalLinks[lvalue] = decl; } stm = new ALocalDeclStm(new TSemicolon(";"), decl); block.GetStatements().Insert(i, stm); } fixRefferences = true; base.CaseAMethodDecl(node); fixRefferences = false; //If we have an assignment to a local where the stored result is never used, remove the assignment //Since we changed some statements, rebuild stuff before.Clear(); after.Clear(); uses.Clear(); intersectingLocals.Clear(); definedLocals.Clear(); renamedLocals.Clear(); assigns.Clear(); changes = false; //Make uses setUses = true; base.CaseAMethodDecl(node); setUses = false; //Build a list of what's visible do { changes = false; base.CaseAMethodDecl(node); } while (changes); PStm[] stms = new PStm[before.Keys.Count]; before.Keys.CopyTo(stms, 0); foreach (PStm stm in stms) { if (assigns[stm] != null && //Assignment exp !after[stm].Contains(assigns[stm]) && //Assignment unused Util.GetAncestor<AMethodDecl>(assigns[stm]) != null && !(stm is ALocalDeclStm))//It is to a local { stm.Apply(new MoveMethodDeclsOut(finalTrans.data)); stm.Parent().RemoveChild(stm); } } //Remove foo = foo; RemoveStupidAssignments assignmentRemover = new RemoveStupidAssignments(finalTrans.data); node.Apply(assignmentRemover); //Remove unused local variables foreach (AALocalDecl local in definedLocals) { if (Util.GetAncestor<AAProgram>(local) != null && Util.GetAncestor<AABlock>(local) != null && !finalTrans.data.LocalLinks.Where(p => p.Value == local).Any(p => Util.GetAncestor<AAProgram>(p.Key) != null)) local.Parent().Parent().RemoveChild(local.Parent()); } if (assignmentRemover.RemovedOne) { CaseAMethodDecl(node); return; } //If an assignment to a variable is completely local, and that assignment is only used once, put the assignment where it is used //Since we changed some statements, rebuild stuff before.Clear(); after.Clear(); uses.Clear(); intersectingLocals.Clear(); definedLocals.Clear(); renamedLocals.Clear(); assigns.Clear(); changes = false; //Make uses setUses = true; base.CaseAMethodDecl(node); setUses = false; //Build a list of what's visible do { changes = false; base.CaseAMethodDecl(node); } while (changes); foreach (KeyValuePair<PStm, AALocalDecl> pair in assigns) { PStm assignStm = pair.Key; AALocalDecl assignVar = pair.Value; bool isLocal = Util.IsLocal(assignStm, finalTrans.data); bool containsInvokeInPrevStm = false; if (assignVar != null && after[assignStm].Contains(assignVar)) { bool dontMove = false; //First, if there are any conditional parrent statement, where the variable is in live before the stm, then we can't move it PStm condParent = (PStm) Util.GetNearestAncestor(assignStm, typeof (AIfThenStm), typeof (AIfThenElseStm), typeof (AWhileStm)); while (condParent != null) { if (before[condParent].Contains(assignVar)) { dontMove = true; break; } condParent = (PStm)Util.GetNearestAncestor(condParent.Parent(), typeof(AIfThenStm), typeof(AIfThenElseStm), typeof(AWhileStm)); } PStm useStm = null; List<PStm> successors = GetSuccessor(assignStm); bool containsConditionalAssignments = false; while (successors.Count > 0) { if (successors.Count > 500) useStm = useStm; PStm successor = successors[0]; successors.RemoveAt(0); if (uses[successor].Contains(assignVar)) { if (useStm == null && !containsConditionalAssignments && !(successor is AWhileStm)) useStm = successor; else { dontMove = true; break; } } if (after[successor].Contains(assignVar) && !(assigns.ContainsKey(successor) && assigns[successor] == assignVar)) { List<PStm> newSuccessors = GetSuccessor(successor); foreach (PStm stm in newSuccessors) { if (!successors.Contains(stm)) successors.Add(stm); } } if (assigns.ContainsKey(successor) && uses[assignStm].Contains(assigns[successor])) { dontMove = true; break; } if (assigns.ContainsKey(successor) && assigns[successor] == assignVar) { condParent = (PStm)Util.GetNearestAncestor(successor, typeof(AIfThenStm), typeof(AIfThenElseStm), typeof(AWhileStm)); while (condParent != null) { if (!Util.IsAncestor(assignStm, condParent)) { containsConditionalAssignments = true; break; } condParent = (PStm)Util.GetNearestAncestor(condParent.Parent(), typeof(AIfThenStm), typeof(AIfThenElseStm), typeof(AWhileStm)); } //If we found a usage, and it is inside a while that the assignStm is not inside, but we are inside, don't move if (useStm != null) { AWhileStm whileParant = Util.GetAncestor<AWhileStm>(successor); while (whileParant != null) { if (Util.IsAncestor(useStm, whileParant) && !Util.IsAncestor(assignStm, whileParant)) { dontMove = true; break; } whileParant = Util.GetAncestor<AWhileStm>(whileParant.Parent()); } } } FindInvoke finder = new FindInvoke(); successor.Apply(finder); if (finder.ContainsInvoke && useStm == null) containsInvokeInPrevStm = true; } if (useStm != null && !dontMove) { //If assignStm is inside an if, and the use stm is not, and there is another assignment //to the same variable in an else block, then don't join AIfThenElseStm ifThenElse = Util.GetAncestor<AIfThenElseStm>(assignStm); while (ifThenElse != null) { if (!Util.IsAncestor(useStm, ifThenElse)) { ABlockStm otherBlock; if (Util.IsAncestor(assignStm, ifThenElse.GetThenBody())) otherBlock = (ABlockStm) ifThenElse.GetElseBody(); else otherBlock = (ABlockStm)ifThenElse.GetThenBody(); StmEnum enumerator = new StmEnum(otherBlock); while (enumerator.MoveNext()) { PStm stm = (PStm) enumerator.Current; if (assigns.ContainsKey(stm) && assigns[stm] == assignVar) { dontMove = true; break; } } if (dontMove) break; } ifThenElse = Util.GetAncestor<AIfThenElseStm>(ifThenElse.Parent()); } //If the assignStm or useStm is inside a while, it could get complicated //if (Util.HasAncestor<AWhileStm>(assignStm) || Util.HasAncestor<AWhileStm>(useStm)) // dontMove = true; } if (useStm != null && dontMove == false && (isLocal || !containsInvokeInPrevStm)) { //Ensure that it is not used twice in this stm FindLvalue finder = new FindLvalue(assignVar, finalTrans.data); useStm.Apply(finder); if (!finder.IsUsedTwice && (isLocal || !finder.HasPrevInvoke)) { PExp rightside; if (assignStm is ALocalDeclStm) { rightside = ((AALocalDecl)((ALocalDeclStm)assignStm).GetLocalDecl()).GetInit(); } else { rightside = ((AAssignmentExp)((AExpStm)assignStm).GetExp()).GetExp(); assignStm.Parent().RemoveChild(assignStm); } if (rightside != null) { finder.Lvalue.Parent().ReplaceBy(rightside); CaseAMethodDecl(node); return; } } } } } if (StatementRemover.Parse(node)) { CaseAMethodDecl(node); return; } firstMethodCall = true; }