This repository has been archived by the owner on Oct 18, 2024. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 3
/
modLUAInstruction.bas
2295 lines (1878 loc) · 102 KB
/
modLUAInstruction.bas
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
Attribute VB_Name = "modLUAInstruction"
Option Explicit
' Module containing LUA instruction-specific code, for decoding instructions.
#Const PrintStack = 0 ' To print debug and stack info (causes an information overload!).
#Const HaltOnErrors = 1 ' Halt on errors like unknown instructions?
#Const UseLineInfo = 1 ' Use line info (ex. for multiple conditions?)
' K = U argument used as index to `kstr'
' J = S argument used as jump offset (relative to pc of next instruction)
' L = unsigned argument used as index of local variable
' N = U argument used as index to `knum'
Private Enum LUA_OPCodes
' ------------------------------------------------------------------------'
' name args stack before stack after side effects '
' ------------------------------------------------------------------------'
OP_END = 0 ' - - (return) no results '
OP_RETURN ' U v_n-v_x(at u) (return) returns v_x-v_n '
OP_CALL ' A B v_n-v_1 f(at a) r_b-r_1 f(v1,...,v_n) '
OP_TAILCALL ' A B v_n-v_1 f(at a) (return) f(v1,...,v_n) '
OP_PUSHNIL ' U - IDT_Nil_1-IDT_Nil_u '
OP_POP ' U a_u-a_1 - '
OP_PUSHINT ' S - (Number)s '
OP_PUSHSTRING ' K - KSTR[k] '
OP_PUSHNUM ' N - KNUM[n] '
OP_PUSHNEGNUM ' N - -KNUM[n] '
OP_PUSHUPVALUE 'U - IDT_Closure[u] '
OP_GETLOCAL ' L - LOC[l] '
OP_GETGLOBAL ' K - VAR[KSTR[k]] '
OP_GETTABLE ' - i t t[i] '
OP_GETDOTTED ' K t t[KSTR[k]] '
OP_GETINDEXED ' L t t[LOC[l]] '
OP_PUSHSELF ' K t t t[KSTR[k]] '
OP_CREATETABLE 'U - newarray(size = u) '
OP_SETLOCAL ' L x - LOC[l]=x '
OP_SETGLOBAL ' K x - VAR[KSTR[k]]=x '
OP_SETTABLE ' A B v a_a-a_1 i t (pops b values) t[i]=v '
OP_SETLIST ' A B v_b-v_1 t t t[i+a*FPF]=v_i '
OP_SETMAP ' U v_u k_u - v_1 k_1 t t t[k_i]=v_i '
OP_ADD ' - y x x+y '
OP_ADDI ' S x x+s '
OP_SUB ' - y x x-y '
OP_MULT ' - y x x*y '
OP_DIV ' - y x x/y '
OP_POW ' - y x x^y '
OP_CONCAT ' U v_u-v_1 v1..-..v_u '
OP_MINUS ' - x -x '
OP_NOT ' - x (x==nil)? 1 : IDT_Nil '
OP_JMPNE ' J y x - (x~=y)? PC+=s '
OP_JMPEQ ' J y x - (x==y)? PC+=s '
OP_JMPLT ' J y x - (x<y)? PC+=s '
OP_JMPLE ' J y x - (x<y)? PC+=s '
OP_JMPGT ' J y x - (x>y)? PC+=s '
OP_JMPGE ' J y x - (x>=y)? PC+=s '
OP_JMPT ' J x - (x~=nil)? PC+=s '
OP_JMPF ' J x - (x==nil)? PC+=s '
OP_JMPONT ' J x (x~=nil)? x : - (x~=nil)? PC+=s '
OP_JMPONF ' J x (x==nil)? x : - (x==nil)? PC+=s '
OP_JMP ' J - - PC+=s '
OP_PUSHNILJMP ' - - IDT_Nil PC++; '
OP_FORPREP ' J '
OP_FORLOOP ' J '
OP_LFORPREP ' J '
OP_LFORLOOP ' J '
OP_IDT_Closure ' A B v_b-v_1 IDT_Closure(KPROTO[a], v_1-v_b) '
End Enum
' first six bytes
Private Const LUA_Instruction_Mask As Long = 63 ' ie [bits:00011111 00000000 00000000 00000000]
Private Const LUA_BArg_Mask = 511 ' ie [bits:11111111 00000001 00000000 00000000]
Private Const LUA_Intruction_SArg_Zero = 33554431 ' ie 2^25 - 1 for -33554431 to 33554431 (which is ~2^26 values)
Private Const LUA_Size_OP = 6 ' ref: LUA Source Code (lopcodes.h and llimits.h)
Private Const LUA_Size_A = 17 '
Private Const LUA_Size_B = 9 '
Private Const LUA_Pos_U = LUA_Size_OP '
Private Const LUA_Pos_S = LUA_Size_OP '
Private Const LUA_Pos_A = LUA_Size_OP + LUA_Size_B '
Private Const LUA_Pos_B = LUA_Size_OP '
Private Const LUA_MaxStackSize = 1024 ' Max. (internal) stack size.
Private Const LUA_NumJumpsStored = 128 ' NR. of jumps stored (may be nested)
Private Const LUA_FieldsPerFlush = 64 ' Fields per flush. Looks like max. stack size...
Private Const LUA_ExtraFields = 8 ' Some extra no. of fields (for calculating the stack size
' while DC'ing LUA).
Private Const LUA_Null = "IDT_Nil" ' not "null" but "IDT_Nil"
' Function statements and their search strings (the sstr will be chopped off).
Private Const FuncStatement_SStr = "--<< Position Reserved for Function "
Private Const FuncStatement_SStr_R = " >>--"
' Main body of function statement, this stores name (%n), function pointer (%f), parent's pointer (%p)
' [all references to pointers internal and may not neccessarily be accurate...]
Private Const FuncStatement = FuncStatement_SStr & "%n, &f, &p" & FuncStatement_SStr_R
Private Enum interpretationDataType
IDT_Nil ' null has it's own type.
IDT_Integral ' \ This would help to
IDT_Float ' / trace origin of value.
IDT_Char
IDT_Table ' a IDT_Table.
IDT_LocalVar ' local var.
IDT_Closure ' function.
End Enum
'Private Enum jumpTypes
' JT_Invalid ' uninitialized...
'
' JT_Conditional ' OP_JMPNE <= JT_Conditional <= OP_JMPONF
' JT_Unconditional ' OP_JMP = JT_Unconditional
' JT_While ' OP_JMPNE <= JT_Conditional <= OP_JMPONF
' JT_For ' OP_FORPREP <= JT_For <= OP_FORLOOP
'End Enum
Private Enum interpretationDataFlags
IDF_IsALocalValue = 1
IDF_FunctionReturn = 2
IDF_FunctionReturnWithEQ = 4
End Enum
Private Type interpretationStack ' stack Type
value As String
type As interpretationDataType
flags As interpretationDataFlags
extraValue As Long
extraString As String
End Type
'Private Type jumpRegister ' for storing jump infos
' type As jumpTypes ' type.
' condition As String ' actual string condition
'
' jmpT As Long ' where to jump if true. Obviously pos+1
' jmpF As Long ' where to jump if false.
' jmpE As Long ' where to jump after this jump is proved true
'End Type
Private localProcessed() As Boolean ' has this local been assigned value?
Private stack() As interpretationStack ' stack data
'Private jumpR(1 To LUA_NumJumpsStored) As jumpRegister
Private stackP As Long
'Private jumpRP As Long
Private currIns As Long ' current instruction
Private level As Long ' tab level
' Returns the OP Code of a given LUA 32-bit instruction.
Private Function Instruction_GetOPCode(ByVal instruction As Long) As LUA_OPCodes
Instruction_GetOPCode = (instruction And LUA_Instruction_Mask)
End Function
' Returns U (unsigned) from a instruction.
Private Function Instruction_GetUArg(ByVal instruction As Long)
Instruction_GetUArg = ShiftRight(instruction, LUA_Pos_U)
End Function
' Returns S (signed) from a instruction.
Private Function Instruction_GetSArg(ByVal instruction As Long)
Instruction_GetSArg = ShiftRight(instruction, LUA_Pos_S) - LUA_Intruction_SArg_Zero
End Function
' Returns A (1st argument of 17 bits in the upper bits) from a instruction.
Private Function Instruction_GetAArg(ByVal instruction As Long)
Instruction_GetAArg = ShiftRight(instruction, LUA_Pos_A)
End Function
' Returns B (2nd argument of 9 bits in the middle bits) from a instruction.
Private Function Instruction_GetBArg(ByVal instruction As Long)
Instruction_GetBArg = ShiftRight(instruction, LUA_Pos_B) And LUA_BArg_Mask
End Function
' Reverses the given condition (ie >= is chaned to <, and please, conditional jump opcodes only)
Private Function ReverseCondition_OP(ByVal condition As LUA_OPCodes) As LUA_OPCodes
ReverseCondition_OP = condition
Select Case ReverseCondition_OP
Case LUA_OPCodes.OP_JMPEQ
ReverseCondition_OP = OP_JMPNE
Case LUA_OPCodes.OP_JMPNE
ReverseCondition_OP = OP_JMPEQ
Case LUA_OPCodes.OP_JMPLT
ReverseCondition_OP = OP_JMPGE
Case LUA_OPCodes.OP_JMPGT
ReverseCondition_OP = OP_JMPLE
Case LUA_OPCodes.OP_JMPLE
ReverseCondition_OP = OP_JMPGT
Case LUA_OPCodes.OP_JMPGE
ReverseCondition_OP = OP_JMPLT
End Select ' Select Case ReverseCondition_OP
End Function
' Returns the index for the FIRST local with matching intruction number (startpc).
Private Function FindMatchingStartPCForLocal(ByRef luaChunk As LUA_Chunk, ByRef find As Long) As Long
Dim I As Long
FindMatchingStartPCForLocal = 0
For I = 1 To luaChunk.numLocals
If luaChunk.locals(I).startpc = find Then
FindMatchingStartPCForLocal = I
Exit For
End If ' If luaChunk.locals(I).startpc = find Then
Next I ' For I = 1 To luaChunk.numLocals
End Function
' Returns the index for the LAST local with matching intruction number (startpc)
Private Function FindMatchingStartPCForLastLocal(ByRef luaChunk As LUA_Chunk, ByRef find As Long) As Long
Dim I As Long
FindMatchingStartPCForLastLocal = -1 ' So that a loop out of this is never executed...
For I = 1 To luaChunk.numLocals
If luaChunk.locals(I).startpc = find Then
FindMatchingStartPCForLastLocal = I
End If ' If luaChunk.locals(I).startpc = find Then
Next I ' For I = 1 To luaChunk.numLocals
End Function
' Returns the nr. of locals which end at the given instruction.
Private Function FindNumLocalsWithEndPC(ByRef luaChunk As LUA_Chunk, ByRef find As Long) As Long
Dim I As Long
For I = 1 To luaChunk.numLocals
If luaChunk.locals(I).endpc = find Then _
FindNumLocalsWithEndPC = FindNumLocalsWithEndPC + 1
Next I ' For I = 1 To luaChunk.numLocals
End Function
' Returns the nr. of locals which start at the given instruction.
Private Function FindNumLocalsWithStartPC(ByRef luaChunk As LUA_Chunk, ByRef find As Long) As Long
Dim I As Long
For I = 1 To luaChunk.numLocals
If luaChunk.locals(I).startpc = find Then _
FindNumLocalsWithStartPC = FindNumLocalsWithStartPC + 1
Next I ' For I = 1 To luaChunk.numLocals
End Function
' Finds the line info for given instruction number and lua chunk.
Private Function FindLineInfo(ByRef luaChunk As LUA_Chunk, ByVal ins As Long) As Long
#If UseLineInfo Then
' Function converted from ANSI C to BASIC (ref: "\luac\print.c" or "\ldebug.c")
Dim refLine As Long, refi As Long
Dim nextLine As Long, nextRef As Long
Dim lineInfo
refLine = 1
refi = 1
If (ins < 1) Or (ins > luaChunk.numInstructions) Or (luaChunk.numLineInfo = 0) Then _
FindLineInfo = -1: _
Exit Function _
Else _
lineInfo = luaChunk.lineInfo
ins = ins - 1
If lineInfo(refi) < 0 Then _
refLine = refLine - lineInfo(refi):
refi = refi + 1
Debug.Assert lineInfo(refi) >= 0
Do While lineInfo(refi) > ins
refLine = refLine - 1
refi = refi - 1
If lineInfo(refi) < 0 Then _
refLine = refLine + lineInfo(refi): _
refi = refi - 1
Debug.Assert lineInfo(refi) >= 0
Loop ' Do While lineInfo(refi) > ins
Debug.Assert lineInfo(refi) >= 0
Do
nextLine = refLine + 1
nextRef = refi + 1
If lineInfo(nextRef) < 0 Then _
nextLine = nextLine - lineInfo(nextRef): _
nextRef = nextRef + 1
Debug.Assert lineInfo(nextRef) >= 0
If lineInfo(nextRef) > ins Then _
Exit Do
refLine = nextLine
refi = nextRef
Loop
FindLineInfo = refLine
#Else
FindLineInfo = -1
#End If
End Function
' Finds the previous condition for the 'if' line (uses line info if enabled)
Private Function FindPreviousCondition(ByVal currIns As Long, ByVal ins As Long, ByRef luaChunk As LUA_Chunk, Optional ByVal includeJMP As Boolean = True, Optional ByVal ingnoreLineInfo As Boolean = False, Optional ByVal bruteForce As Boolean = False) As Long
Dim opCode As LUA_OPCodes
Dim I As Long
FindPreviousCondition = 0
' Try to get the previous IDT_Nil-comparision jump... if possible.
If ins - 2 > 0 Then
opCode = Instruction_GetOPCode(luaChunk.instructions(ins - 2))
' Determine whether the instruction is a jump
If (OP_JMPNE <= opCode) And (opCode <= OP_JMP + IIf(includeJMP, 0, -1)) Then
If (FindLineInfo(luaChunk, ins - 2) = FindLineInfo(luaChunk, ins)) Or ingnoreLineInfo Then
FindPreviousCondition = ins - 2
Exit Function
End If ' If (FindLineInfo(luaChunk, ins - 2) = FindLineInfo(luaChunk, ins)) Or ingnoreLineInfo Then
End If ' If (OP_JMPNE <= opCode) And (opCode <= OP_JMP + IIf(includeJMP, 0, -1)) Then
End If ' If ins - 2 > 0 Then
' Try to get the previous two-comparision jump... if possible.
If ins - 3 > 0 Then
opCode = Instruction_GetOPCode(luaChunk.instructions(ins - 3))
' Determine whether the previous instruction is a jump
If (OP_JMPNE <= opCode) And (opCode <= OP_JMP + IIf(includeJMP, 0, -1)) Then
If (FindLineInfo(luaChunk, ins - 3) = FindLineInfo(luaChunk, ins)) Or ingnoreLineInfo Then
FindPreviousCondition = ins - 3
Exit Function
End If ' If (FindLineInfo(luaChunk, ins - 3) = FindLineInfo(luaChunk, ins)) Or ingnoreLineInfo Then
End If ' If (OP_JMPNE <= opCode) And (opCode <= OP_JMP + IIf(includeJMP, 0, -1)) Then
End If ' If ins - 3 > 0 Then
If bruteForce Then
For I = ins - 1 To 1 Step -1
opCode = Instruction_GetOPCode(luaChunk.instructions(I))
' Determine whether the previous instruction is a jump
If (OP_JMPNE <= opCode) And (opCode <= OP_JMP + IIf(includeJMP, 0, -1)) Then
If (FindLineInfo(luaChunk, I) = FindLineInfo(luaChunk, ins)) Or ingnoreLineInfo Then
FindPreviousCondition = I
Exit Function
End If ' If (FindLineInfo(luaChunk, I) = FindLineInfo(luaChunk, ins)) Or ingnoreLineInfo Then
End If ' If (OP_JMPNE <= opCode) And (opCode <= OP_JMP + IIf(includeJMP, 0, -1)) Then
Next I ' For I = ins - 1 To 1 Step -1
End If ' If bruteForce Then
End Function
' Finds the next condition for the 'if' line (uses line info if enabled)
Private Function FindNextCondition(ByVal currIns As Long, ByVal ins As Long, ByRef luaChunk As LUA_Chunk, Optional ByVal includeJMP As Boolean = True, Optional ByVal overrideLineInfo As Boolean = False) As Long
Dim opCode As LUA_OPCodes
FindNextCondition = 0
' Try to get the next IDT_Nil-comparision jump... if possible.
If luaChunk.numInstructions > 2 + ins Then
opCode = Instruction_GetOPCode(luaChunk.instructions(2 + ins))
' Determine whether the next instruction is a jump
If (OP_JMPNE <= opCode) And (opCode <= OP_JMP + IIf(includeJMP, 0, -1)) Then
If (FindLineInfo(luaChunk, ins + 2) = FindLineInfo(luaChunk, ins)) Or overrideLineInfo Then
FindNextCondition = 2 + ins
Exit Function
End If ' If (FindLineInfo(luaChunk, ins + 2) = FindLineInfo(luaChunk, ins)) Or overrideLineInfo Then
End If ' If (OP_JMPNE <= opCode) And (opCode <= OP_JMP + IIf(includeJMP, 0, -1)) Then
End If ' If luaChunk.numInstructions > 2 + ins Then
' Try to get the next two-comparision jump... if possible.
If luaChunk.numInstructions > 3 + ins Then
opCode = Instruction_GetOPCode(luaChunk.instructions(3 + ins))
' Determine whether the instruction is a jump
If (OP_JMPNE <= opCode) And (opCode <= OP_JMP + IIf(includeJMP, 0, -1)) Then
If (FindLineInfo(luaChunk, ins + 3) = FindLineInfo(luaChunk, ins)) Or overrideLineInfo Then
FindNextCondition = 3 + ins
Exit Function
End If ' If (FindLineInfo(luaChunk, ins + 3) = FindLineInfo(luaChunk, ins)) Or overrideLineInfo Then
End If ' If (OP_JMPNE <= opCode) And (opCode <= OP_JMP + IIf(includeJMP, 0, -1)) Then
End If ' If luaChunk.numInstructions > 3 + ins Then
opCode = Instruction_GetOPCode(luaChunk.instructions(ins + Instruction_GetSArg(currIns)))
' Determine whether the instruction is a jump
If (OP_JMPNE <= opCode) And (opCode <= OP_JMP + IIf(includeJMP, 0, -1)) Then
If (FindLineInfo(luaChunk, ins + Instruction_GetSArg(currIns)) = FindLineInfo(luaChunk, ins)) Or overrideLineInfo Then
FindNextCondition = ins + Instruction_GetSArg(currIns)
End If ' If (FindLineInfo(luaChunk, ins + Instruction_GetSArg(currIns)) = FindLineInfo(luaChunk, ins)) Or overrideLineInfo Then
End If ' If (OP_JMPNE <= opCode) And (opCode <= OP_JMP + IIf(includeJMP, 0, -1)) Then
End Function
' Finds the next condition for the 'if' line (uses line info if enabled) (preference to JMP value)
Private Function FindNextCondition_PrefJMP(ByVal currIns As Long, ByVal ins As Long, ByRef luaChunk As LUA_Chunk, Optional ByVal includeJMP As Boolean = True) As Long
Dim opCode As LUA_OPCodes
FindNextCondition_PrefJMP = 0
opCode = Instruction_GetOPCode(luaChunk.instructions(ins + Instruction_GetSArg(currIns)))
' Determine whether the instruction is a jump
If (OP_JMPNE <= opCode) And (opCode <= OP_JMP + IIf(includeJMP, 0, -1)) Then
If FindLineInfo(luaChunk, Instruction_GetSArg(currIns) + ins) = FindLineInfo(luaChunk, ins) Then
FindNextCondition_PrefJMP = ins + Instruction_GetSArg(currIns)
Exit Function
End If ' If FindLineInfo(luaChunk, Instruction_GetSArg(currIns) + ins) = FindLineInfo(luaChunk, ins) Then
End If ' If (OP_JMPNE <= opCode) And (opCode <= OP_JMP + IIf(includeJMP, 0, -1)) Then
' Try to get the next IDT_Nil-comparision jump... if possible.
If luaChunk.numInstructions > 2 + ins Then
opCode = Instruction_GetOPCode(luaChunk.instructions(2 + ins))
' Determine whether the next instruction is a jump
If (OP_JMPNE <= opCode) And (opCode <= OP_JMP + IIf(includeJMP, 0, -1)) Then
If FindLineInfo(luaChunk, ins + 2) = FindLineInfo(luaChunk, ins) Then
FindNextCondition_PrefJMP = 2 + ins
Exit Function
End If ' If FindLineInfo(luaChunk, ins + 2) = FindLineInfo(luaChunk, ins) Then
End If ' If (OP_JMPNE <= opCode) And (opCode <= OP_JMP + IIf(includeJMP, 0, -1)) Then
End If ' If luaChunk.numInstructions > 2 + ins Then
' Try to get the next two-comparision jump... if possible.
If luaChunk.numInstructions > 3 + ins Then
opCode = Instruction_GetOPCode(luaChunk.instructions(3 + ins))
' Determine whether the instruction is a jump
If (OP_JMPNE <= opCode) And (opCode <= OP_JMP + IIf(includeJMP, 0, -1)) Then
If FindLineInfo(luaChunk, ins + Instruction_GetSArg(currIns)) = FindLineInfo(luaChunk, ins) Then
FindNextCondition_PrefJMP = 3 + ins
End If ' If FindLineInfo(luaChunk, ins + Instruction_GetSArg(currIns)) = FindLineInfo(luaChunk, ins) Then
End If ' If (OP_JMPNE <= opCode) And (opCode <= OP_JMP + IIf(includeJMP, 0, -1)) Then
End If ' If luaChunk.numInstructions > 3 + ins Then
End Function
' Finds the end of this 'if' line (uses line info if enabled)
Private Function FindEndOfJump(ByVal currIns As Long, ByVal ins As Long, ByRef luaChunk As LUA_Chunk) As Long
Dim lastValue As Long
lastValue = ins ' Don't forget to initialize me!
FindEndOfJump = FindNextCondition_PrefJMP(currIns, ins, luaChunk)
Do While Not FindEndOfJump = 0
lastValue = FindEndOfJump
FindEndOfJump = FindNextCondition_PrefJMP(luaChunk.instructions(lastValue), lastValue, luaChunk)
' Safety catch: Jumps with 0 pc offset!
If lastValue = FindEndOfJump Then Exit Do
Loop ' Do While Not FindEndOfJump = 0
FindEndOfJump = Instruction_GetSArg(luaChunk.instructions(lastValue)) + lastValue + 1
End Function
' Tries to findout whether the given block (use last condition only!) is a 'elseif' or an 'if' block.
Private Function FindELSEIFPresence(ByVal ins As Long, ByRef luaChunk As LUA_Chunk) As Boolean
Dim I As Long, J As Long
Dim jmpPrev As Long, jmpNext As Long, jmpCurr As Long
' For an 'elseif', either
' i) we have the previous unconditional jump pointing to instruction which this instruction does,
' or, ii) we have two unconditional jumps, both pointing to same instruction.
' Note: The previous jump will always be 1 'line' behind. Not more, not less (it's true, think on it).
' First try using the jump register.
'If jumpRP < 2 Then Exit Function
'
'For I = 2 To jumpRP
' If jumpR(I).jmpE = jumpR(I - 1).jmpE Then
' FindELSEIFPresence = True
' Exit Function
' End If ' If jumpR(I).jmpE = jumpR(I - 1).jmpE Then
'Next I ' For I = 1 To jumpRP
'
' Then manually check, if jump register doesn't reference it...
'Debug.Assert 0 ' should never come here in the first place (if we have a last jump, ofcourse).
GetCurrJmp:
jmpCurr = 1 + ins + Instruction_GetSArg(luaChunk.instructions(ins))
GetPrevJump:
' Try to find the previous condition on the same line.
I = FindPreviousCondition(luaChunk.instructions(ins), ins, luaChunk, , True, True)
If I = 0 Then _
FindELSEIFPresence = False: _
Exit Function
' Get the unconditional jump!
Do While Not I = 0
If Instruction_GetOPCode(luaChunk.instructions(I)) = OP_JMP Then
' Compare it's lineinfo.
If FindLineInfo(luaChunk, I) = FindLineInfo(luaChunk, ins) - 1 Then
jmpPrev = 1 + I + Instruction_GetSArg(luaChunk.instructions(I))
Exit Do
End If ' If FindLineInfo(luaChunk, I) = FindLineInfo(luaChunk, ins) - 1 Then
End If ' If Instruction_GetOPCode(luaChunk.instructions(I)) = OP_JMP Then
J = I
I = FindPreviousCondition(luaChunk.instructions(J), J, luaChunk, , True)
If I = J Then _
Exit Do
Loop ' Do While Not I = 0
I = J
' If jmpPrev = 0, then this is no 'elseif' block...
If jmpPrev = 0 Then _
FindELSEIFPresence = False: _
Exit Function
If jmpCurr = jmpPrev Then _
FindELSEIFPresence = True: _
Exit Function
' Try to get the next condition (no lineinfos).
I = FindNextCondition(luaChunk.instructions(ins), ins, luaChunk, , True)
GetNextJump:
If I = 0 Then
I = FindNextCondition(luaChunk.instructions(I), I, luaChunk, , True)
If Instruction_GetOPCode(I) = OP_JMP Then
J = 1 + I + Instruction_GetSArg(luaChunk.instructions(I))
If jmpCurr = J Then _
jmpNext = J: _
GoTo Ending
Else ' If Instruction_GetOPCode(I) = OP_JMP Then
GoTo GetNextJump
End If ' If Instruction_GetOPCode(I) = OP_JMP Then
Else ' If I = 0 Then
jmpNext = 1 + I + Instruction_GetSArg(luaChunk.instructions(I))
End If ' If I = 0 Then
Ending:
If (jmpCurr = jmpNext) Or (jmpPrev = jmpNext) Then _
FindELSEIFPresence = True: _
Exit Function _
Else _
FindELSEIFPresence = False: _
Exit Function
End Function
' Tries to find out whether 'else' should be written at this JMP or not.
Private Function FindELSERequirement(ByVal ins As Long, ByRef luaChunk As LUA_Chunk) As Boolean
Dim I As Long, J As Long, K As Long
' There is a need of writing 'else', when the next jump instruction on the next line is present.
' (and we are NOT in a 'while' loop)
FindELSERequirement = True
' If this is part of a while loop, then no 'else' is needed.
If Instruction_GetSArg(luaChunk.instructions(ins)) < 0 Then FindELSERequirement = False: Exit Function
For I = ins + 1 To luaChunk.numInstructions
J = Instruction_GetOPCode(luaChunk.instructions(I))
If (OP_JMPNE <= J) And (J <= OP_JMPONF) Then _
If FindLineInfo(luaChunk, I) - 1 = FindLineInfo(luaChunk, ins) Then _
Exit For
Next I ' For I = ins + 1 To luaChunk.numInstructions
If I = luaChunk.numInstructions + 1 Then _
Exit Function
FindELSERequirement = False
End Function
' Tries to find out whether we need an 'end' at this instruction or not.
Private Function FindENDRequirement(ByVal ins As Long, ByRef luaChunk As LUA_Chunk) As Long
Dim I As Long
' We always need an 'end' on the last instruction, whenever applicable.
If ins = luaChunk.numInstructions Then _
FindENDRequirement = ins: _
Exit Function
' There is a need for 'end', when two consecutive jumps (no relation betw. line infos) send jump to
' the same pos (this happens in case of nested 'if' blocks ending at same instruction).
For I = ins + 1 To luaChunk.numInstructions
If (OP_JMPNE <= Instruction_GetOPCode(luaChunk.instructions(I))) And _
(Instruction_GetOPCode(luaChunk.instructions(I)) <= OP_JMPONF) And _
Not Instruction_GetOPCode(luaChunk.instructions(I)) = OP_JMP Then _
I = luaChunk.numInstructions + 1: _
Exit For
If Instruction_GetOPCode(luaChunk.instructions(I)) = OP_JMP Then _
If Instruction_GetSArg(luaChunk.instructions(I)) + I = Instruction_GetSArg(luaChunk.instructions(ins)) + ins Then _
Exit For
Next I ' For I = ins + 1 To luaChunk.numInstructions
If I = luaChunk.numInstructions + 1 Then _
Exit Function
FindENDRequirement = I
End Function
' Determines presence of 'or' or 'and' between this jump instruction and next jump instruction.
Private Function FindORPresence(ByVal instructionNr As Long, ByRef luaChunk As LUA_Chunk) As Boolean
Dim I As Long, J As Long
Dim ins() As Long, nIns() As Long, jmpT() As Long, jmpF() As Long, swaped() As Boolean
Dim tIns As Long, tNIns As Long, tJmpT As Long, tJmpF As Long
Dim cIPos As Long
' For an 'or', the only known condition is (due to their nature),
' that: in the IDT_Table of conditions, if T and F jump instructions are in a descending order, and
' if one set doesn't match with the instruction, then an 'and' is present for that instruction.
' FIRST CACHE CURRENT STATE OF INSTRUCTIONS...
ReDim ins(0), nIns(0), jmpT(0), jmpF(0), swaped(0)
tNIns = instructionNr
tIns = luaChunk.instructions(tNIns)
tJmpT = Instruction_GetSArg(tIns) + tNIns + 1
tJmpF = tNIns + 1
' Incase this is the very first instruction...
nIns(0) = tNIns
ins(0) = tIns
jmpT(0) = tJmpT
jmpF(0) = tJmpF
' Get the number of instructions, for 'if' before this...
J = FindPreviousCondition(tIns, tNIns, luaChunk, False)
Do While Not J = 0
nIns(I) = J
ins(I) = luaChunk.instructions(J)
jmpT(I) = Instruction_GetSArg(ins(I)) + J + 1
jmpF(I) = J + 1
I = I + 1
J = FindPreviousCondition(ins(I - 1), nIns(I - 1), luaChunk, False)
ReDim Preserve ins(I), nIns(I), jmpT(I), jmpF(I), swaped(I)
Loop ' Do While Not J = 0
' But the instructions we have are inverted!
For J = 0 To (I - 1) \ 2
If (Not I - J - 1 = J) And (Not I - J - 1 < 0) Then
' So invert them, we'll instructions in the correct order.
swap nIns(J), nIns(I - J - 1)
swap ins(J), ins(I - J - 1)
swap jmpT(J), jmpT(I - J - 1)
swap jmpF(J), jmpF(I - J - 1)
End If ' If (Not I - J - 1 = J) And (Not I - J - 1 < 0) Then
Next J ' For J = 0 To (I - 1) \ 2
' This instruction...
cIPos = I
nIns(I) = tNIns
ins(I) = tIns
jmpT(I) = tJmpT
jmpF(I) = tJmpF
' ... and the instructions after this...
J = FindNextCondition(ins(I), nIns(I), luaChunk, False)
If J = instructionNr Then J = 0
' If J = 0 (ie NO conditions after this) then this is an 'and' (and an end too, no doubt!),
' else, go ahead, caching...
If J Then _
I = I + 1: _
ReDim Preserve ins(I), nIns(I), jmpT(I), jmpF(I), swaped(I) _
Else _
FindORPresence = False: _
Exit Function
Do While Not J = 0
nIns(I) = J
ins(I) = luaChunk.instructions(J)
jmpT(I) = Instruction_GetSArg(ins(I)) + J + 1
jmpF(I) = J + 1
J = FindNextCondition(ins(I), nIns(I), luaChunk, False)
If J Then _
I = I + 1: _
ReDim Preserve ins(I), nIns(I), jmpT(I), jmpF(I), swaped(I) _
Else _
Exit Do
Loop ' Do While Not J = 0
#If PrintStack Then
For J = 0 To UBound(ins())
Debug.Print nIns(J), Instruction_GetOPCode(ins(J)), jmpT(J), jmpF(J), IIf(J = cIPos, "<<", "")
Next J
#End If
' THEN, SWAP AND STORE AS NEEDED...
' first swap the last one... if we have only two conditions, then this could get messy if we dont...
swap jmpT(I), jmpF(I)
swaped(I) = True
' swap the first one, if needed.
If (jmpT(0) = jmpF(1)) Or (jmpT(1) = jmpF(0)) Then _
swap jmpT(0), jmpF(0): _
swaped(0) = True
' swap others...
For J = 1 To I - 1
If (jmpT(J) = jmpF(J - 1)) Or (jmpT(J - 1) = jmpF(J)) Then _
swap jmpT(J), jmpF(J): _
swaped(J) = True
Next J ' For J = 1 To I - 1
' finally swap the last one (last is always and, like, 'x and true' where x = <condition>.
swap jmpT(J), jmpF(J)
swaped(J) = True
' FINALLY, IF THE CONCERNED VARIABLE WAS SWAPPED, THEN 'or' IS NOT PRESENT AFTER IT,
' ELSE 'or' IS PRESENT.
FindORPresence = Not swaped(cIPos)
End Function
' Gets the LUA function with this pointer.
Private Function FindLUAFunction(ByVal funcPtr As Long, ByRef theLUA As LUA_File) As LUA_Chunk
Dim I As Long
For I = 1 To UBound(theLUA.chunks())
If theLUA.chunks(I).funcPtr = funcPtr Then _
FindLUAFunction = theLUA.chunks(I): _
Exit Function
Next I ' For I = 1 To UBound(theLUA.chunks())
For I = 1 To UBound(theLUA.funcs())
If theLUA.funcs(I).funcPtr = 0 Then _
Exit For
If theLUA.funcs(I).funcPtr = funcPtr Then _
FindLUAFunction = theLUA.funcs(I): _
Exit Function
Next I ' For I = 1 To UBound(theLUA.funcs())
' We don't 'know' this function.
If Not funcPtr = 0 Then _
Debug.Assert 0
End Function
' Gets the tab for the function with the given pointer.
Private Function FindLUAFunctionTab(ByVal funcPtr As Long, ByRef theLUA As LUA_File) As Long
Dim theFunc As LUA_Chunk
' First get this function
theFunc = FindLUAFunction(funcPtr, theLUA)
Do While Not theFunc.parentPtr = 0
' For each valid parent, we have an extra tab...
FindLUAFunctionTab = FindLUAFunctionTab + 1
' Get this function's parent.
If Not theFunc.parentPtr = 0 Then _
theFunc = FindLUAFunction(theFunc.parentPtr, theLUA)
Loop ' Do While Not theFunc.parentPtr = 0
End Function
' Processes the given value for output, for example:
' - In a IDT_Table, if it's raw (no data, just value indicating number of entries), then IDT_Nil's are written.
' - For a stack type 'IDT_Nil', 'IDT_Nil' is written out, even if it's not so in the stack value (for safety).
Private Function ProcessValueForOutput(Optional ByVal offset As Long = 0) As String
Dim I As Long
Select Case stack(stackP + offset).type
Case interpretationDataType.IDT_Table
If IsNumeric(stack(stackP + offset).value) Then
' Empty IDT_Table.
If CLng(stack(stackP + offset).value) = 0 Then
' No data
ProcessValueForOutput = "{}"
Else ' If stack(stackP + offset).value = 0 Then
' Data, but not defined yet...
' fill with Null's (IDT_Nil's)
ProcessValueForOutput = "{"
For I = 1 To stack(stackP + offset).value
ProcessValueForOutput = ProcessValueForOutput & _
LUA_Null & _
IIf(Not I = stack(stackP + offset).value, ", ", "")
Next I ' For I = 1 To stack(stackP + offset).value
ProcessValueForOutput = ProcessValueForOutput & _
"}"
End If ' If stack(stackP + offset).value = 0 Then
Else ' If IsNumeric(stack(stackP + offset).value) Then
' Filled IDT_Table.
ProcessValueForOutput = stack(stackP + offset).value
ProcessValueForOutput = EscapeBacklashesInString(ProcessValueForOutput)
End If ' If IsNumeric(stack(stackP + offset).value) Then
Case interpretationDataType.IDT_Nil
ProcessValueForOutput = LUA_Null
Debug.Assert stack(stackP + offset).value = LUA_Null
Case Else
ProcessValueForOutput = IIf(InStr(1, stack(stackP + offset).value, "[[") > 0, _
" ", _
"" _
) & _
stack(stackP + offset).value
ProcessValueForOutput = EscapeBacklashesInString(ProcessValueForOutput)
End Select ' Select Case stack(stackP + offset).type
End Function
Private Function ProcessTableValue(ByRef tbl As String, ByRef key As String) As String
Dim dotted As Boolean
#If 0 Then
dotted = (NumTokens(key, LUA_Tokens, " ") = 1)
dotted = dotted And (Not IsNumeric(key))
dotted = dotted And ((InStr(1, key, Chr$(34)) = 1) Or (InStr(1, key, "[[") = 1))
If ((InStr(1, key, Chr$(34)) = 1) Or (InStr(1, key, "[[") = 1)) Then _
dotted = dotted And (NumTokens(UnquoteString(key), LUA_Tokens, " ") = 1)
#Else
dotted = False
#End If
If dotted Then
ProcessTableValue = tbl & _
"." & _
(key)
Else ' If dotted Then
ProcessTableValue = tbl & _
"[" & _
key & _
"]"
End If ' If dotted Then
End Function
' Processes current line for "output", ie for ";" and CR-LF.
Private Sub PushStatement(ByRef out As String, ByRef statement As String, Optional ByVal semiColon As Boolean = True, Optional crlf As Boolean = True)
Dim tmpStr As String
tmpStr = statement
' Remove multiple spaces.
Do While InStr(1, tmpStr, " ")
tmpStr = Replace(tmpStr, " ", " ")
Loop
' Dump statement here.
out = out & _
String(max(0, level), Chr$(9)) & _
LTrim( _
RTrim(tmpStr) _
) & _
IIf(Left(statement, 2) = "--", "", IIf(semiColon, IIf(Len(statement) > 0, ";", ""), "")) & _
IIf(crlf, vbCrLf, "")
End Sub
' Pushes the given jump into the register
Private Function GetLocalInStack(Optional ByRef name As String) As Long
GetLocalInStack = 1
Do While BitsPresent(stack(GetLocalInStack).flags, IDF_IsALocalValue) Or (stack(GetLocalInStack).type = IDT_LocalVar)
' Is this the one?
If Not Len(name) = 0 Then _
If stack(GetLocalInStack).value = name Or stack(GetLocalInStack).extraString = name Then _
Exit Function
' Next!
GetLocalInStack = GetLocalInStack + 1
Loop ' Do While BitsPresent(stack(GetLocalInStack).flags, IDF_IsALocalValue) Or (stack(GetLocalInStack).type = IDT_LocalVar)
GetLocalInStack = GetLocalInStack - 1
End Function
' Method for "Push"-ing values into the stack.
' First search for a viable local, and
' i) if found, assign value to it (change to stack, 1st value is popped, and this is pushed).
' ii) if not found, push value in stack.
' If we're return value for a function, then set this IN for return.
' Otherwise, if FORCED to push value, then do so.
Private Sub PushValueInStack(ByRef value As String, ByVal dType As interpretationDataType, ByVal instructionNr As Long, ByRef luaChunk As LUA_Chunk, ByRef outLUA As String, Optional ByVal searchForLocal As Boolean = True)
Dim I As Long, J As Long
Dim tmpStr As String
If (searchForLocal) Then
' Try to search for a feasible (ie unused, here) local with 'active' state from here.
For J = FindMatchingStartPCForLocal(luaChunk, instructionNr) To FindMatchingStartPCForLastLocal(luaChunk, instructionNr)
If Not localProcessed(J) Then
PopLocalFromStack luaChunk.locals(J).name
I = PushLocalInStack(value, dType)
stack(I).extraString = luaChunk.locals(J).name
stack(I).flags = IDF_IsALocalValue
tmpStr = _
"local " & _
luaChunk.locals(J).name & _
"=" & _
ProcessValueForOutput
' mark this local done.
localProcessed(J) = True
' Don't forget this!
PushStatement outLUA, tmpStr
Exit Sub
End If ' If Not localProcessed(J) Then
Next J ' For J = FindMatchingStartPCForLocal(luaChunk, instructionNr) To FindMatchingStartPCForLastLocal(luaChunk, instructionNr)
End If ' If (searchForLocal) Then
stackP = stackP + 1
stack(stackP).value = value
stack(stackP).type = dType
End Sub
' Method for "Push"-ing values into the stack on the TOP.
Private Function PushValueInStackTop(ByRef value As String, ByVal dType As interpretationDataType) As Long
Dim I As Long
stackP = stackP + 1
For I = stackP - 1 To 1 Step -1
If Not (stack(I).type = IDT_LocalVar) And Not BitsPresent(stack(I).flags, IDF_IsALocalValue) Then
stack(I + 1).type = stack(I).type
stack(I + 1).value = stack(I).value
stack(I + 1).flags = stack(I).flags
stack(I + 1).extraString = stack(I).extraString
stack(I + 1).extraValue = stack(I).extraValue
Else ' If Not (stack(I).type = IDT_LocalVar) And Not BitsPresent(stack(I).flags, IDF_IsALocalValue) Then
' don't move a local var!
stack(I + 1).type = dType
stack(I + 1).value = value
stack(I + 1).flags = 0
stack(I + 1).extraString = ""
stack(I + 1).extraValue = 0
PushValueInStackTop = I + 1
Exit Function
End If ' If Not (stack(I).type = IDT_LocalVar) And Not BitsPresent(stack(I).flags, IDF_IsALocalValue) Then
Next I ' For I = stackP - 1 To 1 Step -1
stack(1).type = dType
stack(1).value = value
stack(1).flags = 0
stack(1).extraString = ""
stack(1).extraValue = 0
PushValueInStackTop = 1
End Function
' Pushes a local in the stack.
Private Function PushLocalInStack(ByRef value As String, ByVal dType As interpretationDataFlags) As Long
PushLocalInStack = PushValueInStackTop(value, dType)
stack(PushLocalInStack).flags = IDF_IsALocalValue
End Function
' Pushes the given jump into the jump register.
'Private Sub PushJumpInRegister(ByRef luaChunk As LUA_Chunk, ByVal pos As Long, ByVal jType As jumpTypes, Optional ByRef condition As String = "")
' Dim tmpLong
'
' jumpRP = jumpRP + 1
'
' jumpR(jumpRP).type = jType
' jumpR(jumpRP).condition = condition
'
' Select Case jType
' Case JT_Unconditional
' jumpR(jumpRP).jmpT = Instruction_GetSArg(luaChunk.instructions(pos)) + pos + 1
' jumpR(jumpRP).jmpF = jumpR(jumpRP).jmpT
' jumpR(jumpRP).jmpE = jumpR(jumpRP).jmpT
' Case Else ' JT_Unconditional, JT_While
' jumpR(jumpRP).jmpT = pos + 1
' jumpR(jumpRP).jmpF = Instruction_GetSArg(luaChunk.instructions(pos)) + pos + 1
'
' tmpLong = Instruction_GetOPCode(luaChunk.instructions(jumpR(jumpRP).jmpF - 1))
'
' If (OP_JMPNE <= tmpLong) And (tmpLong <= OP_JMPONF) Then
' jumpR(jumpRP).jmpE = FindEndOfJump(luaChunk.instructions(jumpR(jumpRP).jmpF - 1), jumpR(jumpRP).jmpF - 1, luaChunk)
' ElseIf OP_JMP = tmpLong Then
' jumpR(jumpRP).jmpE = Instruction_GetSArg(luaChunk.instructions(jumpR(jumpRP).jmpF - 1)) + _
' (jumpR(jumpRP).jmpF - 1) + _
' 1
' Else