public void fillInit(Context curContext) { if (curContext.Idents.Count > 0) { msil.Append(" .locals init (\n"); int index = 0; foreach (var kv in curContext.Idents) { if (kv.Value.IdentType != IdentType.Function) { msil.Append(string.Format(" [{0}] {1}", index, ReturnType(kv.Value.DataType.SimpleDataType))); //kv.Value.Index kv.Value.Index = index; if (kv.Value.DataType.ArrayCount == 1) { msil.Append(string.Format("[]")); } else if (kv.Value.DataType.ArrayCount > 1) { MsilArray(kv.Value.DataType.ArrayCount); } msil.Append(string.Format(" {0}{1}\n", kv.Key, ++index < curContext.Idents.Count ? "," : ",")); } } msil.Remove(msil.Length - 2, 1); msil.Append(" )\n"); } }
public static string GenerateMSIL(ITree programNode, Context context1) { MSILGenerator g = new MSILGenerator(programNode); //g.NumVariables(); context = context1; g.Generate(); return g.msil.ToString(); }
public static AstNode Check(string src, Context context) { ICharStream input = new ANTLRStringStream(src); MathExprLexer lexer = new MathExprLexer(input); CommonTokenStream tokens = new CommonTokenStream(lexer); MathExprParser parser = new MathExprParser(tokens); parser.TreeAdaptor = new AstNodeTreeAdapter(); AstNode program = (AstNode) parser.execute().Tree; SemanticChecker.Check((AstNode)program, context); return program; }
public static void Main(string[] args) { try { // в зависимости от наличия параметров командной строки разбираем // либо файл с именем, переданным первым параметром, либо стандартный ввод Context context = new Context(null); string src = @" void printInt(int a) { } void printDouble(double a) { } double sqrt(double a) { } double sqr(double a) { } int readInt() { } double readDouble() { } "; //Check(src, context); src = args.Length == 1 ? new StreamReader(args[0]).ReadToEnd() : Console.In.ReadToEnd(); ICharStream input = new ANTLRStringStream(src); MathExprLexer lexer = new MathExprLexer(input); CommonTokenStream tokens = new CommonTokenStream(lexer); MathExprParser parser = new MathExprParser(tokens); parser.TreeAdaptor = new AstNodeTreeAdapter(); ITree program = (ITree)parser.execute().Tree; AstNodePrinter.Print(program); Console.WriteLine(); SemanticChecker.Check((AstNode) program, context); AstNodePrinter.Print(program); //Console.ReadLine(); AstNodePrinter.Print(program); Console.WriteLine(); string msil = MSILGenerator.GenerateMSIL(program,context); Console.WriteLine(msil); Console.WriteLine(); Console.ReadLine(); } catch (Exception e) { Console.WriteLine("Error: {0}", e); Console.ReadLine(); } }
public Context(Context parentContext) { this.parentContext = parentContext; }
public static DataType Check(AstNode node, Context context) { switch (node.Type) { case MathExprLexer.PROGRAM: { if (context == null) context = new Context(context); CheckBlock(node, context); return DataType.Void; } case MathExprLexer.BLOCK: { context = new Context(context); CheckBlock(node, context); return DataType.Void; } case MathExprLexer.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 == MathExprLexer.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(MathExprLexer.VAR, "VAR")); var.AddChild(new AstNode(new Antlr.Runtime.CommonToken(MathExprLexer.IDENT, dataTypeToStr(dataType)))); var.GetChild(0).AddChild(new AstNode(new Antlr.Runtime.CommonToken(MathExprLexer.IDENT, temp.GetChild(0).Text))); nodes.Add(var); nodes.Add(temp); } else { Ident ident = context.InThisContext(temp.Text); if (ident != null) throw new ApplicationException(string.Format("Identifier {0} already exists", temp.Text)); AstNode var = new AstNode(new Antlr.Runtime.CommonToken(MathExprLexer.VAR, "VAR")); var.AddChild(new AstNode(new Antlr.Runtime.CommonToken(MathExprLexer.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 MathExprLexer.FUNCTION: { DataType dataType = strToDataType(node.GetChild(0).Text); string name = node.GetChild(1).Text; Ident ident = context[name]; if (ident != null) throw new ApplicationException(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 ApplicationException(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 MathExprLexer.CALL: { Ident ident = context[node.GetChild(0).Text]; if (ident == null) throw new ApplicationException(string.Format("Unknown identifier {0}", node.GetChild(0).Text)); if (ident.IdentType != IdentType.Function) throw new ApplicationException(string.Format("Identifier {0} is not function", node.GetChild(0).Text)); if (node.GetChild(1).ChildCount != ident.Node.GetChild(2).ChildCount) throw new ApplicationException(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 ApplicationException(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 MathExprLexer.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 ApplicationException(string.Format("Function {0} returns void", ident.Name)); if (ident.Node.GetChild(1).ChildCount > 0) throw new ApplicationException(string.Format("No params for function {0} call", ident.Name)); AstNode call = new AstNode(new Antlr.Runtime.CommonToken(MathExprLexer.CALL)); call.AddChild(node); call.AddChild(new AstNode(new Antlr.Runtime.CommonToken(MathExprLexer.PARAMS))); node.Parent.SetChild(node.ChildIndex, call); node.DataType = ident.DataType; return node.DataType; } else { node.DataType = ident.DataType; return node.DataType; } } case MathExprLexer.NUMBER: { node.DataType = node.Text.Contains(".") ? DataType.Double : DataType.Int; return node.DataType; } case MathExprLexer.TRUE: case MathExprLexer.FALSE: { node.DataType = DataType.Bool; return node.DataType; } case MathExprLexer.ASSIGN: { Ident ident = context[node.GetChild(0).Text]; if (ident == null) throw new ApplicationException(string.Format("Unknown identifier {0}", node.GetChild(0).Text)); if (ident.IdentType == IdentType.Function) throw new ApplicationException(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 ApplicationException(string.Format("Assign incopotible types {0} {1}", dataTypeToStr(ident.DataType), dataTypeToStr(rightDataType))); } return DataType.Void; } case MathExprLexer.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 ApplicationException(string.Format("Return incopotible types {0} {1}", dataTypeToStr(context.Function.DataType), dataTypeToStr(returnDataType))); } return DataType.Void; } case MathExprLexer.ADD: case MathExprLexer.SUB: case MathExprLexer.MUL: case MathExprLexer.DIV: case MathExprLexer.GE: case MathExprLexer.LE: case MathExprLexer.NEQUALS: case MathExprLexer.EQUALS: case MathExprLexer.GT: case MathExprLexer.LT: { bool compareOperation = true; switch (node.Type) { case MathExprLexer.ADD: case MathExprLexer.SUB: case MathExprLexer.MUL: case MathExprLexer.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 ApplicationException(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 ApplicationException(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 MathExprLexer.NOT: { DataType dataType = Check((AstNode) node.GetChild(0), context); if (dataType != DataType.Bool) throw new ApplicationException(string.Format("Not operator with type {0}", dataTypeToStr(dataType))); node.DataType = DataType.Bool; return node.DataType; } case MathExprLexer.AND: case MathExprLexer.OR: case MathExprLexer.XOR: { DataType leftDataType = Check((AstNode) node.GetChild(0), context); DataType rightDataType = Check((AstNode) node.GetChild(1), context); if (leftDataType != DataType.Bool && rightDataType != DataType.Bool) throw new ApplicationException(string.Format("{0} operator with type {1}, {2}", node.Text, dataTypeToStr(leftDataType), dataTypeToStr(rightDataType))); node.DataType = DataType.Bool; return node.DataType; } case MathExprLexer.WHILE: { DataType condDataType = Check((AstNode)node.GetChild(0), context); if (condDataType != DataType.Bool) throw new ApplicationException(string.Format("In while condition type is {0}", dataTypeToStr(condDataType))); // context = new Context(context); Check((AstNode)node.GetChild(1), context); return DataType.Void; } case MathExprLexer.IF: { DataType condDataType = Check((AstNode)node.GetChild(0), context); if (condDataType != DataType.Bool) throw new ApplicationException(string.Format("In if condition type is {0}", dataTypeToStr(condDataType))); // context = new Context(context); Check((AstNode)node.GetChild(1), context); if (node.ChildCount == 3) Check((AstNode)node.GetChild(2), context); return DataType.Void; } case MathExprLexer.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 ApplicationException(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: { throw new ApplicationException("Unknown token type"); } break; } }
public static void CheckBlock(AstNode node, Context context) { for (int i = 0; i < node.ChildCount; i++) Check((AstNode)node.GetChild(i), context); }
private void Generate(ITree node, Context context) { int tempLabIndex; switch (node.Type) { case AstNodeType.VARS: case AstNodeType.VAR: int tmp = (node.GetChild(1) as AstNode).ODataType.ArrayCount; if (tmp > 0) { for (int i = 0; i < tmp; i++) { msil.Append(string.Format(" ldc.i4.s {0}\n", (node.GetChild(1) as AstNode).ODataType.ALength)); } if (tmp == 1) msil.Append(string.Format(" newarr [mscorlib]System.{0}\n", ReturnConvertType(context.Idents[node.GetChild(0).Text].DataType.SimpleDataType))); else { msil.Append(string.Format(" newobj instance void {0}", ReturnType(context.Idents[node.GetChild(0).Text].DataType.SimpleDataType))); MsilArray(tmp); msil.Append(string.Format("\n")); } msil.Append(string.Format(" stloc.s {0}\n", context.Idents[node.GetChild(0).Text].Index)); } break; case AstNodeType.ARRAYPART: Generate((AstNode)node.GetChild(0), context); for (int i = 1; i < node.ChildCount; i++) { Generate((AstNode)node.GetChild(i), context); } if (node.ChildCount == 2) { msil.Append(string.Format(" ldelem.i4\n")); } else { string type = ReturnType(context.Idents[node.GetChild(0).Text].DataType.SimpleDataType); msil.Append(string.Format(" call instance {0} {0} ", type)); MsilArray(node.ChildCount - 1); msil.Append(string.Format("::Get({0} ", type)); for (int i = 0; i < node.ChildCount - 2; i++) { msil.Append(string.Format(",{0}", type)); } msil.Append(string.Format(")\n", type)); } break; case AstNodeType.ASSIGN: if (node.GetChild(0).Type != AstNodeType.ARRAYPART) { Generate(node.GetChild(1), context); msil.Append(string.Format(" stloc.s {0}\n", context.Idents[node.GetChild(0).Text].Index)); } else { Generate(node.GetChild(0).GetChild(0), context); for (int i = 1; i < node.ChildCount; i++) { Generate((AstNode)node.GetChild(0).GetChild(i), context); } if (node.ChildCount == 2) { Generate(node.GetChild(1), context); msil.Append(string.Format(" stelem.i4\n")); } else { string type = ReturnType(context.Idents[node.GetChild(0).Text].DataType.SimpleDataType); msil.Append(string.Format(" call instance void {0} ", type)); MsilArray(node.ChildCount - 1); msil.Append(string.Format("::Set({0} ", type)); for (int i = 0; i < node.ChildCount - 2; i++) { msil.Append(string.Format(",{0}", type)); } msil.Append(string.Format(")\n", type)); } } break; case AstNodeType.IDENT: Ident ident = context.InThisContext(node.Text);//context.Idents[node.Text]; if (ident == null) { ident = context.ParentContext.InThisContext(node.Text); if (ident != null && context.ParentContext.Function != null) msil.Append(string.Format(" ldarg.s {0}\n", ident.Index)); break; } msil.Append(string.Format(" ldloc.s {0}\n", ident.Index)); break; case AstNodeType.NUMBER: msil.Append(string.Format(" ldc.i4.s {0}\n", node.Text)); break; case AstNodeType.TRUE: msil.Append(string.Format(" ldc.i4.s {0}\n", 1)); break; case AstNodeType.FALSE: msil.Append(string.Format(" ldc.i4.s {0}\n", 0)); break; case AstNodeType.STRINGVAL: msil.Append(string.Format(" ldstr {0}\n", node.Text)); break; case AstNodeType.FUNC_CALL: for (int i = 0; i < node.GetChild(1).ChildCount; i++) { Generate(node.GetChild(1).GetChild(i), context); } msil.Append(string.Format(" call {0} Program::{1}(", ReturnType((node as AstNode).ODataType.SimpleDataType), node.GetChild(0).Text)); for (int i = 0; i < node.GetChild(1).ChildCount; i++) { msil.Append(string.Format("{0}, ", ReturnType((node.GetChild(1).GetChild(i) as AstNode).ODataType.SimpleDataType))); } msil.Remove(msil.Length - 2, 2); msil.Append(string.Format(")\n")); break; case AstNodeType.FUNC: break; case AstNodeType.CONVERT: Generate((AstNode)node.GetChild(0), context); msil.Append(string.Format(" call string [mscorlib]System.Convert::To{0}({1})\n", ReturnConvertType((node as AstNode).ODataType.SimpleDataType), ReturnType((node.GetChild(0) as AstNode).ODataType.SimpleDataType))); break; case AstNodeType.ADD: case AstNodeType.SUB: case AstNodeType.MUL: case AstNodeType.DIV: string oper = node.Type == AstNodeType.ADD ? "add" : node.Type == AstNodeType.SUB ? "sub" : node.Type == AstNodeType.MUL ? "mul" : node.Type == AstNodeType.DIV ? "div" : "unknown"; Generate(node.GetChild(0), context); Generate(node.GetChild(1), context); msil.Append(string.Format(" {0}\n", oper)); break; case AstNodeType.GT: case AstNodeType.EQ: case AstNodeType.LT: oper = node.Type == AstNodeType.GT ? "cgt" : node.Type == AstNodeType.LT ? "clt" : node.Type == AstNodeType.EQ ? "ceq" : "unknown"; Generate(node.GetChild(0), context); Generate(node.GetChild(1), context); msil.Append(string.Format(" {0}\n", oper)); break; case AstNodeType.GE: case AstNodeType.LE: case AstNodeType.NE: oper = node.Type == AstNodeType.GE ? "clt" : node.Type == AstNodeType.LE ? "cgt" : node.Type == AstNodeType.NE ? "seq" : "unknown"; Generate(node.GetChild(0), context); Generate(node.GetChild(1), context); msil.Append(string.Format(" {0}\n", oper)); msil.Append(string.Format(" ldc.i4.0 \n")); msil.Append(string.Format(" seq\n")); break; case MathExprLexer.SINCR: case MathExprLexer.EINCR: case MathExprLexer.SDECR: case MathExprLexer.EDECR: oper = (node.Type == AstNodeType.SINCR || node.Type == AstNodeType.EINCR) ? "add" : (node.Type == AstNodeType.SDECR || node.Type == AstNodeType.EDECR) ? "sub" : "unknown"; msil.Append(string.Format(" ldloc.s {0}\n", context.Idents[node.GetChild(0).Text].Index)); msil.Append(string.Format(" ldc.i4.1 \n")); msil.Append(string.Format(" {0}\n", oper)); msil.Append(string.Format(" stloc.s {0}\n", context.Idents[node.GetChild(0).Text].Index)); break; case AstNodeType.IF: tempLabIndex = labIndex; labIndex += 2; Generate(node.GetChild(0), context); msil.Append(string.Format(" brfalse.s L_{0:X4}\n", tempLabIndex + 1)); Generate(node.GetChild(1), context); msil.Append(string.Format(" br.s L_{0:X4}\n", tempLabIndex + 2)); msil.Append(string.Format(" L_{0:X4}:\n", tempLabIndex + 1)); if (node.ChildCount > 2) Generate(node.GetChild(2), context); msil.Append(string.Format(" L_{0:X4}:\n", tempLabIndex + 2)); break; case AstNodeType.WHILE: tempLabIndex = labIndex; labIndex += 2; msil.Append(string.Format(" L_{0:X4}:\n", tempLabIndex + 1)); Generate(node.GetChild(0), context); msil.Append(string.Format(" brfalse.s L_{0:X4}\n", tempLabIndex + 2)); Generate(node.GetChild(1), context); msil.Append(string.Format(" br.s L_{0:X4}\n", tempLabIndex + 1)); msil.Append(string.Format(" L_{0:X4}:\n", tempLabIndex + 2)); break; case AstNodeType.REPEATE: tempLabIndex = labIndex; labIndex += 1; msil.Append(string.Format(" L_{0:X4}:\n", tempLabIndex + 1)); Generate(node.GetChild(0), context); Generate(node.GetChild(1), context); msil.Append(string.Format(" brtrue.s L_{0:X4}\n", tempLabIndex + 1)); break; case AstNodeType.FOR: tempLabIndex = labIndex; labIndex += 2; Generate(node.GetChild(1), context); msil.Append(string.Format(" stloc.s {0}\n", context.Idents[node.GetChild(0).GetChild(0).Text].Index)); msil.Append(string.Format(" L_{0:X4}:\n", tempLabIndex + 1)); msil.Append(string.Format(" ldloc.s {0}\n", context.Idents[node.GetChild(0).GetChild(0).Text].Index)); Generate(node.GetChild(2), context); msil.Append(string.Format(" sub\n")); msil.Append(string.Format(" ldc.i4.s {0}\n", 1)); msil.Append(string.Format(" sub\n")); msil.Append(string.Format(" brfalse.s L_{0:X4}\n", tempLabIndex + 2)); Generate(node.GetChild(3), context); msil.Append(string.Format(" ldloc.s {0}\n", context.Idents[node.GetChild(0).GetChild(0).Text].Index)); msil.Append(string.Format(" ldc.i4.s {0}\n", 1)); msil.Append(string.Format(" add\n")); msil.Append(string.Format(" stloc.s {0}\n", context.Idents[node.GetChild(0).GetChild(0).Text].Index)); msil.Append(string.Format(" br.s L_{0:X4}\n", tempLabIndex + 1)); msil.Append(string.Format(" L_{0:X4}:\n", tempLabIndex + 2)); break; case AstNodeType.PRINT: Generate(node.GetChild(0), context); msil.Append(string.Format(" call void [mscorlib]System.Console::WriteLine(string)\n")); msil.Append(string.Format(" nop\n")); break; case AstNodeType.RETURN: Generate((AstNode)node.GetChild(0), context); msil.Append(string.Format(" ret\n")); break; case AstNodeType.BLOCK: case AstNodeType.PROGRAM: for (int i = 0; i < node.ChildCount; i++) Generate(node.GetChild(i), context); break; default: throw new MSILGeneratorException("Not implemented!"); } }
public static void CheckBlock(AstNode node, Context context) { for (int crutch = 0; crutch < node.ChildCount; crutch++) { //AstNodePrinter.Print(node); Check((AstNode)node.GetChild(crutch), context); AstNodePrinter.Print(node); } }
public static OrigDataType Check(AstNode node, Context context) { switch (node.Type) { case MathExprLexer.PROGRAM: { if (context == null) context = new Context(context); CheckBlock(node, context); return new OrigDataType(DataType.Void); } case MathExprLexer.BLOCK: { context = new Context(context); contexts.Add(context); CheckBlock(node, context); return new OrigDataType(DataType.Void); } case MathExprLexer.LET: case MathExprLexer.VAR: { List<AstNode> nodes = new List<AstNode>(); //String str = node.GetChild(1).GetChild(0).Text; OrigDataType dataType; //OrigDataType dataType = strToDataType(node.GetChild(1).GetChild(0).Text); for (int i = 0; i < node.ChildCount; i++) { dataType = new OrigDataType(DataType.Void); AstNode tempi = (AstNode)node.GetChild(i); Ident ident = context.InThisContext(node.GetChild(i).Text); if (ident != null) throw new ApplicationException(string.Format("Identifier {0} already exists", tempi.Text)); String typeText = node.Type == MathExprLexer.VAR ? "VARS" : "LETS"; AstNode var = new AstNode(new Antlr.Runtime.CommonToken(MathExprLexer.VARS, typeText)); var.AddChild(new AstNode(new Antlr.Runtime.CommonToken(MathExprLexer.IDENT, tempi.Text))); nodes.Add(var); for (int j = 0; j < node.GetChild(i).ChildCount; j++) { AstNode tempj = (AstNode)node.GetChild(i).GetChild(j); if (tempj.Token.Type == MathExprLexer.TYPE && tempj.ChildCount > 0) { dataType.ReturnFromType(tempj); AstNode tempType = new AstNode(new Antlr.Runtime.CommonToken(MathExprLexer.TYPE, dataTypeToStr(dataType.SimpleDataType))); tempType.ODataType = dataType; var.AddChild(tempType); } if (tempj.Token.Type == MathExprLexer.ASSIGN) { AstNode tempAssign = new AstNode(new Antlr.Runtime.CommonToken(MathExprLexer.ASSIGN, "=")); tempAssign.AddChild(new AstNode(new Antlr.Runtime.CommonToken(MathExprLexer.IDENT, tempi.Text))); tempAssign.AddChild(tempj.GetChild(0)); nodes.Add(tempAssign); if (dataType.SimpleDataType == DataType.Void) { dataType = Check((AstNode)tempAssign.GetChild(1), context); AstNode tempType = new AstNode(new Antlr.Runtime.CommonToken(MathExprLexer.TYPE, dataTypeToStr(dataType.SimpleDataType))); tempType.ODataType = dataType; AstNode tempCheckArrayPart = (AstNode)tempj.GetChild(0); //часть массива if (tempCheckArrayPart.Token.Type == MathExprLexer.ARRAY) { dataType.Check((AstNode)tempAssign.GetChild(1)); AstNode tempTypeArr = (AstNode)tempj.GetChild(0); tempType.ODataType.ArrayCount = tempTypeArr.ODataType.ArrayCount; } //вызов функции if (tempCheckArrayPart.Token.Type == MathExprLexer.FUNC_CALL) { Check((AstNode)tempAssign.GetChild(1), context); tempType.ODataType = (tempAssign.GetChild(1) as AstNode).ODataType; } var.AddChild(tempType); crutch++; } } } string name = nodes[i + i].GetChild(0).Text; context[name] = new Ident(name, context.ParentContext == null ? IdentType.GlobalVar : IdentType.LocalVar, dataType, nodes[i + i], identIndex++); } 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 new OrigDataType(DataType.Void); } case MathExprLexer.VARS: case MathExprLexer.PARAMS: return new OrigDataType(DataType.Void); case MathExprLexer.FUNC: { OrigDataType dataType = new OrigDataType(strToDataType(node.GetChild(2).GetChild(0).Text)); string name = node.GetChild(0).Text; Ident ident = context[name]; if (ident != null) throw new ApplicationException(string.Format("Identifier {0} already exists", name)); Ident func = new Ident(name, IdentType.Function, dataType, node, identIndex++); context[name] = func; context = new Context(context); contexts.Add(context); AstNode _params = (AstNode)node.GetChild(1); for (int i = 0; i < _params.ChildCount; i++) { OrigDataType paramDataType = new OrigDataType(strToDataType(_params.GetChild(i).GetChild(0).Text)); string paramName = _params.GetChild(i).Text; if (paramDataType.SimpleDataType == DataType.Void) throw new ApplicationException(string.Format("In function {0} void param {1}", name, paramName)); context[paramName] = new Ident(paramName, IdentType.Param, paramDataType, (AstNode)_params.GetChild(i), identIndex++); } context.Function = func; if (dataType.SimpleDataType == DataType.Array) { dataType.ReturnFromType((AstNode)node.GetChild(2).GetChild(0)); dataType.ArrayCount++; AstNode tempType = new AstNode(new Antlr.Runtime.CommonToken(MathExprLexer.TYPE, dataTypeToStr(dataType.SimpleDataType))); tempType.ODataType = dataType; node.GetChild(2).ReplaceChildren(0, 0, tempType); } Check((AstNode)node.GetChild(3), context); return new OrigDataType(DataType.Void); } case MathExprLexer.CONVERT: { OrigDataType dataType = new OrigDataType(strToDataType(node.GetChild(1).Text)); return dataType; } case MathExprLexer.FUNC_CALL: { Ident ident = context[node.GetChild(0).Text]; node.ODataType = ident.DataType; if (ident == null) throw new ApplicationException(string.Format("Unknown identifier {0}", node.GetChild(0).Text)); if (ident.IdentType != IdentType.Function) throw new ApplicationException(string.Format("Identifier {0} is not function", node.GetChild(0).Text)); if (node.ChildCount == 2 && node.GetChild(1).ChildCount != ident.Node.GetChild(1).ChildCount) throw new ApplicationException(string.Format("Not equals params count in function {0}", node.GetChild(0).Text)); for (int i = 0; i < ident.Node.GetChild(1).ChildCount; i++) { OrigDataType formalDataType = new OrigDataType(strToDataType(ident.Node.GetChild(1).GetChild(i).GetChild(0).Text)); OrigDataType factDataType = Check((AstNode)node.GetChild(1).GetChild(i), context); if (formalDataType.SimpleDataType != factDataType.SimpleDataType) { if (formalDataType.SimpleDataType == DataType.Double && factDataType.SimpleDataType == DataType.Int) convert((AstNode)node.GetChild(1).GetChild(i), new OrigDataType(DataType.Double)); else throw new ApplicationException(string.Format("In function {0} param {1} incopotible types {2} {3}", node.GetChild(0).Text, i, dataTypeToStr(formalDataType.SimpleDataType), dataTypeToStr(factDataType.SimpleDataType))); } } return new OrigDataType(strToDataType(ident.Node.GetChild(2).GetChild(0).Text)); } case MathExprLexer.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.SimpleDataType == DataType.Void) throw new ApplicationException(string.Format("Function {0} returns void", ident.Name)); if (ident.Node.GetChild(1).ChildCount > 0) throw new ApplicationException(string.Format("No params for function {0} call", ident.Name)); AstNode call = new AstNode(new Antlr.Runtime.CommonToken(MathExprLexer.FUNC_CALL)); call.AddChild(node); call.AddChild(new AstNode(new Antlr.Runtime.CommonToken(MathExprLexer.PARAMS))); node.Parent.SetChild(node.ChildIndex, call); node.ODataType = ident.DataType; return node.ODataType; } else { node.ODataType = ident.DataType; return node.ODataType; } } case MathExprLexer.NUMBER: { node.ODataType = node.Text.Contains(".") ? new OrigDataType(DataType.Double) : new OrigDataType(DataType.Int); return node.ODataType; } case MathExprLexer.STRINGVAL: { node.ODataType.SimpleDataType = DataType.String; return node.ODataType; } case MathExprLexer.TRUE: case MathExprLexer.FALSE: { node.ODataType.SimpleDataType = DataType.Bool; return node.ODataType; } case MathExprLexer.ARRAY: { OrigDataType dataType = new OrigDataType(DataType.Void); dataType.ReturnFromValue(node); node.ODataType = dataType; int tmpArr = dataType.ArrayCount; //int type = node.GetChild(0).Type; for (int i = 0; i < node.ChildCount; i++) { dataType = Check((AstNode)node.GetChild(i), context); } return dataType; } case MathExprLexer.ARRAYPART: { Ident ident = context[node.GetChild(0).Text]; OrigDataType dataType = new OrigDataType(ident.DataType.SimpleDataType); dataType.ArrayCount = ident.DataType.ArrayCount - node.ChildCount + 1; for (int i = 1; i < node.ChildCount; i++) { Check((AstNode)node.GetChild(i), context); } node.ODataType = dataType; return dataType; } case MathExprLexer.ASSIGN: { Ident ident = context[node.GetChild(0).Text]; if (node.GetChild(0).Type == MathExprLexer.ARRAYPART) { ident = context[node.GetChild(0).GetChild(0).Text]; } if (ident == null) throw new ApplicationException(string.Format("Unknown identifier {0}", node.GetChild(0).Text)); if (ident.IdentType == IdentType.Function) throw new ApplicationException(string.Format("Assign to function {0}", node.GetChild(0).Text)); OrigDataType rightDataType = Check((AstNode)node.GetChild(1), context); if (ident.DataType.SimpleDataType == DataType.Void) return rightDataType; //if(ident.OrigDataType == OrigDataType.Void) if (ident.DataType.SimpleDataType != rightDataType.SimpleDataType) { if (ident.DataType.SimpleDataType == DataType.Double && rightDataType.SimpleDataType == DataType.Int) convert((AstNode)node.GetChild(1), new OrigDataType(DataType.Double)); else throw new ApplicationException(string.Format("Assign incopotible types {0} {1}", dataTypeToStr(ident.DataType.SimpleDataType), dataTypeToStr(rightDataType.SimpleDataType))); } return new OrigDataType(DataType.Void); } case MathExprLexer.RETURN: { if (context.Function == null) throw new ApplicationException(string.Format("Return not in function in line {0}", node.Line)); OrigDataType returnDataType = Check((AstNode)node.GetChild(0), context); if (context.Function.DataType.SimpleDataType != returnDataType.SimpleDataType && context.Function.DataType.ArrayCount != returnDataType.ArrayCount) { if (context.Function.DataType.SimpleDataType == DataType.Double && returnDataType.SimpleDataType == DataType.Int) convert((AstNode)node.GetChild(0), new OrigDataType(DataType.Double)); else throw new ApplicationException(string.Format("Return incopotible types {0} {1}", dataTypeToStr(context.Function.DataType.SimpleDataType), dataTypeToStr(returnDataType.SimpleDataType))); } return new OrigDataType(DataType.Void); } case MathExprLexer.SINCR: case MathExprLexer.EINCR: case MathExprLexer.SDECR: case MathExprLexer.EDECR: { OrigDataType idenDataType = Check((AstNode)node.GetChild(0), context); if (idenDataType.SimpleDataType != DataType.Int && idenDataType.SimpleDataType != DataType.Double) throw new ApplicationException(string.Format("In crement condition type is {0}", dataTypeToStr(idenDataType.SimpleDataType))); return new OrigDataType(DataType.Void); } case MathExprLexer.ADD: case MathExprLexer.SUB: case MathExprLexer.MUL: case MathExprLexer.DIV: case MathExprLexer.GE: case MathExprLexer.LE: case MathExprLexer.NE: case MathExprLexer.EQ: case MathExprLexer.GT: case MathExprLexer.LT: { bool compareOperation = true; switch (node.Type) { case MathExprLexer.ADD: case MathExprLexer.SUB: case MathExprLexer.MUL: case MathExprLexer.DIV: compareOperation = false; break; } OrigDataType leftDataType = Check((AstNode)node.GetChild(0), context); OrigDataType rightDataType = Check((AstNode)node.GetChild(1), context); if (leftDataType.SimpleDataType != DataType.Double && leftDataType.SimpleDataType != DataType.Int && leftDataType.SimpleDataType != DataType.Bool) throw new ApplicationException(string.Format("Left operand invalid type for operation {0}, line = {1}, pos = {2}", node.Text, node.Line, node.TokenStartIndex)); if (rightDataType.SimpleDataType != DataType.Double && rightDataType.SimpleDataType != DataType.Int && leftDataType.SimpleDataType != DataType.Bool) throw new ApplicationException(string.Format("Right operand invalid type for operation {0}, line = {1}, pos = {2}", node.Text, node.Line, node.TokenStartIndex)); if (leftDataType.SimpleDataType == DataType.Double) { if (rightDataType.SimpleDataType == DataType.Int) convert((AstNode)node.GetChild(1), new OrigDataType(DataType.Double)); node.ODataType = compareOperation ? new OrigDataType(DataType.Bool) : new OrigDataType(DataType.Double); return node.ODataType; } if (rightDataType.SimpleDataType == DataType.Double) { if (leftDataType.SimpleDataType == DataType.Int) convert((AstNode)node.GetChild(0), new OrigDataType(DataType.Double)); node.ODataType = compareOperation ? new OrigDataType(DataType.Bool) : new OrigDataType(DataType.Double); return node.ODataType; } node.ODataType = compareOperation ? new OrigDataType(DataType.Bool) : new OrigDataType(DataType.Int); return node.ODataType; } case MathExprLexer.NOT: { OrigDataType dataType = Check((AstNode)node.GetChild(0), context); if (dataType.SimpleDataType != DataType.Bool) throw new ApplicationException(string.Format("Not operator with type {0}", dataTypeToStr(dataType.SimpleDataType))); node.ODataType.SimpleDataType = DataType.Bool; return node.ODataType; } case MathExprLexer.AND: case MathExprLexer.OR: { OrigDataType leftDataType = Check((AstNode)node.GetChild(0), context); OrigDataType rightDataType = Check((AstNode)node.GetChild(1), context); if (leftDataType.SimpleDataType != DataType.Bool && rightDataType.SimpleDataType != DataType.Bool) throw new ApplicationException(string.Format("{0} operator with type {1}, {2}", node.Text, dataTypeToStr(leftDataType.SimpleDataType), dataTypeToStr(rightDataType.SimpleDataType))); node.ODataType = new OrigDataType(DataType.Bool); return node.ODataType; } case MathExprLexer.REPEATE: case MathExprLexer.WHILE: { OrigDataType condDataType = Check((AstNode)node.GetChild(0), context); if (condDataType.SimpleDataType != DataType.Bool) throw new ApplicationException(string.Format("In while condition type is {0}", dataTypeToStr(condDataType.SimpleDataType))); // context = new Context(context); Check((AstNode)node.GetChild(1), context); return new OrigDataType(DataType.Void); } case MathExprLexer.IF: { OrigDataType condDataType = Check((AstNode)node.GetChild(0), context); if (condDataType.SimpleDataType != DataType.Bool) throw new ApplicationException(string.Format("In if condition type is {0}", dataTypeToStr(condDataType.SimpleDataType))); //context = new Context(context); Check((AstNode)node.GetChild(1), context); if (node.ChildCount == 3) Check((AstNode)node.GetChild(2), context); return new OrigDataType(DataType.Void); } case MathExprLexer.FOR: { for (int i = 0; i < node.ChildCount - 1; i++) { Check((AstNode)node.GetChild(i), context); } context = new Context(context); CheckBlock((AstNode)node.GetChild(node.ChildCount - 1), context); OrigDataType condDataType = Check((AstNode)node.GetChild(node.ChildCount - 3), context); if (condDataType.SimpleDataType != DataType.Bool) throw new ApplicationException(string.Format("In while condition type is {0}", dataTypeToStr(condDataType.SimpleDataType))); return new OrigDataType(DataType.Void); } case MathExprLexer.SWITCH: { OrigDataType identDataType = Check((AstNode)node.GetChild(0), context); for (int i = 1; i < node.ChildCount; i++) { AstNode tempi = (AstNode)node.GetChild(i); for (int j = 0; j < tempi.GetChild(0).ChildCount; j++) { if (identDataType.SimpleDataType != Check((AstNode)tempi.GetChild(0).GetChild(j), context).SimpleDataType) throw new ApplicationException(string.Format("In switch identDataType type is {0}", dataTypeToStr(identDataType.SimpleDataType))); } context = new Context(context); CheckBlock((AstNode)tempi.GetChild(1), context); //Check((AstNode)node.GetChild(i), context); } //context = new Context(context); return new OrigDataType(DataType.Void); } case MathExprLexer.PRINT: { if (node.ChildCount > 0) { Check((AstNode)node.GetChild(0), context); if ((node.GetChild(0) as AstNode).ODataType.SimpleDataType != DataType.String) { convert((AstNode)node.GetChild(0), new OrigDataType(DataType.String)); } } return new OrigDataType(DataType.String); } default: { throw new ApplicationException("Unknown token type"); } } }