Compare commits

...

13 Commits

Author SHA1 Message Date
Rairii
54404a1fa6 asm: fix the case for non-exported function that returns a value 2025-04-11 13:04:58 +01:00
Rairii
301c583ce2 asm: fix referencing arguments where function is not exported and argument list may be unknown 2025-04-11 12:59:29 +01:00
Rairii
2dca25d95b lib: fix creating an argument variable where function is not exported therefore arguments are unknown 2025-04-11 12:58:44 +01:00
Rairii
7202da81ea asm: fix culture issues by setting current thread culture when inside the assembler 2025-04-11 12:29:37 +01:00
Rairii
0f6e7a5bcb lib: use single static cultureinfo instead of allocating every time 2025-04-11 12:28:50 +01:00
Rairii
056cd7a9a1 tests: add test for extended floating point variables 2025-04-11 12:05:47 +01:00
Rairii
1767aeec9f tests: fix compilation with vs2022 2025-04-11 11:59:42 +01:00
Rairii
82ddafd61e ifpslib: fix extended float for certain regions
ExtF80 always uses '.' for number decimal separator, ensure that english culture info is used to match it.
2025-04-06 19:47:12 +01:00
zc
adc9a2dde1 cc: add timer for each stage (via compile time config)
cc: optimise lexer for speed (~10x speed improvement)
cc: implement OperatorParser class as per TODO in original codebase (seems refactoring chains of parser-combinators leads to at least SOME speed improvement)
2023-07-11 17:57:57 +01:00
zc
b20d5d88b5 libifps: allow Instruction.Create(OpCode, Operand, Operand, Operand) to be used for InlineCmpValueType too
libasm: allow generic operand to be used for InlineCmpValueType op2, as well as type
tests: refactor and fix
tests: add test for InlineCmpValueType on type and variable
2023-03-31 13:19:31 +01:00
zc
8aea82c678 libifps: fix loading and saving op2 for InlineCmpValueType (is instruction)
libifps: document is instruction better
libifps: document InlineCmpValueType better
2023-03-31 12:52:45 +01:00
zc
6feeac38f7 Revert "libifps: allow reading invalid operands"
This reverts commit 58e78597e7.
2023-03-31 12:36:20 +01:00
zc
58e78597e7 libifps: allow reading invalid operands
this should allow disassembling some malware samples (etc)
2023-03-31 12:27:42 +01:00
25 changed files with 1667 additions and 3357 deletions

View File

@ -9,6 +9,8 @@ using IFPSLib.Emit.FDecl;
using System.Runtime.InteropServices;
using System.Collections;
using System.ComponentModel;
using System.Globalization;
using System.Threading;
namespace IFPSAsmLib
{
@ -98,6 +100,7 @@ namespace IFPSAsmLib
public static class Assembler
{
private static readonly CultureInfo s_Culture = new CultureInfo("en");
private static IEnumerable<ParsedBody> OfType(this IEnumerable<ParsedBody> self, ElementParentType type)
{
return self.Where(x => x.Element.ParentType == type);
@ -534,6 +537,16 @@ namespace IFPSAsmLib
return function.CreateArgumentVariable(i);
}
value = value.ToLower();
// For a non-exported function, allow use of hardcoded Argx to refer to unknown arguments
if (!function.Exported)
{
if (value.StartsWith(Constants.VARIABLE_ARG_PREFIX)) {
if (!int.TryParse(value.Substring(Constants.VARIABLE_ARG_PREFIX.Length), out var argIdx)) return null;
if (function.ReturnArgument == null) argIdx--;
if (argIdx < 0) return null;
return function.CreateArgumentVariable(argIdx);
}
}
if (value == Constants.VARIABLE_RET) return function.CreateReturnVariable();
if (!value.StartsWith(Constants.VARIABLE_LOCAL_PREFIX)) return null;
if (!int.TryParse(value.Substring(Constants.VARIABLE_LOCAL_PREFIX.Length), out var idx)) return null;
@ -693,11 +706,20 @@ namespace IFPSAsmLib
var op1 = ParseOperandValue(next, function, types, globals, functions, aliases, defines);
if (next.Next == null) next.ThrowInvalid();
next = next.Next;
Operand op2 = null;
try
{
op2 = ParseOperandValue(next, function, types, globals, functions, aliases, defines);
}
catch
{
next.ExpectValidName();
next.EnsureNoNextChild();
if (!types.TryGetValue(next.Value, out var typeOp)) next.ThrowInvalid(string.Format("In function \"{0}\": Referenced unknown type", function.Name));
op2 = Operand.Create(typeOp);
}
if (next.Next != null) next.Next.ThrowInvalid();
return Instruction.Create(opcode, op0, op1, typeOp);
return Instruction.Create(opcode, op0, op1, op2);
}
case OperandType.InlineTypeVariable:
{
@ -847,7 +869,7 @@ namespace IFPSAsmLib
}
}
public static Script Assemble(List<ParsedBody> parsed)
private static Script AssembleImpl(List<ParsedBody> parsed)
{
int version = Script.VERSION_HIGHEST;
{
@ -930,6 +952,21 @@ namespace IFPSAsmLib
return ret;
}
public static Script Assemble(List<ParsedBody> parsed)
{
// Set the current thread's culture to english when assembling, to ensure float/double/decimal parsing works correctly.
var currentCulture = Thread.CurrentThread.CurrentCulture;
Thread.CurrentThread.CurrentCulture = s_Culture;
try
{
return AssembleImpl(parsed);
}
finally
{
Thread.CurrentThread.CurrentCulture = currentCulture;
}
}
public static Script Assemble(string str) => Assemble(Parser.Parse(str));
}
}

View File

@ -71,6 +71,7 @@ namespace IFPSAsmLib
internal const string VARIABLE_RET = "retval";
internal const string VARIABLE_LOCAL_PREFIX = "var";
internal const string VARIABLE_ARG_PREFIX = "arg";
internal const string LABEL_NULL = "null";
}

Binary file not shown.

View File

