public static ExpBase CreateExpression(CodeElement elem, Scope scope) { if (elem == null) { throw new Exception("Missing expression element"); } // First non operator values switch (elem.Name) { case WordInt: return(new ExpInt(elem)); case WordString: return(new ExpString(elem)); case WordReal: return(new ExpFloat(elem)); case WordBool: return(new ExpBool(elem)); case WordExp: return(CreateExpression(elem.Codes().FirstOrDefault(), scope)); case WordPar: return(CreateExpression(elem.Codes().FirstOrDefault(), scope)); case "identifier": return(CreateExpVariable(elem, scope)); case WordFuncCall: return(CreateExpFuncCall(elem, scope)); } // Then binary operator values. All binary operators has two operants. CodeElement first = elem.Codes().FirstOrDefault(); CodeElement next = elem.Codes().FirstOrDefault(c => c != first); ExpBase op1 = CreateExpression(first, scope); ExpBase op2 = CreateExpression(next, scope); // For multiplication, division, subtraction, greaterThan and lowerThan the operants must be numbers. if (elem.Name == WordMul || elem.Name == WordDiv || elem.Name == WordSub || elem.Name == WordGt || elem.Name == WordLt) { // check type if (!ExpBase.IsNumber(op1)) { throw new Exception(string.Format("The left operant of '{0}', {1}, is not a number", elem.Name, elem.GetLineAndColumn())); } if (!ExpBase.IsNumber(op2)) { throw new Exception(string.Format("The right operant of '{0}', {1}, is not a number", elem.Name, elem.GetLineAndColumn())); } } // For 'equals' the operants must both be numbers or both be strings. if (elem.Name == WordEq) { if (!(ExpBase.IsNumber(op1, op2) || ExpBase.IsString(op1, op2))) { throw new Exception(string.Format("Operants must both be numbers or both be strings: '{0}', {1}", elem.Name, elem.GetLineAndColumn())); } } switch (elem.Name) { case WordGt: return(new ExpGt(op1, op2)); case WordLt: return(new ExpLt(op1, op2)); case WordEq: return(new ExpEquals(op1, op2)); case WordDiv: return(new ExpDivide(op1, op2)); case WordMul: if (ExpBase.IsInt(op1, op2)) { return(new ExpMultiplyInt(op1, op2)); } else { return(new ExpMultiplyFloat(op1, op2)); } case WordSub: if (ExpBase.IsInt(op1, op2)) { return(new ExpMinusInt(op1, op2)); } else { return(new ExpMinusFloat(op1, op2)); } case WordSum: if (ExpBase.IsInt(op1, op2)) { return(new ExpSumInt(op1, op2)); } else if (ExpBase.IsNumber(op1, op2)) { return(new ExpSumFloat(op1, op2)); } else { return(new ExpSumString(op1, op2)); } default: throw new Exception(string.Format("Unknown expression element: '{0}'", elem.Name)); } }
public void BuildVariable(DefType theType, string name, CodeElement elem) { if (Vars.ContainsKey(name)) { throw new Exception(string.Format("A variable called '{0}', {1}, is allready declared", name, elem.GetLineAndColumn())); } ValueBase variable = ValueBase.Compile(theType, this, null); Vars.Add(name, variable); }
public DefType ExistsVariable(string name, CodeElement elem) { if (Vars.ExistsVariable(name)) { return(Vars.GetVariable(name).ResultType); } else if (ParentScope != null) { return(ParentScope.ExistsVariable(name, elem)); } else { throw new Exception(string.Format("A variable called '{0}', {1}, does not exists", name, elem.GetLineAndColumn())); } }
public static FuncCall CreateFuncCall(CodeElement elem, Scope scope) { // funcCall = identifier '(' [exp {',' exp}] ')'; CodeElement idElem = elem.Codes("identifier").First(); string name = idElem.Value; Function theFunc = scope.GetFunction(name); var parameters = new List <ExpBase>(); int i = -1; foreach (CodeElement item in elem.Codes().Where(e => e != idElem)) { var parm = CreateExpression(item, scope); if (++i == theFunc.Parameters.Count) { throw new Exception(string.Format("Too many parameters for function '{0}', {1}", name, item.GetLineAndColumn())); } if (theFunc.Parameters[i].TheType == DefType.Int && !ExpBase.IsInt(parm)) { throw new Exception(string.Format("The parameter for function '{0}' must be an integer, {1}", name, item.GetLineAndColumn())); } if (theFunc.Parameters[i].TheType == DefType.Bool && !ExpBase.IsBool(parm)) { throw new Exception(string.Format("The parameter for function '{0}' must be a boolean, {1}", name, item.GetLineAndColumn())); } if (theFunc.Parameters[i].TheType == DefType.Bool && !ExpBase.IsNumber(parm)) { throw new Exception(string.Format("The parameter for function '{0}' must be a number, {1}", name, item.GetLineAndColumn())); } parameters.Add(parm); } if (i + 1 != theFunc.Parameters.Count) { throw new Exception(string.Format("Too few parameters for function '{0}', {1}", name, elem.GetLineAndColumn())); } var call = new FuncCall(theFunc, parameters); return(call); }
public static Declare CreateDeclare(CodeElement elem, bool isVariable) { CodeElement defType = elem.Codes().FirstOrDefault(); CodeElement identifier = elem.Codes("identifier").FirstOrDefault(); Declare dec = new Declare() { TheName = identifier.Value }; switch (defType.Name) { case WordTypeInt: dec.TheType = DefType.Int; break; case WordTypeStr: dec.TheType = DefType.String; break; case WordTypeReal: dec.TheType = DefType.Float; break; case WordTypeBool: dec.TheType = DefType.Bool; break; case WordTypeVoid: if (isVariable) { throw new Exception(string.Format("Only functions can be 'void'. {0}", defType.GetLineAndColumn())); } dec.TheType = DefType.Void; break; default: throw new Exception(string.Format("The type '{0}' is not defined. {1}", defType.Value, defType.GetLineAndColumn())); } return(dec); }
public static void CreateFunctionDef(CodeElement elem, Scope scope) { // functionDef = typeAndId '(' [typeAndId {',' typeAndId}] ')' '{' scope '}'; CodeElement defElem = elem.Codes(WordDeclare).First(); var def2 = CreateDeclare(defElem, false); Function funcDef = new Function() { FuncType = def2.TheType, Name = def2.TheName }; if (scope.Functions.ContainsKey(funcDef.Name)) { throw new Exception(string.Format("A function called '{0}', {1}, is allready declared", funcDef.Name, elem.GetLineAndColumn())); } funcDef.Parameters = new List <Declare>(); foreach (CodeElement item in elem.Codes(WordDeclare).Where(e => e != defElem)) { var parm = CreateDeclare(item, true); funcDef.Parameters.Add(parm); } scope.Functions.Add(funcDef.Name, funcDef); }
public static Return CreateReturn(CodeElement elem, Scope scope, DefType resultType) { // return = 'return' [exp] ';'; var cmd = new Return(); CodeElement expCode = elem.Codes().FirstOrDefault(); if (expCode != null) { cmd.Expression = ExpressionBuilder.CreateExpression(expCode, scope); if (resultType == DefType.Bool && !ExpBase.IsBool(cmd.Expression)) { throw new Exception(string.Format("The expression must be a bool'. {0}", expCode.GetLineAndColumn())); } if (resultType == DefType.Int && !ExpBase.IsInt(cmd.Expression)) { throw new Exception(string.Format("The expression must be an integer'. {0}", expCode.GetLineAndColumn())); } if (resultType == DefType.Float && !ExpBase.IsNumber(cmd.Expression)) { throw new Exception(string.Format("The expression must be a number'. {0}", expCode.GetLineAndColumn())); } } else if (resultType != DefType.Void) { throw new Exception(string.Format("This function must return a value. {0}", elem.GetLineAndColumn())); } return(cmd); }
public static While CreateWhile(CodeElement elem, Scope scope, DefType resultType) { // loop = 'while' '(' exp ')' body; ExpBase expbase = ExpressionBuilder.CreateExpression(elem.Codes().First(), scope); var cmd = new While(); cmd.Expression = expbase as ExpTyped <bool>; if (cmd.Expression == null) { throw new Exception(string.Format("The expression type must be a boolean, {0}", elem.GetLineAndColumn())); } cmd.Body = CreateBody(elem.Codes(WordBody).First(), scope, resultType, out bool ret); return(cmd); }
public static If CreateIf(CodeElement elem, Scope scope, DefType resultType, out bool alwaysReturnValue) { // if = 'if' '(' exp ')' body ['else' body]; ExpBase expbase = ExpressionBuilder.CreateExpression(elem.Codes().First(), scope); var cmd = new If(); cmd.Expression = expbase as ExpTyped <bool>; if (cmd.Expression == null) { throw new Exception(string.Format("The expression type must be a boolean, {0}", elem.GetLineAndColumn())); } bool trueReturn; cmd.TrueStatement = CreateBody(elem.Codes(WordBody).First(), scope, resultType, out trueReturn); bool elseReturn; cmd.ElseStatement = CreateBody(elem.Codes(WordBody).Last(), scope, resultType, out elseReturn); alwaysReturnValue = trueReturn && elseReturn; return(cmd); }
public static Assign CreateAssign(CodeElement elem, Scope scope) { // assign = identifier '=' exp ';'; var cmd = new Assign(); CodeElement idElem = elem.Codes(WordIdentifier).First(); cmd.VariableName = idElem.Value; cmd.VariableType = scope.ExistsVariable(cmd.VariableName, idElem); CodeElement expCode = elem.Codes().Last(); cmd.Expression = ExpressionBuilder.CreateExpression(expCode, scope); if (cmd.VariableType == DefType.Bool && !ExpBase.IsBool(cmd.Expression)) { throw new Exception(string.Format("The expression must be a bool'. {0}", expCode.GetLineAndColumn())); } if (cmd.VariableType == DefType.Int && !ExpBase.IsInt(cmd.Expression)) { throw new Exception(string.Format("The expression must be an integer'. {0}", expCode.GetLineAndColumn())); } if (cmd.VariableType == DefType.Float && !ExpBase.IsNumber(cmd.Expression)) { throw new Exception(string.Format("The expression must be a number'. {0}", expCode.GetLineAndColumn())); } return(cmd); }
public static VariableDef CreateVariableDef(CodeElement elem, Scope scope) { // variableDef = typeAndId '=' exp ';'; var def = CreateDeclare(elem.Codes(WordDeclare).First(), true); var cmd = new VariableDef() { Name = def.TheName, VariableType = def.TheType }; if (elem.Codes().Count() == 2) { CodeElement expCode = elem.Codes().Last(); cmd.Expression = ExpressionBuilder.CreateExpression(expCode, scope); if (cmd.VariableType == DefType.Bool && !ExpBase.IsBool(cmd.Expression)) { throw new Exception(string.Format("The expression must be a bool'. {0}", expCode.GetLineAndColumn())); } if (cmd.VariableType == DefType.Int && !ExpBase.IsInt(cmd.Expression)) { throw new Exception(string.Format("The expression must be an integer'. {0}", expCode.GetLineAndColumn())); } if (cmd.VariableType == DefType.Float && !ExpBase.IsNumber(cmd.Expression)) { throw new Exception(string.Format("The expression must be a number'. {0}", expCode.GetLineAndColumn())); } } if (scope.ExistsFunction(cmd.Name)) { throw new Exception(string.Format("A Function called '{0}', {1}, is declared", cmd.Name, elem.GetLineAndColumn())); } scope.Vars.BuildVariable(cmd.VariableType, cmd.Name, elem); return(cmd); }
public static OperationBase CreateVariableOrOperation(CodeElement elem, Scope scope, DefType resultType, out bool alwaysReturnValue) { alwaysReturnValue = false; OperationBase stm; switch (elem.Name) { case WordVariableDef: stm = CreateVariableDef(elem, scope); break; case WordAssign: stm = CreateAssign(elem, scope); break; case WordIf: stm = CreateIf(elem, scope, resultType, out alwaysReturnValue); break; case WordWhile: case WordLoop: stm = CreateWhile(elem, scope, resultType); break; case WordFuncCall: stm = CreateOperationFuncCall(elem, scope); break; case WordReturn: stm = CreateReturn(elem, scope, resultType); alwaysReturnValue = true; break; default: throw new Exception(string.Format("The operation type '{0}' is not allowed, {1}", elem.Name, elem.GetLineAndColumn())); } return(stm); }
public static void CreateFunctionInnerScope(CodeElement elem, Scope scope) { // functionDef = typeAndId '(' [typeAndId {',' typeAndId}] ')' '{' scope '}'; CodeElement defElem = elem.Codes(WordDeclare).First(); var def2 = CreateDeclare(defElem, false); Function funcDef; scope.Functions.TryGetValue(def2.TheName, out funcDef); Variables innerVariables = new Variables(null, null); foreach (CodeElement item in elem.Codes(WordDeclare).Where(e => e != defElem)) { var parm = CreateDeclare(item, true); innerVariables.BuildVariable(parm.TheType, parm.TheName, item); } CodeElement scopeElem = elem.Codes(WordScope).First(); bool alwaysReturns; funcDef.FunctionScope = CreateScope(scopeElem, innerVariables, scope, funcDef.FuncType, out alwaysReturns); if (funcDef.FuncType != DefType.Void && !alwaysReturns) { throw new Exception(string.Format("The function '{0}' must return a value, {1}", funcDef.Name, elem.GetLineAndColumn())); } }