private AstItem ReadExternFuncDecl(TokenIterator tokens) { tokens.PopExpected(TokenKind.Ext); tokens.PopExpected(TokenKind.RoundBracketOpen); var libFnName = tokens.PopExpected(TokenKind.String); tokens.PopExpected(TokenKind.Comma); var libName = tokens.PopExpected(TokenKind.String); tokens.PopExpected(TokenKind.RoundBracketClose); var name = tokens.PopExpected(TokenKind.Word); tokens.PopExpected(TokenKind.RoundBracketOpen); var parameters = ReadFuncParameters(tokens); var next = tokens.Pop(); DataType returnType = DataType.VOID; if (next.Kind == TokenKind.TypeOperator) { returnType = ReadDataType(tokens); tokens.PopExpected(TokenKind.SemiColon); } return(AstItem.ExternFunctionDecl(name.Value, returnType, parameters, libFnName.Value, libName.Value)); }
private AstItem ReadVector(TokenIterator tokens) { var name = tokens.Pop(); var bracket = tokens.Pop(); if (bracket.Kind != TokenKind.RoundBracketOpen) { throw new Exception("Unexcepted token after vector name! Expected '(', found: " + bracket); } var vectorValues = new List <List <Token> >(); var valueTokens = new List <Token>(); var bracketCounter = 0; var token = tokens.Pop(); while (token != null) { if (token.Kind == TokenKind.RoundBracketOpen) { bracketCounter += 1; valueTokens.Add(token); } else if (token.Kind == TokenKind.RoundBracketClose) { if (bracketCounter <= 0) { vectorValues.Add(valueTokens); break; } else { bracketCounter -= 1; valueTokens.Add(token); } } else if (token.Kind == TokenKind.Comma) { vectorValues.Add(valueTokens); valueTokens = new List <Token>(); } else { valueTokens.Add(token); } token = tokens.Pop(); } var paramExpressions = new List <AstItem>(vectorValues.Count); foreach (var values in vectorValues) { var expression = ReadExpression(new TokenIterator(values), null); paramExpressions.Add(expression); } //Need to pass the name so SemanticAnalysis knows if "vec" or (i.e.) "vec4f" was used return(AstItem.Vector(name.Value, paramExpressions)); }
public void ValidateOperand(AstItem operand) { if (operand.DataType.Kind != DataTypeKind.POINTER) { throw new Exception("Can only dereference pointers with '*', given: " + operand.DataType); } }
private AstItem ReadForLoop(TokenIterator tokens) { //for i in 0..5 [inc 1] {...} tokens.PopExpected(TokenKind.For); var varName = tokens.PopExpected(TokenKind.Word); tokens.PopExpected(TokenKind.In); var startExpression = ReadExpression(tokens, TokenKind.To); tokens.PopExpected(TokenKind.To); var endExpression = ReadExpression(tokens, new List <TokenKind>() { TokenKind.CurlyBracketOpen, TokenKind.Inc }); var next = tokens.Pop(); AstItem incExpression = AstItem.Immediate("1"); if (next.Kind == TokenKind.Inc) { incExpression = ReadExpression(tokens, TokenKind.CurlyBracketOpen); tokens.PopExpected(TokenKind.CurlyBracketOpen); } else { Assert.True(next.Kind == TokenKind.CurlyBracketOpen, "Expected 'inc' or '{', got: " + next); } var statements = ReadStatements(tokens); tokens.PopExpected(TokenKind.CurlyBracketClose); return(AstItem.ForLoop(varName.Value, startExpression, endExpression, incExpression, statements)); }
public void ValidateOperand(AstItem operand) { if (operand.DataType != DataType.BOOL) { throw new Exception("! operator can only be applied to bool, got: " + operand.DataType); } }
private AstItem ReadNewPointer(TokenIterator tokens) { tokens.PopExpected(TokenKind.New); var token = tokens.Current(); if (token.Kind == TokenKind.SquareBracketOpen) { return(AstItem.NewHeapArray(ReadArray(tokens))); } else { var subType = ReadDataType(tokens); var dataType = DataType.Pointer(subType); var amountExpression = AstItem.Immediate("1"); var current = tokens.Current(); if (current != null && current.Kind == TokenKind.RoundBracketOpen) { tokens.Pop(); amountExpression = ReadExpression(tokens, TokenKind.RoundBracketClose); tokens.PopExpected(TokenKind.RoundBracketClose); } return(AstItem.NewRawPointer(dataType, amountExpression)); } }
private List <AstItem> ReadFuncParameters(TokenIterator tokens) { var result = new List <AstItem>(); var current = tokens.Pop(); while (current.Kind != TokenKind.RoundBracketClose) { var name = current; if (name.Kind != TokenKind.Word) { throw new Exception("Expected parameter name, found " + name); } tokens.PopExpected(TokenKind.TypeOperator); var dataType = ReadDataType(tokens); result.Add(AstItem.Parameter(name.Value, dataType)); current = tokens.Pop(); if (current.Kind == TokenKind.Comma) { current = tokens.Pop(); } } return(result); }
private AstItem ReadDelStatement(TokenIterator tokens) { tokens.PopExpected(TokenKind.Del); var varName = tokens.PopExpected(TokenKind.Word); return(AstItem.DelPointer(varName.Value)); }
public void Analyze(CompilerContext context) { var tokens = new TokenIterator(context.Tokens); var result = AstItem.Programm(); result.Children = Read(tokens); context.AST = result; }
public DataType GetReturnType(AstItem operand) { if (operand.DataType.Kind == DataTypeKind.ARRAY || operand.DataType.Kind == DataTypeKind.STRING8) { return(DataType.Pointer(operand.DataType.ElementType)); } return(DataType.Pointer(operand.DataType)); }
public void ValidateOperand(AstItem operand) { var operandType = operand.DataType; if ((operandType.Group == DataTypeGroup.ScalarInteger && !operandType.IsSigned) && operandType.Group != DataTypeGroup.ScalarFloat && operandType.Group != DataTypeGroup.VectorFloat) { throw new Exception("Unsupported data type for arithmetic negation operator: " + operandType); } }
public void ValidateOperands(AstItem operand1, AstItem operand2) { //Do not check kind of operand1, just trust it is okay. It can be all kinds of expression items Assert.AstItemKind(operand2.Kind, AstItemKind.Type, "Invalid second operand for 'as' operator"); var typeCast = TypeCast.GetFrom(operand1.DataType.Kind); Assert.True(typeCast != null, "Invalid type cast from " + operand1.DataType + " to " + operand2.DataType); Assert.True(typeCast.CanCastTo(operand2.DataType.Kind), "Invalid type cast from " + operand1.DataType + " to " + operand2.DataType); }
private AstItem ReadWhileLoop(TokenIterator tokens) { //while a > 5 {...} tokens.PopExpected(TokenKind.While); var whileExpression = ReadExpression(tokens, TokenKind.CurlyBracketOpen); tokens.PopExpected(TokenKind.CurlyBracketOpen); var statements = ReadStatements(tokens); tokens.PopExpected(TokenKind.CurlyBracketClose); return(AstItem.WhileLoop(whileExpression, statements)); }
private AstItem ReadIndexAccess(TokenIterator tokenIter) { var symbol = tokenIter.PopExpected(TokenKind.Word); tokenIter.PopExpected(TokenKind.SquareBracketOpen); var valueExpression = ReadExpression(tokenIter, TokenKind.SquareBracketClose); tokenIter.PopExpected(TokenKind.SquareBracketClose); return(AstItem.IndexAccess(symbol.Value, valueExpression)); }
private AstItem ReadVariableAssignment(TokenIterator tokens) { var name = tokens.PopExpected(TokenKind.Word); tokens.PopExpected(TokenKind.AssigmnentOperator); var expression = ReadExpression(tokens, TokenKind.SemiColon); tokens.PopExpected(TokenKind.SemiColon); return(AstItem.VariableAssignment(name.Value, expression)); }
public void ValidateOperand(AstItem operand) { var dataType = operand.DataType; if (dataType.Kind == DataTypeKind.VOID || dataType.Kind == DataTypeKind.ENUM || dataType.Kind == DataTypeKind.VARS) { throw new Exception("Cannot create a reference with '&' to: " + dataType); } if (dataType.MemoryRegion == MemoryRegion.Stack) { throw new Exception("Cannot create reference with '&' to data on stack: " + operand); } }
public void ValidateOperands(AstItem operand1, AstItem operand2) { var operand1Type = operand1.DataType; var operand2Type = operand2.DataType; if (operand1Type.Kind != operand2Type.Kind) { throw new Exception("Data types of both operands must match for equality operator! " + operand1Type + " != " + operand2Type); } //Can compare all types! //if (!_supportedDataTypes.Contains(operand1Type)) // throw new Exception("Datatype not supported for equality operator: " + operand1Type); }
public void ValidateOperands(AstItem operand1, AstItem operand2) { var operand1Type = operand1.DataType; var operand2Type = operand2.DataType; if (operand1Type.Kind != operand2Type.Kind) { throw new Exception("Data types of both operands must match for boolean operator! " + operand1Type + " != " + operand2Type); } if (operand1Type.Kind != DataTypeKind.BOOL) { throw new Exception("Datatype not supported for boolean operator: " + operand1Type); } }
public void ValidateOperands(AstItem operand1, AstItem operand2) { var operand1Type = operand1.DataType; var operand2Type = operand2.DataType; if (operand1Type.Kind != operand2Type.Kind) { throw new Exception("Data types of both operands must match for relational operator '" + Figure + "'! " + operand1Type + " != " + operand2Type); } //Can only compare scalar values if (operand1Type.Group != DataTypeGroup.ScalarInteger && operand1Type.Group != DataTypeGroup.ScalarFloat) { throw new Exception("Datatype not supported for relational operator '" + Figure + "': " + operand1Type); } }
public void ValidateOperands(AstItem operand1, AstItem operand2) { if (operand1.Kind != AstItemKind.Type || operand2.Kind != AstItemKind.Identifier) { throw new Exception("Invalid combination of operands for static access member: " + operand1 + " and " + operand2 + "!"); } var enumType = operand1.DataType; Assert.True(enumType != null, "Enum type not found: " + operand1.Identifier); Assert.DataTypeKind(enumType.Kind, DataTypeKind.ENUM, "Invalid type for left side of :: operator"); var element = enumType.EnumElements.Find((e) => e.Name == operand2.Identifier); Assert.True(element != null, "Element '" + operand2.Identifier + "' not found in enum '" + operand1.Identifier + "'!"); }
private AstItem ReadEnumDecl(TokenIterator tokens) { //Skip "enum" tokens.Pop(); var enumName = tokens.PopExpected(TokenKind.Word).Value; tokens.PopExpected(TokenKind.CurlyBracketOpen); var currentIndex = 0; var elements = new List <AstItem>(); var current = tokens.Current(); while (current.Kind != TokenKind.CurlyBracketClose) { var elementName = tokens.PopExpected(TokenKind.Word).Value; var next = tokens.Pop(); switch (next.Kind) { case TokenKind.AssigmnentOperator: var indexStr = tokens.PopExpected(TokenKind.Number).Value; var index = int.Parse(indexStr); if (index < currentIndex) { throw new Exception("Invalid enum element index for " + enumName + "." + elementName + "! Must be >= " + currentIndex); } currentIndex = index; next = tokens.PopExpected(TokenKind.Comma, TokenKind.CurlyBracketClose); break; case TokenKind.Comma: case TokenKind.CurlyBracketClose: //Nothing to do here, but also no error break; default: throw new Exception("Unexpected token in enum declaration: " + next); } elements.Add(AstItem.EnumElement(elementName, currentIndex)); currentIndex += 1; current = next; } return(AstItem.EnumDecl(enumName, elements)); }
private AstItem ReadIndexerAssignment(TokenIterator tokens) { var name = tokens.PopExpected(TokenKind.Word); tokens.PopExpected(TokenKind.SquareBracketOpen); var indexExpression = ReadExpression(tokens, TokenKind.SquareBracketClose); tokens.PopExpected(TokenKind.SquareBracketClose); tokens.PopExpected(TokenKind.AssigmnentOperator); var valueExpression = ReadExpression(tokens, TokenKind.SemiColon); tokens.PopExpected(TokenKind.SemiColon); return(AstItem.PointerIndexAssignment(name.Value, indexExpression, valueExpression)); }
private AstItem ReadFuncCall(TokenIterator tokens) { var name = tokens.PopExpected(TokenKind.Word); tokens.PopExpected(TokenKind.RoundBracketOpen); var paramValues = ReadBreaketedList(tokens, TokenKind.RoundBracketOpen, TokenKind.RoundBracketClose, TokenKind.Comma); var paramExpressions = new List <AstItem>(paramValues.Count); foreach (var valueTokens in paramValues) { var expression = ReadExpression(new TokenIterator(valueTokens), null); paramExpressions.Add(expression); } return(AstItem.FunctionCall(name.Value, paramExpressions)); }
private AstItem ReadArray(TokenIterator tokens) { tokens.PopExpected(TokenKind.SquareBracketOpen); var firstValue = ReadExpression(tokens, new List <TokenKind> { TokenKind.SemiColon, TokenKind.Comma }); var token = tokens.Pop(); if (token.Kind == TokenKind.SquareBracketClose) { //Array with only single value return(AstItem.ValueArrayDefinition(new List <AstItem>() { firstValue })); } if (token.Kind == TokenKind.Comma) { //Array definition with n values var valueTokens = ReadBreaketedList(tokens, TokenKind.SquareBracketOpen, TokenKind.SquareBracketClose, TokenKind.Comma); var valueExpressions = new List <AstItem>(valueTokens.Count + 1) { firstValue }; foreach (var tokenList in valueTokens) { var iterator = new TokenIterator(tokenList); var valueItem = ReadExpression(iterator, null); valueExpressions.Add(valueItem); } return(AstItem.ValueArrayDefinition(valueExpressions)); } else if (token.Kind == TokenKind.SemiColon) { //Array definition with one value and number of items var numItemsExpression = ReadExpression(tokens, TokenKind.SquareBracketClose); return(AstItem.SizedArrayDefinition(firstValue, numItemsExpression)); } throw new Exception("Unexpected token in array definition: " + token); }
private void EvaluateConstantExpressions(AstItem item) { if (item.Kind == AstItemKind.Expression) { for (int i = 0; i < item.Children.Count; i++) { var child = item.Children[i]; if (child.Kind == AstItemKind.BinaryOperator && child.BinaryOperator.Figure == "::") { //Convert enum value access like "Enum::Value" to immediate values var typeItem = item.Children[i - 2]; Assert.AstItemKind(typeItem.Kind, AstItemKind.Type, "Invalid kind of first operand in expression"); var valueItem = item.Children[i - 1]; Assert.AstItemKind(valueItem.Kind, AstItemKind.Identifier, "Invalid kind of second operand in expression"); var element = typeItem.DataType.EnumElements.Find((e) => e.Name == valueItem.Identifier); Assert.True(element != null, "Enum element with name not found: " + valueItem.Identifier + " in enum: " + typeItem.Identifier); child.Kind = AstItemKind.Immediate; child.DataType = DataType.U32; child.Value = element.Index; child.Operator = null; item.Children.RemoveAt(i - 2); item.Children.RemoveAt(i - 2); i -= 2; } } } else { foreach (var child in item.Children) { if (child != null) { EvaluateConstantExpressions(child); } } } }
private AstItem ReadFuncDecl(TokenIterator tokens) { //Skip "fn" tokens.Pop(); var next = tokens.Current(); if (next.Kind == TokenKind.Ext) { return(ReadExternFuncDecl(tokens)); } var name = tokens.PopExpected(TokenKind.Word); tokens.PopExpected(TokenKind.RoundBracketOpen); var parameters = ReadFuncParameters(tokens); DataType returnType = DataType.VOID; next = tokens.Pop(); if (next.Kind == TokenKind.TypeOperator) { returnType = ReadDataType(tokens); next = tokens.Pop(); } if (next.Kind != TokenKind.CurlyBracketOpen) { throw new Exception("Expected ':' or '{', found " + next); } var statements = ReadStatements(tokens); tokens.PopExpected(TokenKind.CurlyBracketClose); return(AstItem.FunctionDecl(name.Value, returnType, parameters, statements)); }
private AstItem ReadIfStatement(TokenIterator tokens) { tokens.PopExpected(TokenKind.If); var expression = ReadExpression(tokens, TokenKind.CurlyBracketOpen); tokens.PopExpected(TokenKind.CurlyBracketOpen); var statements = ReadStatements(tokens); tokens.PopExpected(TokenKind.CurlyBracketClose); List <AstItem> elseStatements = null; var current = tokens.Current(); if (current.Kind == TokenKind.Else) { tokens.PopExpected(TokenKind.Else); tokens.PopExpected(TokenKind.CurlyBracketOpen); elseStatements = ReadStatements(tokens); tokens.PopExpected(TokenKind.CurlyBracketClose); } return(AstItem.IfStatement(expression, statements, elseStatements)); }
public void Optimize(AstItem programItem) { Assert.AstItemKind(programItem.Kind, AstItemKind.Programm, "Invalid AST item for optimization"); EvaluateConstantExpressions(programItem); }
public void ValidateOperands(AstItem operand1, AstItem operand2) { }
public DataType GetReturnType(AstItem operand1, AstItem operand2) { return(DataType.VOID); }