private static void EmitShowMessage(Token[] smt) { //ShowMessage DoorOpenedScienceMsg passSkill //59 10 0E 00 01 00 72 02 00 01 00 73 01 00 00 00 00 00 Emit(0x1059); if(smt.Length==1) { AddError("Not enough arguments to ShowMessage"); return; } long pos=bw.BaseStream.Length; Emit(0); Emit(1); switch(smt[1].type) { case TokenType.edid: if(edidList[smt[1].token].Value!="MESG") goto default; else EmitRefLabel(smt[1], RefType.Expression); break; case TokenType.Local: LocalVar vt=locals[smt[1].token]; if(vt.type!=VarType.Ref) goto default; EmitRefLabel(smt[1], RefType.Expression); break; default: AddError("First argument to ShowMessage must be an MESG record"); return; } if(smt.Length==2) { Emit(0); } else { bool lastwasref=false; Emit((ushort)(smt.Length-2)); for(int i=2;i<smt.Length;i++) { if(smt[i].type==TokenType.Symbol) { if(smt[i].IsSymbol(".")&&lastwasref) { if(i<smt.Length-1&&farVars.ContainsKey(smt[i-1].token)) { i++; EmitByte(0x73); Dictionary<string, ushort> vars=farVars[smt[i-2].token]; if(!vars.ContainsKey(smt[i].token)) AddError("Reference '"+smt[i-2].utoken+"' has no variable called '"+smt[i].utoken+"'"); else Emit(vars[smt[i].token]); continue; } } else if(smt[i].IsSymbol("-")) { if(i<smt.Length-1&&(smt[i+1].type==TokenType.Integer||smt[i+1].type==TokenType.Float)) { smt[i+1]=new Token(smt[i+1].type, "-"+smt[i+1].token); continue; } } AddError("Unexpected symbol '"+smt[i].token+"' in ShowMessage arguments"); } lastwasref=false; switch(smt[i].type) { case TokenType.edid: EmitRefLabel(smt[i], RefType.Expression); lastwasref=true; break; case TokenType.Local: LocalVar vt=locals[smt[i].token]; switch(vt.type) { case VarType.Int: EmitByte(0x73); Emit((ushort)locals[smt[i].token].index); break; case VarType.Float: EmitByte(0x66); Emit((ushort)locals[smt[i].token].index); break; case VarType.Ref: EmitRefLabel(smt[i], RefType.Expression); break; } break; case TokenType.Global: EmitRefLabel(smt[i], RefType.Expression); break; case TokenType.Integer: EmitByte(0x6e); bw.Write(int.Parse(smt[i].token)); break; case TokenType.Float: EmitByte(0x7a); bw.Write(double.Parse(smt[i].token)); break; default: AddError("Expected <global>|<local>|<constant>"); return; } } } Emit(0); Emit(0); bw.BaseStream.Position=pos; Emit((ushort)(bw.BaseStream.Length-(pos+2))); bw.BaseStream.Position=bw.BaseStream.Length; }
private static void HandleStatement(Token[] smt) { if(smt[0].type==TokenType.Function) { EmitFunctionCall(ref smt, false, false, false); } else if(smt[0].IsKeyword(Keywords.ShowMessage)) { EmitShowMessage(smt); ; } else if(smt[0].IsKeyword(Keywords.Set)) { if(smt.Length<4||!(smt[2].IsKeyword(Keywords.To)||smt[2].IsSymbol("."))) { AddError("Expected 'set <var> to <expression>'"); return; } Emit(0x15); long pos=bw.BaseStream.Length; Emit(0); if(smt[1].type==TokenType.Local) { LocalVar lv=locals[smt[1].token]; if(lv.type==VarType.Int) EmitByte(0x73); else EmitByte(0x66); Emit((ushort)lv.index); EmitExpression(TrimStatement(smt, 3), (lv.type==VarType.Ref)?ExpressionType.Ref:ExpressionType.Numeric); } else if(smt[1].type==TokenType.Global) { EmitRefLabel(smt[1], RefType.Expression); EmitExpression(TrimStatement(smt, 3), ExpressionType.Numeric); } else if(smt[1].type==TokenType.edid&&farVars.ContainsKey(smt[1].token)&&smt[2].IsSymbol(".")) { if(smt.Length<6||!smt[4].IsKeyword(Keywords.To)) { AddError("Expected 'set <var> to <expression>'"); return; } EmitRefLabel(smt[1], RefType.Expression); EmitByte(0x73); if(!farVars[smt[1].token].ContainsKey(smt[3].token)) { AddError("Local variable '"+smt[3].token+" does not exist in quest "+smt[1].token); } else { Emit(farVars[smt[1].token][smt[3].token]); } EmitExpression(TrimStatement(smt, 5), ExpressionType.If); } else { AddError("Expected set <local>|<global> to <expression>"); } bw.BaseStream.Position=pos; Emit((ushort)(bw.BaseStream.Length-(pos+2))); bw.BaseStream.Position=bw.BaseStream.Length; } else if(smt[0].type==TokenType.edid) { if(smt.Length<3||!smt[1].IsSymbol(".")||smt[2].type!=TokenType.Function) { AddError("Expected ref.function"); return; } EmitRefLabel(smt[0], RefType.Standard); smt=TrimStatement(smt, 2); EmitFunctionCall(ref smt, false, true, false); } else if(smt[0].type==TokenType.Local) { LocalVar lv=locals[smt[0].token]; if(lv.type!=VarType.Ref) { AddError("Expected 'Set', <function> or <ref>.<function>"); return; } if(smt.Length<3||!smt[1].IsSymbol(".")||smt[2].type!=TokenType.Function) { AddError("Expected ref.function"); return; } EmitRefLabel(smt[0], RefType.Standard); smt=TrimStatement(smt, 2); EmitFunctionCall(ref smt, false, true, false); } else { AddError("Expected 'Set', <function> or <ref>.<function>"); } }
private static void EmitFunctionCall(ref Token[] smt, bool expression, bool hadref, bool requiresRef) { FunctionSig fs=functionList[smt[0].token]; if(hadref&&!fs.allowref) AddError("Object reference not valid on this function"); if(expression) { EmitByte(0x58); //if(fs.ret==VarType.None) AddError("Functions with no return type cannot be used in expressions"); } //if(requiresRef&&fs.ret!=VarType.Ref) AddError("Function does not return a reference"); Emit(fs.opcode); if(fs.skipArgs) { if(expression) AddError("SkipArgs is not valid on functions used in expressions"); //for(int j=1;j<smt.Length;j++) smt[j-1]=smt[j]; //Array.Resize<Token>(ref smt, smt.Length-1); smt=new Token[0]; Emit(0); return; } if(smt.Length==1) { if(fs.requiredArgs>0) AddError("Not enough arguments to function"); if(fs.args.Length>0) Emit(2); Emit(0); smt=new Token[0]; return; } if(fs.args.Length==0) { Emit(0); for(int j=1;j<smt.Length;j++) smt[j-1]=smt[j]; Array.Resize<Token>(ref smt, smt.Length-1); return; } long pos=bw.BaseStream.Length; ushort argcount=0; Emit(0); Emit(0); int i=0; bool lastwasref=false; while(true) { i++; if(i==smt.Length) { if(argcount<fs.requiredArgs) AddError("Not enough arguments to function. Expected "+fs.requiredArgs); smt=new Token[0]; break; } if(smt[i].type==TokenType.Symbol) { if(smt[i].IsSymbol(".")&&lastwasref) { if(i<smt.Length-1&&farVars.ContainsKey(smt[i-1].token)) { i++; EmitByte(0x73); Dictionary<string, ushort> vars=farVars[smt[i-2].token]; if(!vars.ContainsKey(smt[i].token)) AddError("Reference '"+smt[i-2].utoken+"' has no variable called '"+smt[i].utoken+"'"); else Emit(vars[smt[i].token]); continue; } } else if(smt[i].IsSymbol("-")&&(!expression||(argcount<fs.requiredArgs))) { if(i<smt.Length-1&&(smt[i+1].type==TokenType.Integer||smt[i+1].type==TokenType.Float)) { smt[i+1]=new Token(smt[i+1].type, "-"+smt[i+1].token); continue; } } if(expression) { if(argcount<fs.requiredArgs) AddError("Not enough arguments to function. Expected "+fs.requiredArgs); for(int j=i;j<smt.Length;j++) smt[j-i]=smt[j]; Array.Resize<Token>(ref smt, smt.Length-i); break; } else AddError("Unexpected symbol '"+smt[i].token+"' in function arguments"); } if(argcount==fs.args.Length) AddError("Too many arguments given to function. Expected "+fs.args.Length); argcount++; lastwasref=false; switch(fs.args[argcount-1]) { case VarType.Axis: switch(smt[i].token) { case "x": EmitByte((byte)'X'); continue; case "y": EmitByte((byte)'Y'); continue; case "z": EmitByte((byte)'Z'); continue; default: AddError("Expected 'x', 'y' or 'z'"); continue; } case VarType.Enum: if(smt[i].type==TokenType.Integer) { Emit(ushort.Parse(smt[i].token)); } else { Dictionary<string, ushort> Enum=enumList[fs.reftypes[argcount-1]]; if(!Enum.ContainsKey(smt[i].token)) { AddError("'"+smt[i].token+"' is not a valid entry of the enum '"+fs.reftypes[argcount-1]+"'"); } else { Emit(Enum[smt[i].token]); } } continue; case VarType.Short: if(smt[i].type!=TokenType.Integer) { AddError("Expected integer argument"); } else { Emit(ushort.Parse(smt[i].token)); } continue; case VarType.String: Emit((ushort)smt[i].token.Length); bw.Write(System.Text.Encoding.Default.GetBytes(smt[i].token)); continue; } switch(smt[i].type) { case TokenType.edid: if(i==smt.Length-1||!smt[i+1].IsSymbol(".")) { if(fs.args[argcount-1]!=VarType.Ref) AddError("Invalid argument "+i+" to function. Expected "+fs.args[argcount-1].ToString()); if(fs.reftypes[argcount-1]!=null&&fs.reftypes[argcount-1]!=edidList[smt[i].token].Value) { AddError("Invalid record type at argument "+i+" of function. Expected "+fs.reftypes[argcount-1]); } } EmitRefLabel(smt[i], RefType.Expression); lastwasref=true; break; case TokenType.Local: LocalVar vt=locals[smt[i].token]; switch(vt.type) { case VarType.Int: if(fs.args[argcount-1]!=VarType.Float&&fs.args[argcount-1]!=VarType.Int) AddError("Invalid argument "+i+" to function. Expected "+fs.args[argcount-1].ToString()); EmitByte(0x73); Emit((ushort)locals[smt[i].token].index); break; case VarType.Float: if(fs.args[argcount-1]!=VarType.Float&&fs.args[argcount-1]!=VarType.Int) AddError("Invalid argument "+i+" to function. Expected "+fs.args[argcount-1].ToString()); EmitByte(0x66); Emit((ushort)locals[smt[i].token].index); break; case VarType.Ref: if(fs.args[argcount-1]!=VarType.Ref) AddError("Invalid argument "+i+" to function. Expected "+fs.args[argcount-1].ToString()); EmitRefLabel(smt[i], RefType.Expression); break; } break; case TokenType.Global: if(fs.args[argcount-1]!=VarType.Float&&fs.args[argcount-1]!=VarType.Int) AddError("Invalid argument "+i+" to function. Expected "+fs.args[argcount-1].ToString()); EmitRefLabel(smt[i], RefType.Expression); break; case TokenType.Integer: if(fs.args[argcount-1]==VarType.Float) goto case TokenType.Float; if(fs.args[argcount-1]!=VarType.Int) AddError("Invalid argument "+i+" to function. Expected "+fs.args[argcount-1].ToString()); EmitByte(0x6e); bw.Write(int.Parse(smt[i].token)); break; case TokenType.Float: if(fs.args[argcount-1]!=VarType.Float&&fs.args[argcount-1]!=VarType.Int) AddError("Invalid argument "+i+" to function. Expected "+fs.args[argcount-1].ToString()); EmitByte(0x7a); bw.Write(double.Parse(smt[i].token)); break; default: AddError("Expected <global>|<local>|<constant>"); return; } } for(int j=0;j<fs.paddingbytes;j++) EmitByte(0); bw.BaseStream.Position=pos; Emit((ushort)(bw.BaseStream.Length-(pos+2))); Emit(argcount); bw.BaseStream.Position=bw.BaseStream.Length; }
private static void EmitRefLabel(Token t, RefType type) { if(t.type==TokenType.Global) { EmitByte(0x47); } else { switch(type) { case RefType.Standard: Emit(0x1c); break; case RefType.Expression: EmitByte(0x72); break; case RefType.Standalone: EmitByte(0x5a); break; } } if(t.type==TokenType.Local) { LocalVar var=locals[t.token]; if(var.refid==0) AddError("Variable was not of type ref"); else Emit((ushort)var.refid); } else if(t.type==TokenType.edid||t.type==TokenType.Global) { if(!edidRefs.ContainsKey(t.token)) { SubRecord sr=new SubRecord(); sr.Name="SCRO"; if(t.type==TokenType.edid) sr.SetData(TypeConverter.i2h(edidList[t.token].Key)); else sr.SetData(TypeConverter.i2h(globals[t.token])); r.AddRecord(sr); refcount++; edidRefs[t.token]=(ushort)refcount; } Emit(edidRefs[t.token]); } else { AddError("Expected ref variable or edid"); } }
private static void EmitExpressionValue(Token t, Queue<Token> smt, ExpressionType type) { EmitByte(0x20); bool hadRef=false; switch(t.type) { case TokenType.edid: if(smt.Count>0&&smt.Peek().IsSymbol(".")) { EmitRefLabel(t, RefType.Expression); smt.Dequeue(); if(smt.Count==0) throw new ExpressionParseException("Unexpected end of line"); if(farVars.ContainsKey(t.token)) { Dictionary<string, ushort> fars=farVars[t.token]; t=smt.Dequeue(); if(fars.ContainsKey(t.token)) { EmitByte(0x73); Emit(fars[t.token]); break; } } else t=smt.Dequeue(); hadRef=true; goto case TokenType.Function; } else { if(type==ExpressionType.Numeric) AddError("Reference type not valid here"); EmitRefLabel(t, RefType.Standalone); } break; case TokenType.Local: LocalVar lv=locals[t.token]; if(lv.type==VarType.Ref&&smt.Count>0&&smt.Peek().IsSymbol(".")) goto case TokenType.edid; if(lv.type==VarType.Ref&&type==ExpressionType.Numeric) AddError("Reference type not valid here"); if(lv.type!=VarType.Ref&&type==ExpressionType.Ref) AddError("A reference assignment must consist of a single edid or function"); if(lv.type==VarType.Int) { EmitByte(0x73); } else { EmitByte(0x66); } Emit((ushort)lv.index); break; case TokenType.Global: if(type==ExpressionType.Ref) AddError("A reference assignment must consist of a single edid or function"); EmitRefLabel(t, RefType.Expression); break; case TokenType.Float: case TokenType.Integer: if(type==ExpressionType.Ref&&t.token!="0") AddError("A reference assignment must consist of a single edid or function"); bw.Write(System.Text.Encoding.ASCII.GetBytes(t.token)); break; case TokenType.Function: //FunctionSig fs=functionList[t.token]; //if(fs.requiredArgs!=fs.args.Length) throw new ExpressionParseException("functions with variable argument count cannot be used in expressions"); //if(fs.ret==VarType.None) throw new ExpressionParseException("Functions with no return type cannot be used in expressions"); //if(smt.Count<fs.args.Length) throw new ExpressionParseException("Not enough parameters to function"); Token[] args=new Token[smt.Count+1]; args[0]=t; for(int i=1;i<args.Length;i++) args[i]=smt.Dequeue(); EmitFunctionCall(ref args, true, hadRef, type==ExpressionType.Ref); for(int i=0;i<args.Length;i++) smt.Enqueue(args[i]); break; default: AddError("Expected <local>|<global>|<number>|<function>"); break; } }
private static void EmitExpression(Token[] smt, ExpressionType type) { long pos=bw.BaseStream.Length; Emit(0); try { EmitExpression2(new Queue<Token>(smt), int.MaxValue, false, type); } catch(ExpressionParseException ex) { AddError(ex.Message); } bw.BaseStream.Position=pos; Emit((ushort)(bw.BaseStream.Length-(pos+2))); bw.BaseStream.Position=bw.BaseStream.Length; }
private static void EmitBegin(Token[] smt) { Emit(0x10); if(!blockList.ContainsKey(smt[1].token)) { AddError("Unknown block type"); EmitLong(0); EmitLong(0); return; } FunctionSig fs=blockList[smt[1].token]; long pos=bw.BaseStream.Length; Emit(0); Emit(fs.opcode); EmitLong(0); if(smt.Length>fs.args.Length+2) AddError("Too many arguments to 'begin' block"); //for(int i=0;i<fs.paddingbytes;i++) EmitByte(0); if(fs.args.Length>0) { Emit((ushort)(smt.Length-2)); for(int i=2;i<smt.Length;i++) { switch(fs.args[i-2]) { case VarType.Short: if(smt[i].type!=TokenType.Integer) AddError("Block argument: Expected short"); else Emit(ushort.Parse(smt[i].token)); break; case VarType.Int: if(smt[i].type!=TokenType.Integer) AddError("Block argument: Expected integer"); else { EmitByte(0x73); EmitLong(uint.Parse(smt[i].token)); } break; case VarType.Ref: if(smt[i].type!=TokenType.edid) AddError("Block argument: Expected edid"); else { EmitRefLabel(smt[i], RefType.Expression); } break; default: AddError("Sanity check failed. VarType of block argument was invalid"); break; } } } bw.BaseStream.Position=pos; Emit((ushort)(bw.BaseStream.Length-(pos+2))); bw.BaseStream.Position=bw.BaseStream.Length; }
public LocalVar(int index, Token t) { this.index=index; switch(t.keyword) { case Keywords.Int: type=VarType.Int; break; case Keywords.Float: type=VarType.Float; break; case Keywords.Ref: type=VarType.Ref; break; default: throw new Exception("Should never happen: Invalid type passed to local variable constructor"); } }
private static Token[] TrimStatement(Token[] smt, int size) { Token[] smt2=new Token[smt.Length-size]; for(int i=0;i<smt2.Length;i++) smt2[i]=smt[i+size]; return smt2; }