@ -0,0 +1,820 @@
.version 23
.entry !MAIN
.type primitive(Pointer) Pointer
.type primitive(U32) U32
.type primitive(Variant) Variant
.type primitive(PChar) PChar
.type primitive(Currency) Currency
.type primitive(Extended) Extended
.type primitive(Double) Double
.type primitive(Single) Single
.type primitive(S64) S64
.type primitive(String) String
.type primitive(U32) U32_2
.type primitive(S32) S32
.type primitive(S16) S16
.type primitive(U16) U16
.type primitive(S8) S8
.type primitive(String) String_2
.type primitive(UnicodeString) UnicodeString
.type primitive(UnicodeString) UnicodeString_2
.type primitive(String) String_3
.type primitive(UnicodeString) UnicodeString_3
.type primitive(WideString) WideString
.type primitive(WideChar) WideChar
.type primitive(WideChar) WideChar_2
.type primitive(Char) Char
.type primitive(U8) U8
.type primitive(U16) U16_2
.type primitive(U32) U32_3
.type(export) primitive(U8) BOOLEAN
.type primitive(U8) U8_2
.type(export) class(TBUTTON) TBUTTON
.type record(U32_2,S32,S32,S32,U32_2,U32_2,U16,U16,U16,U16,U16,S32,S32,U32_2,U32_2,PChar,PChar,S32,S32) Type30
.type record(S32,PChar,PChar,PChar,U32_2) Type31
.type record(S32,S32) Type32
.type(export) record(S32,S32,S32,S32) TRECT
.type record(U32_2,U32_2,TRECT,TRECT,Type32) Type34
.type(export) class(TWIZARDFORM) TWIZARDFORM
.type(export) class(TRICHEDITVIEWER) TRICHEDITVIEWER
.type(export) class(TOBJECT) TOBJECT
.type(export) class(TNEWRADIOBUTTON) TNEWRADIOBUTTON
.type(export) class(TCONTROL) TCONTROL
.type(export) class(TCOMPONENT) TCOMPONENT
.type(export) class(TNEWNOTEBOOKPAGE) TNEWNOTEBOOKPAGE
.type(export) funcptr(void(__in)) TNOTIFYEVENT
.type(export) class(TWINCONTROL) TWINCONTROL
.global TBUTTON Global0
.function(export) void !MAIN()
ret
.function(import) external dll("gdi32.dll","GetDeviceCaps") __stdcall returnsval gdi32.dll!GetDeviceCaps(__in __unknown,__in __unknown)
.function(import) external dll("comdlg32.dll","PrintDlgA") __stdcall returnsval comdlg32.dll!PrintDlgA(__out __unknown)
.function(import) external dll("gdi32.dll","DeleteDC") __stdcall returnsval gdi32.dll!DeleteDC(__in __unknown)
.function(import) external dll("gdi32.dll","StartDocA") __stdcall returnsval gdi32.dll!StartDocA(__in __unknown,__in __unknown)
.function(import) external dll("gdi32.dll","StartPage") __stdcall returnsval gdi32.dll!StartPage(__in __unknown)
.function(import) external dll("gdi32.dll","EndPage") __stdcall returnsval gdi32.dll!EndPage(__in __unknown)
.function(import) external dll("gdi32.dll","EndDoc") __stdcall returnsval gdi32.dll!EndDoc(__in __unknown)
.function(import) external dll("gdi32.dll","AbortDoc") __stdcall returnsval gdi32.dll!AbortDoc(__in __unknown)
.function(import) external dll("user32.dll","SendMessageA") __stdcall returnsval user32.dll!SendMessageA(__in __unknown,__in __unknown,__in __unknown,__out __unknown)
.function(import) external dll("user32.dll","SendMessageA") __stdcall returnsval user32.dll!SendMessageA_2(__in __unknown,__in __unknown,__in __unknown,__out __unknown)
.function(export) BOOLEAN ISUPGRADE()
pushtype UnicodeString_2 ; StackCount = 1
pushtype TWIZARDFORM ; StackCount = 2
pushvar Var2 ; StackCount = 3
call WIZARDFORM
pop ; StackCount = 2
pushvar Var1 ; StackCount = 3
call TWIZARDFORM->PREVAPPDIR
pop ; StackCount = 2
pop ; StackCount = 1
ne RetVal, Var1, UnicodeString_3("")
ret
.function(import) external internal returnsval WIZARDFORM()
.function(import) external class(TWIZARDFORM, PREVAPPDIR) __pascal void TWIZARDFORM->PREVAPPDIR(__in __unknown,__in __unknown)
.function(export) BOOLEAN ISPORTABLE()
pushtype UnicodeString_2 ; StackCount = 1
pushtype UnicodeString_2 ; StackCount = 2
assign Var2, UnicodeString_3("{param:portable|0}")
pushvar Var1 ; StackCount = 3
call EXPANDCONSTANT
pop ; StackCount = 2
pop ; StackCount = 1
eq RetVal, Var1, WideChar_2("1")
pop ; StackCount = 0
ret
.function(import) external internal returnsval EXPANDCONSTANT(__in __unknown)
.function(export) BOOLEAN SELECTPRINTER(__out Type30 Arg1)
pushtype S32 ; StackCount = 1
pushtype Type30 ; StackCount = 2
assign Var2, Arg1
pushvar Var1 ; StackCount = 3
call SIZEOF
pop ; StackCount = 2
pop ; StackCount = 1
assign Arg1[0], Var1
pop ; StackCount = 0
pushtype TWIZARDFORM ; StackCount = 1
pushvar Var1 ; StackCount = 2
call WIZARDFORM
pop ; StackCount = 1
pushvar Arg1[1] ; StackCount = 2
call TWINCONTROL->HANDLE
pop ; StackCount = 1
pop ; StackCount = 0
assign Arg1[2], S32(0)
assign Arg1[3], S32(0)
assign Arg1[4], S32(0)
assign Arg1[5], S32(262404)
assign Arg1[6], S32(0)
assign Arg1[7], S32(0)
assign Arg1[8], S32(0)
assign Arg1[9], S32(0)
assign Arg1[10], S32(0)
assign Arg1[11], S32(0)
assign Arg1[12], S32(0)
assign Arg1[13], S32(0)
assign Arg1[14], S32(0)
assign Arg1[15], UnicodeString_3("")
assign Arg1[16], UnicodeString_3("")
assign Arg1[17], S32(0)
assign Arg1[18], S32(0)
pushtype Pointer ; StackCount = 1
setptr Var1, Arg1
pushvar RetVal ; StackCount = 2
call comdlg32.dll!PrintDlgA
pop ; StackCount = 1
pop ; StackCount = 0
ret
.function(import) external internal returnsval SIZEOF()
.function(import) external class(TWINCONTROL, HANDLE) __pascal void TWINCONTROL->HANDLE(__in __unknown,__in __unknown)
.function(export) BOOLEAN PRINTRICHEDIT(__in Type30 Arg1,__in TRICHEDITVIEWER Arg2,__in UnicodeString_2 Arg3,__in Double Arg4,__in Double Arg5,__in Double Arg6,__in Double Arg7)
pushtype Type31 ; StackCount = 1
pushtype Type34 ; StackCount = 2
pushtype U32_2 ; StackCount = 3
pushtype S32 ; StackCount = 4
pushtype S32 ; StackCount = 5
pushtype S32 ; StackCount = 6
pushtype S32 ; StackCount = 7
pushtype S32 ; StackCount = 8
pushtype S32 ; StackCount = 9
pushtype S32 ; StackCount = 10
pushtype S32 ; StackCount = 11
pushtype S32 ; StackCount = 12
pushtype S32 ; StackCount = 13
pushtype S32 ; StackCount = 14
assign Var3, Arg1[4]
pushtype TRICHEDITVIEWER ; StackCount = 15
assign Var15, Arg2
pushvar Var4 ; StackCount = 16
call TWINCONTROL->HANDLE
pop ; StackCount = 15
pop ; StackCount = 14
pushtype Type31 ; StackCount = 15
assign Var15, Var1
pushvar Var1[0] ; StackCount = 16
call SIZEOF
pop ; StackCount = 15
pop ; StackCount = 14
assign Var1[1], Arg3
assign Var1[2], UnicodeString_3("")
assign Var1[3], UnicodeString_3("")
assign Var1[4], S32(0)
pushtype BOOLEAN ; StackCount = 15
pushtype S32 ; StackCount = 16
pushtype Type31 ; StackCount = 17
assign Var17, Var1
pushtype U32_2 ; StackCount = 18
assign Var18, Var3
pushvar Var16 ; StackCount = 19
call gdi32.dll!StartDocA
pop ; StackCount = 18
pop ; StackCount = 17
pop ; StackCount = 16
le Var15, Var16, S32(0)
pop ; StackCount = 15
sfz Var15
pop ; StackCount = 14
jf loc_137
ret
loc_137:
pushtype S32 ; StackCount = 15
assign Var15, S32(88)
pushtype U32_2 ; StackCount = 16
assign Var16, Var3
pushvar Var8 ; StackCount = 17
call gdi32.dll!GetDeviceCaps
pop ; StackCount = 16
pop ; StackCount = 15
pop ; StackCount = 14
pushtype S32 ; StackCount = 15
assign Var15, S32(90)
pushtype U32_2 ; StackCount = 16
assign Var16, Var3
pushvar Var9 ; StackCount = 17
call gdi32.dll!GetDeviceCaps
pop ; StackCount = 16
pop ; StackCount = 15
pop ; StackCount = 14
pushtype S32 ; StackCount = 15
assign Var15, S32(8)
pushtype U32_2 ; StackCount = 16
assign Var16, Var3
pushvar Var6 ; StackCount = 17
call gdi32.dll!GetDeviceCaps
pop ; StackCount = 16
pop ; StackCount = 15
pop ; StackCount = 14
mul Var6, S32(1440)
div Var6, Var8
pushtype S32 ; StackCount = 15
assign Var15, S32(10)
pushtype U32_2 ; StackCount = 16
assign Var16, Var3
pushvar Var7 ; StackCount = 17
call gdi32.dll!GetDeviceCaps
pop ; StackCount = 16
pop ; StackCount = 15
pop ; StackCount = 14
mul Var7, S32(1440)
div Var7, Var9
pushtype S32 ; StackCount = 15
assign Var15, S32(110)
pushtype U32_2 ; StackCount = 16
assign Var16, Var3
pushvar Var10 ; StackCount = 17
call gdi32.dll!GetDeviceCaps
pop ; StackCount = 16
pop ; StackCount = 15
pop ; StackCount = 14
mul Var10, S32(1440)
div Var10, Var8
pushtype S32 ; StackCount = 15
assign Var15, S32(111)
pushtype U32_2 ; StackCount = 16
assign Var16, Var3
pushvar Var11 ; StackCount = 17
call gdi32.dll!GetDeviceCaps
pop ; StackCount = 16
pop ; StackCount = 15
pop ; StackCount = 14
mul Var11, S32(1440)
div Var11, Var9
pushtype S32 ; StackCount = 15
assign Var15, S32(112)
pushtype U32_2 ; StackCount = 16
assign Var16, Var3
pushvar Var12 ; StackCount = 17
call gdi32.dll!GetDeviceCaps
pop ; StackCount = 16
pop ; StackCount = 15
pop ; StackCount = 14
mul Var12, S32(1440)
div Var12, Var8
pushtype S32 ; StackCount = 15
assign Var15, S32(113)
pushtype U32_2 ; StackCount = 16
assign Var16, Var3
pushvar Var13 ; StackCount = 17
call gdi32.dll!GetDeviceCaps
pop ; StackCount = 16
pop ; StackCount = 15
pop ; StackCount = 14
mul Var13, S32(1440)
div Var13, Var9
pushtype Extended ; StackCount = 15
pushtype Double ; StackCount = 16
assign Var16, Arg4
mul Var16, S32(1440)
assign Var15, Var16
pop ; StackCount = 15
pushvar Var5 ; StackCount = 16
call ROUND
pop ; StackCount = 15
pop ; StackCount = 14
sub Var5, Var12
pushtype BOOLEAN ; StackCount = 15
lt Var15, Var5, S32(0)
sfz Var15
pop ; StackCount = 14
jf loc_3ef
assign Var5, S32(0)
loc_3ef:
pushtype Pointer ; StackCount = 15
setptr Var15, Var2
setptr Var15, Var15[2]
setptr Var15, Var15[0]
assign Var15, Var5
pop ; StackCount = 14
pushtype Extended ; StackCount = 15
pushtype Double ; StackCount = 16
assign Var16, Arg5
mul Var16, S32(1440)
assign Var15, Var16
pop ; StackCount = 15
pushvar Var5 ; StackCount = 16
call ROUND
pop ; StackCount = 15
pop ; StackCount = 14
sub Var5, Var13
pushtype BOOLEAN ; StackCount = 15
lt Var15, Var5, S32(0)
sfz Var15
pop ; StackCount = 14
jf loc_4a9
assign Var5, S32(0)
loc_4a9:
pushtype Pointer ; StackCount = 15
setptr Var15, Var2
setptr Var15, Var15[2]
setptr Var15, Var15[1]
assign Var15, Var5
pop ; StackCount = 14
assign Var5, Var10
pushtype S32 ; StackCount = 15
pushtype Extended ; StackCount = 16
pushtype Double ; StackCount = 17
assign Var17, Arg6
mul Var17, S32(1440)
assign Var16, Var17
pop ; StackCount = 16
pushvar Var15 ; StackCount = 17
call ROUND
pop ; StackCount = 16
pop ; StackCount = 15
sub Var5, Var15
pop ; StackCount = 14
sub Var5, Var12
pushtype BOOLEAN ; StackCount = 15
gt Var15, Var5, Var6
sfz Var15
pop ; StackCount = 14
jf loc_578
assign Var5, Var6
loc_578:
pushtype Pointer ; StackCount = 15
setptr Var15, Var2
setptr Var15, Var15[2]
setptr Var15, Var15[2]
assign Var15, Var5
pop ; StackCount = 14
assign Var5, Var11
pushtype S32 ; StackCount = 15
pushtype Extended ; StackCount = 16
pushtype Double ; StackCount = 17
assign Var17, Arg7
mul Var17, S32(1440)
assign Var16, Var17
pop ; StackCount = 16
pushvar Var15 ; StackCount = 17
call ROUND
pop ; StackCount = 16
pop ; StackCount = 15
sub Var5, Var15
pop ; StackCount = 14
sub Var5, Var13
pushtype BOOLEAN ; StackCount = 15
gt Var15, Var5, Var7
sfz Var15
pop ; StackCount = 14
jf loc_647
assign Var5, Var7
loc_647:
pushtype Pointer ; StackCount = 15
setptr Var15, Var2
setptr Var15, Var15[2]
setptr Var15, Var15[3]
assign Var15, Var5
pop ; StackCount = 14
assign Var2[3], Var2[2]
assign Var2[0], Var3
assign Var2[1], Var3
pushtype S32 ; StackCount = 15
pushtype S32 ; StackCount = 16
assign Var16, S32(-1)
pushtype S32 ; StackCount = 17
assign Var17, S32(0)
pushtype S32 ; StackCount = 18
assign Var18, S32(177)
pushtype S32 ; StackCount = 19
assign Var19, Var4
pushvar Var15 ; StackCount = 20
call SENDMESSAGE
pop ; StackCount = 19
pop ; StackCount = 18
pop ; StackCount = 17
pop ; StackCount = 16
pop ; StackCount = 15
pop ; StackCount = 14
pushtype S32 ; StackCount = 15
pushtype Pointer ; StackCount = 16
setptr Var16, Var2[4]
pushtype S32 ; StackCount = 17
assign Var17, S32(0)
pushtype S32 ; StackCount = 18
assign Var18, S32(1076)
pushtype S32 ; StackCount = 19
assign Var19, Var4
pushvar Var15 ; StackCount = 20
call user32.dll!SendMessageA
pop ; StackCount = 19
pop ; StackCount = 18
pop ; StackCount = 17
pop ; StackCount = 16
pop ; StackCount = 15
pop ; StackCount = 14
assign RetVal, BOOLEAN(1)
pushtype BOOLEAN ; StackCount = 15
loc_787:
pushtype BOOLEAN ; StackCount = 16
pushtype Pointer ; StackCount = 17
setptr Var17, Var2
setptr Var17, Var17[4]
setptr Var17, Var17[0]
pushtype Pointer ; StackCount = 18
setptr Var18, Var2
setptr Var18, Var18[4]
setptr Var18, Var18[1]
lt Var16, Var17, Var18
pop ; StackCount = 17
pop ; StackCount = 16
assign Var15, Var16
pop ; StackCount = 15
jz loc_81d, Var15
and Var15, RetVal
loc_81d:
jz loc_9cf, Var15
pushtype S32 ; StackCount = 16
pushtype U32_2 ; StackCount = 17
assign Var17, Var3
pushvar Var16 ; StackCount = 18
call gdi32.dll!StartPage
pop ; StackCount = 17
pop ; StackCount = 16
gt RetVal, Var16, S32(0)
pop ; StackCount = 15
pushtype BOOLEAN ; StackCount = 16
assign Var16, RetVal
setz Var16
sfz Var16
pop ; StackCount = 15
jf loc_887
jump loc_9cf
loc_887:
pushtype Pointer ; StackCount = 16
setptr Var16, Var2
pushtype S32 ; StackCount = 17
assign Var17, S32(-1)
pushtype S32 ; StackCount = 18
assign Var18, S32(1081)
pushtype S32 ; StackCount = 19
assign Var19, Var4
pushvar Var14 ; StackCount = 20
call user32.dll!SendMessageA_2
pop ; StackCount = 19
pop ; StackCount = 18
pop ; StackCount = 17
pop ; StackCount = 16
pop ; StackCount = 15
pushtype BOOLEAN ; StackCount = 16
pushtype BOOLEAN ; StackCount = 17
pushtype Pointer ; StackCount = 18
setptr Var18, Var2
setptr Var18, Var18[4]
setptr Var18, Var18[0]
le Var17, Var14, Var18
pop ; StackCount = 17
assign Var16, Var17
pop ; StackCount = 16
sfz Var16
pop ; StackCount = 15
jf loc_958
assign RetVal, BOOLEAN(0)
jump loc_9cf
jump loc_9ca
loc_958:
pushtype Pointer ; StackCount = 16
setptr Var16, Var2
setptr Var16, Var16[4]
setptr Var16, Var16[0]
assign Var16, Var14
pop ; StackCount = 15
pushtype S32 ; StackCount = 16
pushtype U32_2 ; StackCount = 17
assign Var17, Var3
pushvar Var16 ; StackCount = 18
call gdi32.dll!EndPage
pop ; StackCount = 17
pop ; StackCount = 16
gt RetVal, Var16, S32(0)
pop ; StackCount = 15
loc_9ca:
jump loc_787
loc_9cf:
pop ; StackCount = 14
pushtype S32 ; StackCount = 15
pushtype S32 ; StackCount = 16
assign Var16, S32(0)
pushtype S32 ; StackCount = 17
assign Var17, S32(0)
pushtype S32 ; StackCount = 18
assign Var18, S32(1081)
pushtype S32 ; StackCount = 19
assign Var19, Var4
pushvar Var15 ; StackCount = 20
call SENDMESSAGE
pop ; StackCount = 19
pop ; StackCount = 18
pop ; StackCount = 17
pop ; StackCount = 16
pop ; StackCount = 15
pop ; StackCount = 14
pushtype BOOLEAN ; StackCount = 15
assign Var15, RetVal
sfz Var15
pop ; StackCount = 14
jf loc_a77
pushtype S32 ; StackCount = 15
pushtype U32_2 ; StackCount = 16
assign Var16, Var3
pushvar Var15 ; StackCount = 17
call gdi32.dll!EndDoc
pop ; StackCount = 16
pop ; StackCount = 15
pop ; StackCount = 14
jump loc_a9a
loc_a77:
pushtype S32 ; StackCount = 15
pushtype U32_2 ; StackCount = 16
assign Var16, Var3
pushvar Var15 ; StackCount = 17
call gdi32.dll!AbortDoc
pop ; StackCount = 16
pop ; StackCount = 15
pop ; StackCount = 14
loc_a9a:
ret
.function(import) external internal returnsval ROUND(__in __unknown)
.function(import) external internal returnsval SENDMESSAGE(__in __unknown,__in __unknown,__in __unknown,__in __unknown)
.function(export) void PRINTBUTTONCLICK(__in TOBJECT Arg1)
pushtype Type30 ; StackCount = 1
pushtype BOOLEAN ; StackCount = 2
pushtype Pointer ; StackCount = 3
setptr Var3, Var1
pushvar Var2 ; StackCount = 4
call SELECTPRINTER
pop ; StackCount = 3
pop ; StackCount = 2
setz Var2
sfz Var2
pop ; StackCount = 1
jf loc_3b
ret
loc_3b:
starteh loc_124, null, null, loc_14d
pushtype BOOLEAN ; StackCount = 2
pushtype Double ; StackCount = 3
assign Var3, Extended(0.50)
pushtype Double ; StackCount = 4
assign Var4, Extended(0.50)
pushtype Double ; StackCount = 5
assign Var5, Extended(0.50)
pushtype Double ; StackCount = 6
assign Var6, Extended(0.50)
pushtype UnicodeString_2 ; StackCount = 7
assign Var7, UnicodeString_3("License")
pushtype TRICHEDITVIEWER ; StackCount = 8
pushtype TWIZARDFORM ; StackCount = 9
pushvar Var9 ; StackCount = 10
call WIZARDFORM
pop ; StackCount = 9
pushvar Var8 ; StackCount = 10
call TWIZARDFORM->LICENSEMEMO
pop ; StackCount = 9
pop ; StackCount = 8
pushtype Type30 ; StackCount = 9
assign Var9, Var1
pushvar Var2 ; StackCount = 10
call PRINTRICHEDIT
pop ; StackCount = 9
pop ; StackCount = 8
pop ; StackCount = 7
pop ; StackCount = 6
pop ; StackCount = 5
pop ; StackCount = 4
pop ; StackCount = 3
pop ; StackCount = 2
pop ; StackCount = 1
endtry
loc_124:
pushtype BOOLEAN ; StackCount = 2
pushtype U32_2 ; StackCount = 3
assign Var3, Var1[4]
pushvar Var2 ; StackCount = 4
call gdi32.dll!DeleteDC
pop ; StackCount = 3
pop ; StackCount = 2
pop ; StackCount = 1
endfinally
loc_14d:
ret
.function(import) external class(TWIZARDFORM, LICENSEMEMO) __pascal void TWIZARDFORM->LICENSEMEMO(__in __unknown,__in __unknown)
.function(export) void ADJUSTPRINTBUTTON()
pushtype BOOLEAN ; StackCount = 1
pushtype TBUTTON ; StackCount = 2
assign Var2, Global0
pushvar Var1 ; StackCount = 3
call !ASSIGNED
pop ; StackCount = 2
pop ; StackCount = 1
sfz Var1
pop ; StackCount = 0
jf loc_138
pushtype S32 ; StackCount = 1
pushtype TRICHEDITVIEWER ; StackCount = 2
pushtype TWIZARDFORM ; StackCount = 3
pushvar Var3 ; StackCount = 4
call WIZARDFORM
pop ; StackCount = 3
pushvar Var2 ; StackCount = 4
call TWIZARDFORM->LICENSEMEMO
pop ; StackCount = 3
pop ; StackCount = 2
pushvar Var1 ; StackCount = 3
call TCONTROL->LEFT
pop ; StackCount = 2
pop ; StackCount = 1
pushtype S32 ; StackCount = 2
pushtype TRICHEDITVIEWER ; StackCount = 3
pushtype TWIZARDFORM ; StackCount = 4
pushvar Var4 ; StackCount = 5
call WIZARDFORM
pop ; StackCount = 4
pushvar Var3 ; StackCount = 5
call TWIZARDFORM->LICENSEMEMO
pop ; StackCount = 4
pop ; StackCount = 3
pushvar Var2 ; StackCount = 4
call TCONTROL->WIDTH
pop ; StackCount = 3
pop ; StackCount = 2
add Var1, Var2
pop ; StackCount = 1
pushtype S32 ; StackCount = 2
pushtype TBUTTON ; StackCount = 3
assign Var3, Global0
pushvar Var2 ; StackCount = 4
call TCONTROL->WIDTH
pop ; StackCount = 3
pop ; StackCount = 2
sub Var1, Var2
pop ; StackCount = 1
pushtype TBUTTON ; StackCount = 2
assign Var2, Global0
call TCONTROL->LEFT_2
pop ; StackCount = 1
pop ; StackCount = 0
pushtype S32 ; StackCount = 1
pushtype TNEWRADIOBUTTON ; StackCount = 2
pushtype TWIZARDFORM ; StackCount = 3
pushvar Var3 ; StackCount = 4
call WIZARDFORM
pop ; StackCount = 3
pushvar Var2 ; StackCount = 4
call TWIZARDFORM->LICENSEACCEPTEDRADIO
pop ; StackCount = 3
pop ; StackCount = 2
pushvar Var1 ; StackCount = 3
call TCONTROL->TOP
pop ; StackCount = 2
pop ; StackCount = 1
pushtype TBUTTON ; StackCount = 2
assign Var2, Global0
call TCONTROL->TOP_2
pop ; StackCount = 1
pop ; StackCount = 0
loc_138:
ret
.function(import) external internal returnsval !ASSIGNED(__in __unknown)
.function(import) external class(TCONTROL, LEFT) __pascal void TCONTROL->LEFT(__in __unknown,__in __unknown)
.function(import) external class(TCONTROL, WIDTH) __pascal void TCONTROL->WIDTH(__in __unknown,__in __unknown)
.function(import) external class(TCONTROL, LEFT, property) __pascal void TCONTROL->LEFT_2(__in __unknown,__in __unknown)
.function(import) external class(TWIZARDFORM, LICENSEACCEPTEDRADIO) __pascal void TWIZARDFORM->LICENSEACCEPTEDRADIO(__in __unknown,__in __unknown)
.function(import) external class(TCONTROL, TOP) __pascal void TCONTROL->TOP(__in __unknown,__in __unknown)
.function(import) external class(TCONTROL, TOP, property) __pascal void TCONTROL->TOP_2(__in __unknown,__in __unknown)
.function(export) void CREATEPRINTBUTTON()
pushtype TCOMPONENT ; StackCount = 1
pushtype TNEWNOTEBOOKPAGE ; StackCount = 2
pushtype TWIZARDFORM ; StackCount = 3
pushvar Var3 ; StackCount = 4
call WIZARDFORM
pop ; StackCount = 3
pushvar Var2 ; StackCount = 4
call TWIZARDFORM->LICENSEPAGE
pop ; StackCount = 3
pop ; StackCount = 2
assign Var1, Var2
pop ; StackCount = 1
pushtype U32_2 ; StackCount = 2
assign Var2, U32_2(29)
pushvar Global0 ; StackCount = 3
call TCONTROL->CREATE
pop ; StackCount = 2
pop ; StackCount = 1
pop ; StackCount = 0
pushtype UnicodeString_2 ; StackCount = 1
assign Var1, UnicodeString_3("&Print")
pushtype TBUTTON ; StackCount = 2
assign Var2, Global0
call TBUTTON->CAPTION
pop ; StackCount = 1
pop ; StackCount = 0
pushtype TNOTIFYEVENT ; StackCount = 1
assign Var1, TNOTIFYEVENT(PRINTBUTTONCLICK)
pushtype TBUTTON ; StackCount = 2
assign Var2, Global0
call TBUTTON->ONCLICK
pop ; StackCount = 1
pop ; StackCount = 0
pushtype TWINCONTROL ; StackCount = 1
pushtype TNEWRADIOBUTTON ; StackCount = 2
pushtype TWIZARDFORM ; StackCount = 3
pushvar Var3 ; StackCount = 4
call WIZARDFORM
pop ; StackCount = 3
pushvar Var2 ; StackCount = 4
call TWIZARDFORM->LICENSEACCEPTEDRADIO
pop ; StackCount = 3
pop ; StackCount = 2
pushvar Var1 ; StackCount = 3
call TCONTROL->PARENT
pop ; StackCount = 2
pop ; StackCount = 1
pushtype TBUTTON ; StackCount = 2
assign Var2, Global0
call TCONTROL->PARENT_2
pop ; StackCount = 1
pop ; StackCount = 0
ret
.function(import) external class(TCONTROL, CREATE) __fastcall returnsval TCONTROL->CREATE(__in __unknown)
.function(import) external class(TWIZARDFORM, LICENSEPAGE) __pascal void TWIZARDFORM->LICENSEPAGE(__in __unknown,__in __unknown)
.function(import) external class(TBUTTON, CAPTION, property) __pascal void TBUTTON->CAPTION(__in __unknown,__in __unknown)
.function(import) external class(TBUTTON, ONCLICK, property) __pascal void TBUTTON->ONCLICK(__in __unknown,__in __unknown)
.function(import) external class(TCONTROL, PARENT) __pascal void TCONTROL->PARENT(__in __unknown,__in __unknown)
.function(import) external class(TCONTROL, PARENT, property) __pascal void TCONTROL->PARENT_2(__in __unknown,__in __unknown)
.function(export) void INITIALIZEWIZARD()
call CREATEPRINTBUTTON
ret
.function(export) void CURPAGECHANGED(__in S32 Arg1)
call ADJUSTPRINTBUTTON
ret
.function(export) BOOLEAN SHOULDSKIPPAGE(__in S32 Arg1)
assign RetVal, BOOLEAN(0)
pushtype BOOLEAN ; StackCount = 1
pushvar Var1 ; StackCount = 2
call ISUPGRADE
pop ; StackCount = 1
sfz Var1
pop ; StackCount = 0
jf loc_90
pushtype BOOLEAN ; StackCount = 1
eq Var1, Arg1, S32(6)
sfz Var1
pop ; StackCount = 0
jf loc_5d
assign RetVal, BOOLEAN(1)
loc_5d:
pushtype BOOLEAN ; StackCount = 1
eq Var1, Arg1, S32(8)
sfz Var1
pop ; StackCount = 0
jf loc_90
assign RetVal, BOOLEAN(1)
loc_90:
ret

