public static DataType Check(AstNode node, Context context) { switch (node.Type) { case CCompilerLexer.PROGRAM: { if (context == null) context = new Context(context); CheckBlock(node, context); return DataType.Void; } case CCompilerLexer.BLOCK: { context = new Context(context); CheckBlock(node, context); return DataType.Void; } case CCompilerLexer.VAR: { List<AstNode> nodes = new List<AstNode>(); DataType dataType = StrToDataType(node.GetChild(0).Text); for (int i = 0; i < node.GetChild(0).ChildCount; i++) { AstNode temp = (AstNode)node.GetChild(0).GetChild(i); if (temp.Token.Type == CCompilerLexer.ASSIGN) { Ident ident = context.InThisContext(temp.GetChild(0).Text); if (ident != null) throw new ApplicationException(string.Format("Identifier {0} already exists", temp.GetChild(0).Text)); AstNode var = new AstNode(new Antlr.Runtime.CommonToken(CCompilerLexer.VAR, "VAR")); var.AddChild(new AstNode(new Antlr.Runtime.CommonToken(CCompilerLexer.IDENT, DataTypeToStr(dataType)))); var.GetChild(0).AddChild(new AstNode(new Antlr.Runtime.CommonToken(CCompilerLexer.IDENT, temp.GetChild(0).Text))); nodes.Add(var); nodes.Add(temp); } else { Ident ident = context.InThisContext(temp.Text); if (ident != null) throw new IntepreterException(string.Format("Identifier {0} already exists", temp.Text)); AstNode var = new AstNode(new Antlr.Runtime.CommonToken(CCompilerLexer.VAR, "VAR")); var.AddChild(new AstNode(new Antlr.Runtime.CommonToken(CCompilerLexer.IDENT, DataTypeToStr(dataType)))); var.GetChild(0).AddChild(temp); nodes.Add(var); } string name = nodes[0].GetChild(0).GetChild(0).Text; context[name] = new Ident(name, context.ParentContext == null ? IdentType.GlobalVar : IdentType.LocalVar, dataType, nodes[0]); Antlr.Runtime.Tree.CommonTree tree = new Antlr.Runtime.Tree.CommonTree(); foreach (AstNode n in nodes) tree.AddChild(n); node.Parent.ReplaceChildren(node.ChildIndex, node.ChildIndex, tree); } return DataType.Void; } case CCompilerLexer.FUNC_DECL: { DataType dataType = StrToDataType(node.GetChild(0).Text); string name = node.GetChild(1).Text; Ident ident = context[name]; if (ident != null) throw new IntepreterException(string.Format("Identifier {0} already exists", name)); Ident func = new Ident(name, IdentType.Function, dataType, node); context[name] = func; context = new Context(context); AstNode _params = (AstNode)node.GetChild(2); for (int i = 0; i < _params.ChildCount; i++) { DataType paramDataType = StrToDataType(_params.GetChild(i).Text); string paramName = _params.GetChild(i).GetChild(0).Text; if (paramDataType == DataType.Void) throw new IntepreterException(string.Format("In function {0} void param {1}", name, paramName)); context[paramName] = new Ident(paramName, IdentType.Param, paramDataType, (AstNode)_params.GetChild(i)); } context.Function = func; Check((AstNode)node.GetChild(3), context); return DataType.Void; } case CCompilerLexer.CALL: { Ident ident = context[node.GetChild(0).Text]; if (ident == null) throw new IntepreterException(string.Format("Unknown identifier {0}", node.GetChild(0).Text)); if (ident.IdentType != IdentType.Function) throw new IntepreterException(string.Format("Identifier {0} is not function", node.GetChild(0).Text)); if (node.GetChild(1).ChildCount != ident.Node.GetChild(2).ChildCount) throw new IntepreterException(string.Format("Not equals params count in function {0}", node.GetChild(0).Text)); for (int i = 0; i < ident.Node.GetChild(2).ChildCount; i++) { DataType formalDataType = StrToDataType(ident.Node.GetChild(2).GetChild(i).Text); DataType factDataType = Check((AstNode)node.GetChild(1).GetChild(i), context); if (formalDataType != factDataType) { if (formalDataType == DataType.Double && factDataType == DataType.Int) convert((AstNode)node.GetChild(1).GetChild(i), DataType.Double); else throw new IntepreterException(string.Format("In function {0} param {1} incopotible types {2} {3}", node.GetChild(0).Text, i, DataTypeToStr(formalDataType), DataTypeToStr(factDataType))); } } return StrToDataType(ident.Node.GetChild(0).Text); } case CCompilerLexer.IDENT: { Ident ident = context[node.Text]; if (ident == null) throw new ApplicationException(string.Format("Unknown identifier {0}", node.Text)); if (ident.IdentType == IdentType.Function) { if (ident.DataType == DataType.Void) throw new IntepreterException(string.Format("Function {0} returns void", ident.Name)); if (ident.Node.GetChild(1).ChildCount > 0) throw new IntepreterException(string.Format("No params for function {0} call", ident.Name)); AstNode call = new AstNode(new Antlr.Runtime.CommonToken(CCompilerLexer.CALL)); call.AddChild(node); call.AddChild(new AstNode(new Antlr.Runtime.CommonToken(CCompilerLexer.ARGS))); node.Parent.SetChild(node.ChildIndex, call); node.DataType = ident.DataType; return node.DataType; } else { node.DataType = ident.DataType; return node.DataType; } } case CCompilerLexer.NUMBER: { node.DataType = node.Text.Contains(".") ? DataType.Double : DataType.Int; return node.DataType; } case CCompilerLexer.TRUE: case CCompilerLexer.FALSE: { node.DataType = DataType.Bool; return node.DataType; } case CCompilerLexer.ASSIGN: { Ident ident = context[node.GetChild(0).Text]; if (ident == null) throw new IntepreterException(string.Format("Unknown identifier {0}", node.GetChild(0).Text)); if (ident.IdentType == IdentType.Function) throw new IntepreterException(string.Format("Assign to function {0}", node.GetChild(0).Text)); DataType rightDataType = Check((AstNode)node.GetChild(1), context); if (ident.DataType != rightDataType) { if (ident.DataType == DataType.Double && rightDataType == DataType.Int) convert((AstNode)node.GetChild(1), DataType.Double); else throw new IntepreterException(string.Format("Assign incopotible types {0} {1}", DataTypeToStr(ident.DataType), DataTypeToStr(rightDataType))); } return DataType.Void; } case CCompilerLexer.RETURN: { if (context.Function == null) throw new ApplicationException(string.Format("Return not in function in line {0}", node.Line)); DataType returnDataType = Check((AstNode)node.GetChild(0), context); if (context.Function.DataType != returnDataType) { if (context.Function.DataType == DataType.Double && returnDataType == DataType.Int) convert((AstNode)node.GetChild(0), DataType.Double); else throw new IntepreterException(string.Format("Return incopotible types {0} {1}", DataTypeToStr(context.Function.DataType), DataTypeToStr(returnDataType))); } return DataType.Void; } case CCompilerLexer.ADD: case CCompilerLexer.SUB: case CCompilerLexer.MUL: case CCompilerLexer.DIV: case CCompilerLexer.GE: case CCompilerLexer.LE: case CCompilerLexer.NE: case CCompilerLexer.EQ: case CCompilerLexer.GT: case CCompilerLexer.LT: { bool compareOperation = true; switch (node.Type) { case CCompilerLexer.ADD: case CCompilerLexer.SUB: case CCompilerLexer.MUL: case CCompilerLexer.DIV: compareOperation = false; break; } DataType leftDataType = Check((AstNode)node.GetChild(0), context); DataType rightDataType = Check((AstNode)node.GetChild(1), context); if (leftDataType != DataType.Double && leftDataType != DataType.Int) throw new IntepreterException(string.Format("Left operand invalid type for operation {0}, line = {1}, pos = {2}", node.Text, node.Line, node.TokenStartIndex)); if (rightDataType != DataType.Double && rightDataType != DataType.Int) throw new IntepreterException(string.Format("Right operand invalid type for operation {0}, line = {1}, pos = {2}", node.Text, node.Line, node.TokenStartIndex)); if (leftDataType == DataType.Double) { if (rightDataType == DataType.Int) convert((AstNode)node.GetChild(1), DataType.Double); node.DataType = compareOperation ? DataType.Bool : DataType.Double; return node.DataType; } if (rightDataType == DataType.Double) { if (leftDataType == DataType.Int) convert((AstNode)node.GetChild(0), DataType.Double); node.DataType = compareOperation ? DataType.Bool : DataType.Double; return node.DataType; } node.DataType = compareOperation ? DataType.Bool : DataType.Int; return node.DataType; } case CCompilerLexer.NOT: { DataType dataType = Check((AstNode)node.GetChild(0), context); if (dataType != DataType.Bool) throw new IntepreterException(string.Format("Not operator with type {0}", DataTypeToStr(dataType))); node.DataType = DataType.Bool; return node.DataType; } case CCompilerLexer.AND: case CCompilerLexer.OR: case CCompilerLexer.WHILE: { DataType condDataType = Check((AstNode)node.GetChild(0), context); if (condDataType != DataType.Bool) throw new IntepreterException(string.Format("In while condition type is {0}", DataTypeToStr(condDataType))); Check((AstNode)node.GetChild(1), context); return DataType.Void; } case CCompilerLexer.IF: { DataType condDataType = Check((AstNode)node.GetChild(0), context); if (condDataType != DataType.Bool) throw new IntepreterException(string.Format("In if condition type is {0}", DataTypeToStr(condDataType))); Check((AstNode)node.GetChild(1), context); if (node.ChildCount == 3) Check((AstNode)node.GetChild(2), context); return DataType.Void; } case CCompilerLexer.FOR: { context = new Context(context); CheckBlock((AstNode)node.GetChild(0), context); DataType condDataType = Check((AstNode)node.GetChild(1), context); if (condDataType != DataType.Bool) throw new IntepreterException(string.Format("In while condition type is {0}", DataTypeToStr(condDataType))); CheckBlock((AstNode)node.GetChild(2), context); Check((AstNode)node.GetChild(3), context); return DataType.Void; } default: { return DataType.Void; //throw new IntepreterException("Unknown token type"); } } }
private static void convert(AstNode node, DataType dataType) { AstNode convert = new AstNode(new Antlr.Runtime.CommonToken(CCompilerLexer.CALL, "CONVERT")); node.Parent.SetChild(node.ChildIndex, convert); convert.DataType = dataType; convert.AddChild(node); convert.AddChild(new AstNode(new Antlr.Runtime.CommonToken(CCompilerLexer.IDENT, DataTypeToStr(dataType)))); }