File diff suppressed because it is too large Load Diff

View File

@ -39,14 +39,6 @@
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<ItemGroup>
<Reference Include="Microsoft.VisualStudio.TestPlatform.TestFramework, Version=14.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<HintPath>..\packages\MSTest.TestFramework.2.2.7\lib\net45\Microsoft.VisualStudio.TestPlatform.TestFramework.dll</HintPath>
</Reference>
<Reference Include="Microsoft.VisualStudio.TestPlatform.TestFramework.Extensions, Version=14.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<HintPath>..\packages\MSTest.TestFramework.2.2.7\lib\net45\Microsoft.VisualStudio.TestPlatform.TestFramework.Extensions.dll</HintPath>
</Reference>
</ItemGroup>
<ItemGroup>
<Compile Include="Properties\Resources.Designer.cs">
<AutoGen>True</AutoGen>
@ -59,8 +51,10 @@
<ItemGroup>
<None Include="app.config" />
<None Include="CompiledCode.bin" />
<None Include="CompiledCode_float80.bin" />
<None Include="CompiledCode_v22.bin" />
<None Include="packages.config" />
<None Include="TestIsInsn.bin" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="Properties\Resources.resx">
@ -85,16 +79,23 @@
<ItemGroup>
<None Include="CompiledCode_v22.txt" />
</ItemGroup>
<ItemGroup>
<None Include="TestIsInsn.txt" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="MSTest.TestAdapter">
<Version>2.2.7</Version>
</PackageReference>
<PackageReference Include="MSTest.TestFramework">
<Version>2.2.7</Version>
</PackageReference>
<PackageReference Include="NETStandard.Library">
<Version>2.0.3</Version>
</PackageReference>
</ItemGroup>
<ItemGroup>
<Content Include="CompiledCode_float80.txt" />
</ItemGroup>
<Import Project="$(VSToolsPath)\TeamTest\Microsoft.TestTools.targets" Condition="Exists('$(VSToolsPath)\TeamTest\Microsoft.TestTools.targets')" />
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
<PropertyGroup>
<ErrorText>This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
</PropertyGroup>
<Error Condition="!Exists('..\packages\MSTest.TestAdapter.2.2.7\build\net45\MSTest.TestAdapter.props')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\MSTest.TestAdapter.2.2.7\build\net45\MSTest.TestAdapter.props'))" />
<Error Condition="!Exists('..\packages\MSTest.TestAdapter.2.2.7\build\net45\MSTest.TestAdapter.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\MSTest.TestAdapter.2.2.7\build\net45\MSTest.TestAdapter.targets'))" />
<Error Condition="!Exists('..\packages\NETStandard.Library.2.0.3\build\netstandard2.0\NETStandard.Library.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\NETStandard.Library.2.0.3\build\netstandard2.0\NETStandard.Library.targets'))" />
</Target>
<Import Project="..\packages\MSTest.TestAdapter.2.2.7\build\net45\MSTest.TestAdapter.targets" Condition="Exists('..\packages\MSTest.TestAdapter.2.2.7\build\net45\MSTest.TestAdapter.targets')" />
<Import Project="..\packages\NETStandard.Library.2.0.3\build\netstandard2.0\NETStandard.Library.targets" Condition="Exists('..\packages\NETStandard.Library.2.0.3\build\netstandard2.0\NETStandard.Library.targets')" />
</Project>

View File

@ -70,6 +70,16 @@ namespace IFPSLib.Tests.Properties {
}
}
/// <summary>
/// Looks up a localized resource of type System.Byte[].
/// </summary>
internal static byte[] CompiledCode_float80 {
get {
object obj = ResourceManager.GetObject("CompiledCode_float80", resourceCulture);
return ((byte[])(obj));
}
}
/// <summary>
/// Looks up a localized resource of type System.Byte[].
/// </summary>
@ -128,12 +138,75 @@ namespace IFPSLib.Tests.Properties {
///.type primitive(S16) S16
///.type primitive(U16) U16
///.type primitive(S8) S8
///.type(export) funcptr(void()) ANY [rest of string was truncated]&quot;;.
///.type primitive(String) String_2 /// [rest of string was truncated]&quot;;.
/// </summary>
internal static string CompiledCodeDisasm_float80 {
get {
return ResourceManager.GetString("CompiledCodeDisasm_float80", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to .version 22
///
///.entry !MAIN
///
///.type primitive(Pointer) Pointer
///.type primitive(U32) U32
///.type primitive(Variant) Variant
///.type primitive(PChar) PChar
///.type primitive(Currency) Currency
///.type primitive(Extended) Extended
///.type primitive(Double) Double
///.type primitive(Single) Single
///.type primitive(String) String
///.type primitive(U32) U32_2
///.type primitive(S32) S32
///.type primitive(S16) S16
///.type primitive(U16) U16
///.type primitive(S8) S8
///.type primitive(Char) Char
///.type primitive(U32) U32_3
///.ty [rest of string was truncated]&quot;;.
/// </summary>
internal static string CompiledCodeDisasm_v22 {
get {
return ResourceManager.GetString("CompiledCodeDisasm_v22", resourceCulture);
}
}
/// <summary>
/// Looks up a localized resource of type System.Byte[].
/// </summary>
internal static byte[] TestIsInsn {
get {
object obj = ResourceManager.GetObject("TestIsInsn", resourceCulture);
return ((byte[])(obj));
}
}
/// <summary>
/// Looks up a localized string similar to .version 23
///
///.type primitive(Pointer) Pointer
///.type primitive(S32) S32
///.type primitive(U32) U32
///.type primitive(U8) U8
///
///.function(export) U8 INITIALIZEUNINSTALL()
/// pushtype U32 ; StackCount = 1
/// pushtype U32 ; StackCount = 2
/// is Var1, Var2, S32
/// is Var1, Var2, Var1
/// ret
///
///
///.
/// </summary>
internal static string TestIsInsnDisasm {
get {
return ResourceManager.GetString("TestIsInsnDisasm", resourceCulture);
}
}
}
}

View File

@ -124,10 +124,22 @@
<data name="CompiledCodeDisasm" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\CompiledCode.txt;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;utf-8</value>
</data>
<data name="CompiledCodeDisasm_float80" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\CompiledCode_float80.txt;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;Windows-1252</value>
</data>
<data name="CompiledCodeDisasm_v22" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\CompiledCode_v22.txt;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;utf-8</value>
</data>
<data name="CompiledCode_float80" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\CompiledCode_float80.bin;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</data>
<data name="CompiledCode_v22" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\CompiledCode_v22.bin;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</data>
<data name="TestIsInsn" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\TestIsInsn.bin;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</data>
<data name="TestIsInsnDisasm" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\TestIsInsn.txt;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;Windows-1252</value>
</data>
</root>

View File

@ -10,18 +10,16 @@ namespace IFPSLib.Tests
[TestClass]
public class ScriptTest
{
private static readonly string origB64 = Convert.ToBase64String(Resources.CompiledCode);
private static readonly string origB64_22 = Convert.ToBase64String(Resources.CompiledCode_v22);
[TestMethod]
public void TestLoadSave()
private void TestLoadSaveImpl(byte[] compiled)
{
// Convert to base64.
string orig = Convert.ToBase64String(compiled);
// Load the script.
var script = Script.Load(Resources.CompiledCode);
var script = Script.Load(compiled);
// Ensure it's not null.
Assert.IsNotNull(script);
// For an official script (compiled by inno setup), the entrypoint is the first function.
Assert.AreEqual(script.EntryPoint, script.Functions[0]);
if (script.EntryPoint != null) Assert.AreEqual(script.EntryPoint, script.Functions[0]);
// Save the script.
var savedBytes = script.Save();
// Convert to base64 for later.
@ -33,50 +31,65 @@ namespace IFPSLib.Tests
// Ensure both saved scripts equal each other.
Assert.AreEqual(saved, savedTwice);
// Ensure the saved script equals the original.
Assert.AreEqual(saved, origB64);
Assert.AreEqual(saved, orig);
// Ensure the disassemblies are equal.
Assert.AreEqual(script.Disassemble(), scriptSaved.Disassemble());
}
private void TestAsmImpl(string disasm, byte[] compiled)
{
string orig = Convert.ToBase64String(compiled);
var script = Assembler.Assemble(disasm);
var savedB64 = Convert.ToBase64String(script.Save());
Assert.AreEqual(savedB64, orig);
}
[TestMethod]
public void TestLoadSave()
{
TestLoadSaveImpl(Resources.CompiledCode);
}
[TestMethod]
public void TestAsm()
{
var script = Assembler.Assemble(Resources.CompiledCodeDisasm);
var savedB64 = Convert.ToBase64String(script.Save());
Assert.AreEqual(savedB64, origB64);
TestAsmImpl(Resources.CompiledCodeDisasm, Resources.CompiledCode);
}
[TestMethod]
public void TestLoadSaveV22()
{
// Load the script.
var script = Script.Load(Resources.CompiledCode_v22);
// Ensure it's not null.
Assert.IsNotNull(script);
// For an official script (compiled by inno setup), the entrypoint is the first function.
Assert.AreEqual(script.EntryPoint, script.Functions[0]);
// Save the script.
var savedBytes = script.Save();
// Convert to base64 for later.
var saved = Convert.ToBase64String(savedBytes);
// Load the saved script.
var scriptSaved = Script.Load(savedBytes);
// Save again.
var savedTwice = Convert.ToBase64String(scriptSaved.Save());
// Ensure both saved scripts equal each other.
Assert.AreEqual(saved, savedTwice);
// Ensure the saved script equals the original.
Assert.AreEqual(saved, origB64_22);
// Ensure the disassemblies are equal.
Assert.AreEqual(script.Disassemble(), scriptSaved.Disassemble());
TestLoadSaveImpl(Resources.CompiledCode_v22);
}
[TestMethod]
public void TestAsmV22()
{
var script = Assembler.Assemble(Resources.CompiledCodeDisasm_v22);
var savedB64 = Convert.ToBase64String(script.Save());
Assert.AreEqual(savedB64, origB64);
TestAsmImpl(Resources.CompiledCodeDisasm_v22, Resources.CompiledCode_v22);
}
[TestMethod]
public void TestLoadSaveIs()
{
TestLoadSaveImpl(Resources.TestIsInsn);
}
[TestMethod]
public void TestAsmIs()
{
TestAsmImpl(Resources.TestIsInsnDisasm, Resources.TestIsInsn);
}
[TestMethod]
public void TestLoadSaveFloat80()
{
TestLoadSaveImpl(Resources.CompiledCode_float80);
}
[TestMethod]
public void TestAsmFloat80()
{
TestAsmImpl(Resources.CompiledCodeDisasm_float80, Resources.CompiledCode_float80);
}
}
}

Binary file not shown.

View File

@ -0,0 +1,15 @@
.version 23
.type primitive(Pointer) Pointer
.type primitive(S32) S32
.type primitive(U32) U32
.type primitive(U8) U8
.function(export) U8 INITIALIZEUNINSTALL()
pushtype U32 ; StackCount = 1
pushtype U32 ; StackCount = 2
is Var1, Var2, S32
is Var1, Var2, Var1
ret

View File

@ -29,6 +29,8 @@ namespace IFPSLib.Emit
private List<Operand> m_Operands = new List<Operand>();
private static readonly Operand s_opU32 = Operand.Create<uint>(0);
/// <summary>
/// Gets or sets the operand at the specified index.
/// </summary>
@ -248,7 +250,8 @@ namespace IFPSLib.Emit
/// <returns>New instruction</returns>
public static Instruction Create(OpCode opcode, Operand op0, Operand op1, Operand op2)
{
if (opcode.OperandType != OperandType.InlineCmpValue) throw new ArgumentOutOfRangeException(nameof(opcode), "Opcode does not have three value operands");
if (opcode.OperandType != OperandType.InlineCmpValue && opcode.OperandType != OperandType.InlineCmpValueType)
throw new ArgumentOutOfRangeException(nameof(opcode), "Opcode does not have three value operands");
return new Instruction(opcode, new List<Operand>(3) { op0, op1, op2 });
}
@ -380,6 +383,13 @@ namespace IFPSLib.Emit
return FixBranchOffset(br, br.Read<uint>());
}
private static Operand ReadTypeForCmpValueType(BinaryReader br, Script script, ScriptFunction function)
{
var operand = Operand.LoadValue(br, script, function);
if (operand.Type == BytecodeOperandType.Immediate) return Operand.Create(script.Types[(int)operand.ImmediateAs<uint>()]);
return operand;
}
internal static Instruction Load(BinaryReader br, Script script, ScriptFunction function)
{
var ret = new Instruction();
@ -449,7 +459,7 @@ namespace IFPSLib.Emit
ret.m_Operands = new List<Operand>(3) {
Operand.LoadValue(br, script, function),
Operand.LoadValue(br, script, function),
Operand.Create(script.Types[(int)br.Read<uint>()])
ReadTypeForCmpValueType(br, script, function)
};
break;
case OperandType.InlineEH:
@ -565,7 +575,7 @@ namespace IFPSLib.Emit
ret += m_Operands[0].Size + m_Operands[1].Size + m_Operands[2].Size;
break;
case OperandType.InlineCmpValueType:
ret += m_Operands[0].Size + m_Operands[1].Size + sizeof(int);
ret += m_Operands[0].Size + m_Operands[1].Size + (m_Operands[2].Type != BytecodeOperandType.Immediate ? m_Operands[2] : s_opU32).Size;
break;
case OperandType.InlineEH:
ret += sizeof(uint) * 4;
@ -664,7 +674,14 @@ namespace IFPSLib.Emit
case OperandType.InlineCmpValueType:
m_Operands[0].Save(bw, ctx);
m_Operands[1].Save(bw, ctx);
bw.Write<int>(ctx.GetTypeIndex(m_Operands[2].ImmediateAs<IType>()));
if (m_Operands[2].Type == BytecodeOperandType.Immediate)
{
Operand.Create((uint)ctx.GetTypeIndex(m_Operands[2].ImmediateAs<IType>())).Save(bw, ctx);
}
else
{
m_Operands[2].Save(bw, ctx);
}
break;
case OperandType.InlineEH:
bw.Write<uint>(GetEHOffset(m_Operands[0], table));

View File

@ -186,6 +186,7 @@ namespace IFPSLib.Emit
/// <summary>
/// Operand 1 must be a <see cref="Types.ClassType"/>, operand 2 is a <see cref="Types.TypeType"/> that must be a <see cref="Types.ClassType"/>
/// Checks if operand 1 is of the <see cref="Types.ClassType"/> referenced by operand 2.
/// Operand 2 can also be a variable of type <see cref="UInt32"/> containing the index of the type to compare against.
/// </summary>
public static readonly OpCode Is = new OpCode("is", Code.Is, OperandType.InlineCmpValueType, FlowControl.Next, OpCodeType.Macro);

View File

@ -39,7 +39,7 @@ namespace IFPSLib.Emit
/// </summary>
InlineCmpValue,
/// <summary>
/// Two <see cref="InlineValue"/>s followed by <see cref="InlineType"/>
/// Three <see cref="InlineValue"/>s where the last is a <see cref="UInt32"/> type index
/// </summary>
InlineCmpValueType,
/// <summary>

View File

@ -148,7 +148,12 @@ namespace IFPSLib.Emit
{
var isVoid = ReturnArgument == null;
var ret = ArgumentVariable.Create(index + (isVoid ? 0 : 1), isVoid);
ret.Name = Arguments[index].Name;
if (!Exported)
{
if (!isVoid && index == 0) ret.Name = "RetVal";
else ret.Name = string.Format("Arg{0}", index + (isVoid ? 0 : 1));
}
else ret.Name = Arguments[index].Name;
return ret;
}

View File

@ -8,6 +8,7 @@ using SharpFloat.FloatingPoint;
using System.Runtime.InteropServices;
using System.Collections;
using System.Runtime.CompilerServices;
using System.Globalization;
namespace IFPSLib
{
@ -16,6 +17,7 @@ namespace IFPSLib
/// </summary>
public class TypedData
{
private static readonly CultureInfo s_Culture = new CultureInfo("en");
public IType Type { get; }
public object Value { get; }
@ -128,11 +130,11 @@ namespace IFPSLib
return new TypedData(type, br.Read<double>());
case PascalTypeCode.Extended:
{
// BUGBUG: there must be something beter than this... but for now, it'll do
// BUGBUG: there must be something better than this... but for now, it'll do
var sb = new StringBuilder();
ExtF80.PrintFloat80(sb, br.Read<ExtF80>(), PrintFloatFormat.ScientificFormat, 19);
TrimDecimalString(sb);
return new TypedData(type, decimal.Parse(sb.ToString(), System.Globalization.NumberStyles.Float));
return new TypedData(type, decimal.Parse(sb.ToString(), NumberStyles.Float, s_Culture));
}
case PascalTypeCode.Currency:
@ -207,7 +209,7 @@ namespace IFPSLib
WriteValue<double>(bw);
break;
case PascalTypeCode.Extended:
if (!ExtF80.TryParse(ValueAs<decimal>().ToString(), out var extf))
if (!ExtF80.TryParse(ValueAs<decimal>().ToString(s_Culture), out var extf))
throw new ArgumentOutOfRangeException("Value {0} cannot fit into an 80-bit floating point number");
bw.Write(extf);
break;
@ -342,7 +344,7 @@ namespace IFPSLib
sb.Append(')');
return sb.ToString();
}
return string.Format("{0}({1})", Type.Name, Value);
return string.Format(s_Culture, "{0}({1})", Type.Name, Value);
}
}
}

View File

@ -8,30 +8,49 @@ using Parsing;
namespace Driver {
public class Compiler {
private static readonly bool SHOW_TIME = false;
private static System.Diagnostics.Stopwatch StartTimer()
{
var watch = new System.Diagnostics.Stopwatch();
watch.Start();
return watch;
}
private Compiler(String source) {
this.Source = source;
// Lexical analysis
var watch = StartTimer();
Scanner scanner = new Scanner(source);
this.Tokens = scanner.Tokens.ToImmutableList();
watch.Stop();
if (SHOW_TIME) Console.WriteLine("lexer: {0} ms", watch.ElapsedMilliseconds);
// Parse
watch = StartTimer();
var parserResult = CParsers.Parse(this.Tokens);
watch.Stop();
if (SHOW_TIME) Console.WriteLine("parser: {0} ms", watch.ElapsedMilliseconds);
if (!parserResult.IsSuccessful || parserResult.Source.Count() != 1) {
throw new InvalidOperationException($"Parsing error:\n{parserResult}");
}
this.SyntaxTree = parserResult.Result;
// Semantic analysis
watch = StartTimer();
var semantReturn = this.SyntaxTree.GetTranslnUnit();
watch.Stop();
if (SHOW_TIME) Console.WriteLine("semant: {0} ms", watch.ElapsedMilliseconds);
this.AbstractSyntaxTree = semantReturn.Value;
this.Environment = semantReturn.Env;
// Code generation
watch = StartTimer();
var state = new CGenState();
this.AbstractSyntaxTree.CodeGenerate(state);
state.EmitCallsToCtor();
this.Script = state.Script;
watch.Stop();
if (SHOW_TIME) Console.WriteLine("codegen: {0} ms", watch.ElapsedMilliseconds);
}
public static Compiler FromSource(String src) {

View File

@ -7,8 +7,10 @@ using static Parsing.ParserCombinator;
using System.Collections.Immutable;
namespace Parsing {
public partial class CParsers {
static CParsers() {
public partial class CParsers
{
static CParsers()
{
SetExpressionRules();
SetDeclarationRules();
SetExternalDefinitionRules();
@ -18,44 +20,56 @@ namespace Parsing {
public static IParserResult<TranslnUnit> Parse(IEnumerable<Token> tokens) =>
TranslationUnit.Parse(new ParserInput(new ParserEnvironment(), tokens));
public class ConstCharParser : IParser<Expr> {
public class ConstCharParser : IParser<Expr>
{
public RuleCombining Combining => RuleCombining.NONE;
public IParserResult<Expr> Parse(ParserInput input) {
public IParserResult<Expr> Parse(ParserInput input)
{
var token = input.Source.First() as TokenCharConst;
if (token == null) {
if (token == null)
{
return new ParserFailed<Expr>(input);
}
return ParserSucceeded.Create(new IntLiteral(token.Value, TokenInt.IntSuffix.NONE), input.Environment, input.Source.Skip(1));
}
}
public class ConstIntParser : IParser<Expr> {
public class ConstIntParser : IParser<Expr>
{
public RuleCombining Combining => RuleCombining.NONE;
public IParserResult<Expr> Parse(ParserInput input) {
public IParserResult<Expr> Parse(ParserInput input)
{
var token = input.Source.First() as TokenInt;
if (token == null) {
if (token == null)
{
return new ParserFailed<Expr>(input);
}
return ParserSucceeded.Create(new IntLiteral(token.Val, token.Suffix), input.Environment, input.Source.Skip(1));
}
}
public class ConstFloatParser : IParser<Expr> {
public class ConstFloatParser : IParser<Expr>
{
public RuleCombining Combining => RuleCombining.NONE;
public IParserResult<Expr> Parse(ParserInput input) {
public IParserResult<Expr> Parse(ParserInput input)
{
var token = input.Source.First() as TokenFloat;
if (token == null) {
if (token == null)
{
return new ParserFailed<Expr>(input);
}
return ParserSucceeded.Create(new FloatLiteral(token.Value, token.Suffix), input.Environment, input.Source.Skip(1));
}
}
public class StringLiteralParser : IParser<Expr> {
public class StringLiteralParser : IParser<Expr>
{
public RuleCombining Combining => RuleCombining.NONE;
public IParserResult<Expr> Parse(ParserInput input) {
public IParserResult<Expr> Parse(ParserInput input)
{
var token = input.Source.First() as TokenString;
if (token == null) {
if (token == null)
{
return new ParserFailed<Expr>(input);
}
return ParserSucceeded.Create(new StringLiteral(token.Val), input.Environment, input.Source.Skip(1));
@ -76,8 +90,10 @@ namespace Parsing {
}
}
public class BinaryOperatorBuilder {
public BinaryOperatorBuilder(IConsumer operatorConsumer, Func<Expr, Expr, Expr> nodeCreator) {
public class BinaryOperatorBuilder
{
public BinaryOperatorBuilder(IConsumer operatorConsumer, Func<Expr, Expr, Expr> nodeCreator)
{
this.OperatorConsumer = operatorConsumer;
this.NodeCreator = nodeCreator;
}
@ -89,29 +105,93 @@ namespace Parsing {
public Func<Expr, Expr, Expr> NodeCreator { get; }
}
// TODO: create a dedicated class for this.
public static IParser<Expr> BinaryOperator(IParser<Expr> operandParser, params BinaryOperatorBuilder[] builders) {
ImmutableList<ITransformer<Expr, Expr>> transformers = builders.Select(builder =>
Given<Expr>()
.Then(builder.OperatorConsumer)
.Then(operandParser)
.Then(builder.NodeCreator)
).ToImmutableList();
return operandParser.Then((new OrTransformer<Expr, Expr>(transformers)).ZeroOrMore());
public class OperatorParser : IParser<Expr>
{
private IParser<Expr> lhsParser;
private IParser<Expr> rhsParser;
private readonly ImmutableList<BinaryOperatorBuilder> builders;
private readonly bool needsOne;
public OperatorParser(IParser<Expr> operandParser, IEnumerable<BinaryOperatorBuilder> builders) : this(operandParser, operandParser, builders)
{
needsOne = false;
}
public OperatorParser(IParser<Expr> lhsParser, IParser<Expr> rhsParser, IEnumerable<BinaryOperatorBuilder> builders)
{
this.lhsParser = lhsParser;
this.rhsParser = rhsParser;
this.builders = builders.ToImmutableList();
needsOne = true;
}
public RuleCombining Combining => RuleCombining.THEN;
public IParserResult<Expr> Parse(ParserInput input)
{
var firstResult = lhsParser.Parse(input);
if (!firstResult.IsSuccessful)
{
return new ParserFailed<Expr>(firstResult);
}
return Transform(firstResult.Result, firstResult.ToInput());
}
private IParserResult<Expr> TransformImpl(Expr seed, ParserInput input)
{
List<IParserFailed> failed = new List<IParserFailed>();
foreach (var builder in builders) {
var given = ParserSucceeded.Create(seed, input.Environment, input.Source);
var result1 = builder.OperatorConsumer.Consume(given.ToInput());
if (!result1.IsSuccessful)
{
failed.Add(new ParserFailed<Expr>(result1));
continue;
}
var result2 = rhsParser.Parse(result1.ToInput());
if (!result2.IsSuccessful)
{
failed.Add(new ParserFailed<Expr>(result2));
continue;
}
var transform = builder.NodeCreator(seed, result2.Result);
var ret = ParserSucceeded.Create(transform, result2.Environment, result2.Source);
var expr = transform as IStoredLineInfo;
if (expr != null)
{
expr.Copy(ret);
}
return ret;
}
return new ParserFailed<Expr>(input, failed);
}
public IParserResult<Expr> Transform(Expr seed, ParserInput input)
{
IParserResult<Expr> curResult = needsOne ? TransformImpl(seed, input) : ParserSucceeded.Create(seed, input.Environment, input.Source);
if (!curResult.IsSuccessful) return new ParserFailed<Expr>(curResult);
IParserResult<Expr> lastSuccessfulResult;
do
{
lastSuccessfulResult = curResult;
curResult = TransformImpl(lastSuccessfulResult.Result, lastSuccessfulResult.ToInput());
} while (curResult.IsSuccessful);
return lastSuccessfulResult;
}
}
public static IParser<Expr> BinaryOperator(IParser<Expr> operandParser, params BinaryOperatorBuilder[] builders)
=> new OperatorParser(operandParser, builders);
public static IParser<Expr> AssignmentOperator(
IParser<Expr> lhsParser,
IParser<Expr> rhsParser,
params BinaryOperatorBuilder[] builders
) {
var transformers = builders.Select(builder =>
Given<Expr>()
.Then(builder.OperatorConsumer)
.Then(rhsParser)
.Then(builder.NodeCreator)
).ToImmutableList();
return lhsParser.Then((new OrTransformer<Expr, Expr>(transformers)).OneOrMore());
}
) => new OperatorParser(lhsParser, rhsParser, builders);
}
}

View File

@ -1,4 +1,5 @@
using System;
using System.Text;
namespace LexicalAnalysis {
/// <summary>
@ -61,7 +62,7 @@ namespace LexicalAnalysis {
}
private State _state;
private String _scanned;
private StringBuilder _scanned;
// quote : Char
// ============
@ -71,11 +72,11 @@ namespace LexicalAnalysis {
public FSAChar(Char quote) {
this._state = State.START;
this._quote = quote;
this._scanned = "";
this._scanned = new StringBuilder();
}
public override void Reset() {
this._scanned = "";
this._scanned.Clear();
this._state = State.START;
}
@ -106,7 +107,7 @@ namespace LexicalAnalysis {
// ==========================
//
public String RetrieveRaw() {
return this._scanned.Substring(0, this._scanned.Length - 1);
return this._scanned.ToString(0, this._scanned.Length - 1);
}
// RetrieveChar : () -> Char
@ -157,7 +158,7 @@ namespace LexicalAnalysis {
// Implementation of the FSA
//
public override void ReadChar(Char ch) {
this._scanned = this._scanned + ch;
this._scanned = this._scanned.Append(ch);
switch (this._state) {
case State.END:
case State.ERROR:
@ -230,7 +231,7 @@ namespace LexicalAnalysis {
// ==================
//
public override void ReadEOF() {
this._scanned = this._scanned + '0';
this._scanned = this._scanned.Append('0');
switch (this._state) {
case State.C:
case State.SO:

View File

@ -1,4 +1,5 @@
using System;
using System.Text;
namespace LexicalAnalysis {
/// <summary>
@ -60,7 +61,7 @@ namespace LexicalAnalysis {
DPL
};
private String _raw;
private StringBuilder _raw;
private Int64 _intPart;
private Int64 _fracPart;
private Int64 _fracCount;
@ -77,7 +78,7 @@ namespace LexicalAnalysis {
this._expPart = 0;
this._suffix = TokenFloat.FloatSuffix.NONE;
this._expPos = true;
this._raw = "";
this._raw = new StringBuilder();
}
public override void Reset() {
@ -88,7 +89,7 @@ namespace LexicalAnalysis {
this._expPart = 0;
this._suffix = TokenFloat.FloatSuffix.NONE;
this._expPos = true;
this._raw = "";
this._raw.Clear();
}
public override FSAStatus GetStatus() {
@ -111,11 +112,11 @@ namespace LexicalAnalysis {
} else {
val = (this._intPart + this._fracPart * Math.Pow(0.1, this._fracCount)) * Math.Pow(10, -this._expPart);
}
return new TokenFloat(val, this._suffix, this._raw.Substring(0, this._raw.Length - 1));
return new TokenFloat(val, this._suffix, this._raw.ToString(0, this._raw.Length - 1));
}
public override void ReadChar(Char ch) {
this._raw += ch;
this._raw.Append(ch);
switch (this._state) {
case State.ERROR:
case State.END:

View File

@ -1,4 +1,6 @@
using System;
using System.Linq;
using System.Text;
namespace LexicalAnalysis {
/// <summary>
@ -24,16 +26,16 @@ namespace LexicalAnalysis {
ID
};
private State _state;
private String _scanned;
private StringBuilder _scanned;
public FSAIdentifier() {
this._state = State.START;
this._scanned = "";
this._scanned = new StringBuilder();
}
public override void Reset() {
this._state = State.START;
this._scanned = "";
this._scanned.Clear();
}
public override FSAStatus GetStatus() {
@ -50,7 +52,7 @@ namespace LexicalAnalysis {
}
public override Token RetrieveToken() {
String name = this._scanned.Substring(0, this._scanned.Length - 1);
String name = this._scanned.ToString(0, this._scanned.Length - 1);
if (TokenKeyword.Keywords.ContainsKey(name)) {
return new TokenKeyword(TokenKeyword.Keywords[name]);
}
@ -58,7 +60,7 @@ namespace LexicalAnalysis {
}
public override void ReadChar(Char ch) {
this._scanned = this._scanned + ch;
this._scanned = this._scanned.Append(ch);
switch (this._state) {
case State.END:
case State.ERROR:
@ -82,7 +84,7 @@ namespace LexicalAnalysis {
}
public override void ReadEOF() {
this._scanned = this._scanned + '0';
this._scanned = this._scanned.Append('0');
switch (this._state) {
case State.ID:
this._state = State.END;

View File

@ -1,4 +1,5 @@
using System;
using System.Text;
namespace LexicalAnalysis {
/// <summary>
@ -69,21 +70,21 @@ namespace LexicalAnalysis {
};
private Int64 _val;
private String _raw;
private StringBuilder _raw;
private TokenInt.IntSuffix _suffix;
private State _state;
public FSAInt() {
this._state = State.START;
this._val = 0;
this._raw = "";
this._raw = new StringBuilder();
this._suffix = TokenInt.IntSuffix.NONE;
}
public override void Reset() {
this._state = State.START;
this._val = 0;
this._raw = "";
this._raw.Clear();
this._suffix = TokenInt.IntSuffix.NONE;
}
@ -101,11 +102,11 @@ namespace LexicalAnalysis {
}
public override Token RetrieveToken() {
return new TokenInt(this._val, this._suffix, this._raw.Substring(0, this._raw.Length - 1));
return new TokenInt(this._val, this._suffix, this._raw.ToString(0, this._raw.Length - 1));
}
public override void ReadChar(Char ch) {
this._raw += ch;
this._raw.Append(ch);
switch (this._state) {
case State.ERROR:
case State.END:

View File

@ -2,6 +2,7 @@
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Linq;
using System.Text;
namespace LexicalAnalysis {
/// <summary>
@ -166,16 +167,16 @@ namespace LexicalAnalysis {
);
private State _state;
private String _scanned;
private StringBuilder _scanned;
public FSAOperator() {
this._state = State.START;
this._scanned = "";
this._scanned = new StringBuilder();
}
public override sealed void Reset() {
this._state = State.START;
this._scanned = "";
this._scanned.Clear();
}
public override sealed FSAStatus GetStatus() {
@ -192,11 +193,11 @@ namespace LexicalAnalysis {
}
public override sealed Token RetrieveToken() {
return new TokenOperator(TokenOperator.Operators[this._scanned.Substring(0, this._scanned.Length - 1)]);
return new TokenOperator(TokenOperator.Operators[this._scanned.ToString(0, this._scanned.Length - 1)]);
}
public override sealed void ReadChar(Char ch) {
this._scanned = this._scanned + ch;
this._scanned = this._scanned.Append(ch);
switch (this._state) {
case State.END:
case State.ERROR:
@ -386,7 +387,7 @@ namespace LexicalAnalysis {
}
public override sealed void ReadEOF() {
this._scanned = this._scanned + '0';
this._scanned = this._scanned.Append('0');
switch (this._state) {
case State.FINISH:
case State.SUB:

View File

@ -36,21 +36,31 @@ namespace LexicalAnalysis {
private IEnumerable<Token> Lex() {
var tokens = new List<Token>();
int line = 1, column = 1, lastColumn = column;
char lastChr = '\0';
for (Int32 i = 0; i < this.Source.Length; ++i) {
if (i > 0 && this.Source[i - 1] == '\n')
if (lastChr == '\n')
{
line++;
lastColumn = 1;
column = 1;
}
else column++;
this.FSAs.ForEach(fsa => fsa.ReadChar(this.Source[i]));
bool isRunning = false;
int endIdx = -1;
var chr = Source[i];
for (int fsaIdx = 0; fsaIdx < FSAs.Count; fsaIdx++)
{
var fsa = FSAs[fsaIdx];
fsa.ReadChar(chr);
var status = fsa.GetStatus();
if (status == FSAStatus.RUNNING) isRunning = true;
else if (endIdx == -1 && status == FSAStatus.END) endIdx = fsaIdx;
}
// if no running
if (this.FSAs.FindIndex(fsa => fsa.GetStatus() == FSAStatus.RUNNING) == -1) {
Int32 idx = this.FSAs.FindIndex(fsa => fsa.GetStatus() == FSAStatus.END);
if (idx != -1) {
Token token = this.FSAs[idx].RetrieveToken();
if (!isRunning) {
if (endIdx != -1) {
Token token = this.FSAs[endIdx].RetrieveToken();
if (token.Kind != TokenKind.NONE) {
token.Line = line;
token.Column = lastColumn;
@ -58,19 +68,26 @@ namespace LexicalAnalysis {
tokens.Add(token);
}
i--; column--;
if (this.Source[i] == '\n') line--;
this.FSAs.ForEach(fsa => fsa.Reset());
if (lastChr == '\n') line--;
foreach (var fsa in FSAs) fsa.Reset();
} else {
Console.WriteLine("error");
}
}
if (!isRunning || endIdx == -1) lastChr = chr;
}
this.FSAs.ForEach(fsa => fsa.ReadEOF());
var endIdx2 = -1;
for (int fsaIdx = 0; fsaIdx < FSAs.Count; fsaIdx++)
{
var fsa = FSAs[fsaIdx];
fsa.ReadEOF();
if (endIdx2 != -1) continue;
if (fsa.GetStatus() == FSAStatus.END) endIdx2 = fsaIdx;
}
// find END
Int32 idx2 = this.FSAs.FindIndex(fsa => fsa.GetStatus() == FSAStatus.END);
if (idx2 != -1) {
Token token = this.FSAs[idx2].RetrieveToken();
if (endIdx2 != -1) {
Token token = this.FSAs[endIdx2].RetrieveToken();
if (token.Kind != TokenKind.NONE) {
token.Line = line;
token.Column = column + 1;

View File

@ -1,4 +1,5 @@
using System;
using System.Text;
namespace LexicalAnalysis {
/// <summary>
@ -54,22 +55,22 @@ namespace LexicalAnalysis {
private State _state;
private readonly FSAChar _fsachar;
private String _val;
private String _raw;
private StringBuilder _val;
private StringBuilder _raw;
private bool unicode = false;
public FSAString() {
this._state = State.START;
this._fsachar = new FSAChar('\"');
this._raw = "";
this._val = "";
this._raw = new StringBuilder();
this._val = new StringBuilder();
}
public override void Reset() {
this._state = State.START;
this._fsachar.Reset();
this._raw = "";
this._val = "";
this._raw.Clear();
this._val.Clear();
unicode = false;
}
@ -87,8 +88,8 @@ namespace LexicalAnalysis {
}
public override Token RetrieveToken() {
if (unicode) return new TokenUnicodeString(this._val, this._raw);
return new TokenString(this._val, this._raw);
if (unicode) return new TokenUnicodeString(this._val.ToString(), this._raw.ToString());
return new TokenString(this._val.ToString(), this._raw.ToString());
}
public override void ReadChar(Char ch) {
@ -129,8 +130,8 @@ namespace LexicalAnalysis {
switch (this._fsachar.GetStatus()) {
case FSAStatus.END:
this._state = State.Q;
this._val = this._val + this._fsachar.RetrieveChar();
this._raw = this._raw + this._fsachar.RetrieveRaw();
this._val.Append(this._fsachar.RetrieveChar());
this._raw.Append(this._fsachar.RetrieveRaw());
this._fsachar.Reset();
ReadChar(ch);
break;