/programs/develop/oberon07/source/AMD64.ob07 |
---|
0,0 → 1,2408 |
(* |
BSD 2-Clause License |
Copyright (c) 2018-2021, Anton Krotov |
All rights reserved. |
*) |
MODULE AMD64; |
IMPORT IL, BIN, WR := WRITER, CHL := CHUNKLISTS, LISTS, PATHS, PROG, TARGETS, |
REG, UTILS, S := STRINGS, PE32, ELF, X86, ERRORS; |
CONST |
rax = REG.R0; |
r10 = REG.R10; |
r11 = REG.R11; |
rcx = REG.R1; |
rdx = REG.R2; |
r8 = REG.R8; |
r9 = REG.R9; |
rsp = 4; |
rbp = 5; |
rsi = 6; |
rdi = 7; |
MAX_XMM = 5; |
je = 84H; jne = 85H; jl = 8CH; jge = 8DH; jle = 8EH; jg = 8FH; jb = 82H; |
sete = 94H; setne = 95H; setl = 9CH; setge = 9DH; setle = 9EH; setg = 9FH; setc = 92H; setnc = 93H; |
shl = IL.opLSL2; shr = IL.opLSR2; sar = IL.opASR2; ror = IL.opROR2; |
sCODE = BIN.PICCODE; |
sDATA = BIN.PICDATA; |
sBSS = BIN.PICBSS; |
sIMP = BIN.PICIMP; |
FPR_ERR = 41; |
TYPE |
COMMAND = IL.COMMAND; |
Number = POINTER TO RECORD (LISTS.ITEM) value: INTEGER END; |
OPRR = PROCEDURE (reg1, reg2: INTEGER); |
VAR |
R: REG.REGS; |
Numbers: LISTS.LIST; |
Numbers_Count: INTEGER; |
Numbers_Offs: INTEGER; |
prog: BIN.PROGRAM; |
tcount: INTEGER; |
dllret, sofinit: INTEGER; |
Win64RegPar: ARRAY 4 OF INTEGER; |
SystemVRegPar: ARRAY 6 OF INTEGER; |
Xmm: ARRAY 1000 OF INTEGER; |
fname: PATHS.PATH; |
PROCEDURE OutByte (b: BYTE); |
BEGIN |
X86.OutByte(b) |
END OutByte; |
PROCEDURE OutByte2 (a, b: BYTE); |
BEGIN |
X86.OutByte(a); |
X86.OutByte(b) |
END OutByte2; |
PROCEDURE OutByte3 (a, b, c: BYTE); |
BEGIN |
X86.OutByte(a); |
X86.OutByte(b); |
X86.OutByte(c) |
END OutByte3; |
PROCEDURE OutInt (n: INTEGER); |
BEGIN |
X86.OutByte(n MOD 256); |
X86.OutByte(UTILS.Byte(n, 1)); |
X86.OutByte(UTILS.Byte(n, 2)); |
X86.OutByte(UTILS.Byte(n, 3)) |
END OutInt; |
PROCEDURE short (n: INTEGER): INTEGER; |
RETURN 2 * ORD(X86.isByte(n)) |
END short; |
PROCEDURE long (n: INTEGER): INTEGER; |
RETURN 40H * ORD(~X86.isByte(n)) |
END long; |
PROCEDURE OutIntByte (n: INTEGER); |
BEGIN |
IF X86.isByte(n) THEN |
OutByte(n MOD 256) |
ELSE |
OutInt(n) |
END |
END OutIntByte; |
PROCEDURE isLong (n: INTEGER): BOOLEAN; |
RETURN (n > UTILS.max32) OR (n < UTILS.min32) |
END isLong; |
PROCEDURE NewNumber (value: INTEGER); |
VAR |
number: Number; |
BEGIN |
NEW(number); |
number.value := value; |
LISTS.push(Numbers, number); |
INC(Numbers_Count) |
END NewNumber; |
PROCEDURE NewLabel (): INTEGER; |
BEGIN |
BIN.NewLabel(prog) |
RETURN IL.NewLabel() |
END NewLabel; |
PROCEDURE Rex (reg1, reg2: INTEGER); |
BEGIN |
OutByte(48H + reg1 DIV 8 + 4 * (reg2 DIV 8)) |
END Rex; |
PROCEDURE lea (reg, offset, section: INTEGER); |
BEGIN |
Rex(0, reg); |
OutByte2(8DH, 05H + 8 * (reg MOD 8)); (* lea reg, [rip + offset] *) |
X86.Reloc(section, offset) |
END lea; |
PROCEDURE oprr (op: BYTE; reg1, reg2: INTEGER); (* op reg1, reg2 *) |
BEGIN |
Rex(reg1, reg2); |
OutByte2(op, 0C0H + 8 * (reg2 MOD 8) + reg1 MOD 8) |
END oprr; |
PROCEDURE oprr2 (op1, op2: BYTE; reg1, reg2: INTEGER); (* op reg1, reg2 *) |
BEGIN |
Rex(reg1, reg2); |
OutByte3(op1, op2, 0C0H + 8 * (reg2 MOD 8) + reg1 MOD 8) |
END oprr2; |
PROCEDURE mov (reg1, reg2: INTEGER); (* mov reg1, reg2 *) |
BEGIN |
oprr(89H, reg1, reg2) |
END mov; |
PROCEDURE xor (reg1, reg2: INTEGER); (* xor reg1, reg2 *) |
BEGIN |
oprr(31H, reg1, reg2) |
END xor; |
PROCEDURE and (reg1, reg2: INTEGER); (* and reg1, reg2 *) |
BEGIN |
oprr(21H, reg1, reg2) |
END and; |
PROCEDURE _or (reg1, reg2: INTEGER); (* or reg1, reg2 *) |
BEGIN |
oprr(09H, reg1, reg2) |
END _or; |
PROCEDURE add (reg1, reg2: INTEGER); (* add reg1, reg2 *) |
BEGIN |
oprr(01H, reg1, reg2) |
END add; |
PROCEDURE sub (reg1, reg2: INTEGER); (* sub reg1, reg2 *) |
BEGIN |
oprr(29H, reg1, reg2) |
END sub; |
PROCEDURE xchg (reg1, reg2: INTEGER); (* xchg reg1, reg2 *) |
BEGIN |
IF rax IN {reg1, reg2} THEN |
Rex(reg1 + reg2, 0); |
OutByte(90H + (reg1 + reg2) MOD 8) |
ELSE |
oprr(87H, reg1, reg2) |
END |
END xchg; |
PROCEDURE cmprr (reg1, reg2: INTEGER); (* cmp reg1, reg2 *) |
BEGIN |
oprr(39H, reg1, reg2) |
END cmprr; |
PROCEDURE pop (reg: INTEGER); (* pop reg *) |
BEGIN |
IF reg >= 8 THEN |
OutByte(41H) |
END; |
OutByte(58H + reg MOD 8) |
END pop; |
PROCEDURE push (reg: INTEGER); (* push reg *) |
BEGIN |
IF reg >= 8 THEN |
OutByte(41H) |
END; |
OutByte(50H + reg MOD 8) |
END push; |
PROCEDURE decr (reg: INTEGER); |
BEGIN |
Rex(reg, 0); |
OutByte2(0FFH, 0C8H + reg MOD 8) (* dec reg1 *) |
END decr; |
PROCEDURE incr (reg: INTEGER); |
BEGIN |
Rex(reg, 0); |
OutByte2(0FFH, 0C0H + reg MOD 8) (* inc reg1 *) |
END incr; |
PROCEDURE drop; |
BEGIN |
REG.Drop(R) |
END drop; |
PROCEDURE GetAnyReg (): INTEGER; |
RETURN REG.GetAnyReg(R) |
END GetAnyReg; |
PROCEDURE callimp (label: INTEGER); |
BEGIN |
OutByte2(0FFH, 15H); (* call qword[rip + label + IMP] *) |
X86.Reloc(sIMP, label) |
END callimp; |
PROCEDURE pushDA (offs: INTEGER); |
VAR |
reg: INTEGER; |
BEGIN |
reg := GetAnyReg(); |
lea(reg, offs, sDATA); |
push(reg); |
drop |
END pushDA; |
PROCEDURE CallRTL (proc: INTEGER); |
VAR |
label: INTEGER; |
BEGIN |
label := IL.codes.rtl[proc]; |
IF label < 0 THEN |
callimp(-label) |
ELSE |
X86.call(label) |
END |
END CallRTL; |
PROCEDURE UnOp (VAR reg: INTEGER); |
BEGIN |
REG.UnOp(R, reg) |
END UnOp; |
PROCEDURE BinOp (VAR reg1, reg2: INTEGER); |
BEGIN |
REG.BinOp(R, reg1, reg2) |
END BinOp; |
PROCEDURE PushAll (NumberOfParameters: INTEGER); |
BEGIN |
REG.PushAll(R); |
DEC(R.pushed, NumberOfParameters) |
END PushAll; |
PROCEDURE movabs (reg, n: INTEGER); |
VAR |
i: INTEGER; |
BEGIN |
Rex(reg, 0); |
OutByte(0B8H + reg MOD 8); (* movabs reg, n *) |
FOR i := 0 TO 7 DO |
OutByte(UTILS.Byte(n, i)) |
END |
END movabs; |
PROCEDURE movrc (reg, n: INTEGER); (* mov reg, n *) |
BEGIN |
IF isLong(n) THEN |
movabs(reg, n) |
ELSIF n = 0 THEN |
xor(reg, reg) |
ELSE |
Rex(reg, 0); |
OutByte2(0C7H, 0C0H + reg MOD 8); |
OutInt(n) |
END |
END movrc; |
PROCEDURE test (reg: INTEGER); (* test reg, reg *) |
BEGIN |
oprr(85H, reg, reg) |
END test; |
PROCEDURE oprlongc (reg, n: INTEGER; oprr: OPRR); |
VAR |
reg2: INTEGER; |
BEGIN |
reg2 := GetAnyReg(); |
ASSERT(reg2 # reg); |
movabs(reg2, n); |
oprr(reg, reg2); |
drop |
END oprlongc; |
PROCEDURE oprc (op, reg, n: INTEGER; oprr: OPRR); |
BEGIN |
IF isLong(n) THEN |
oprlongc(reg, n, oprr) |
ELSE |
Rex(reg, 0); |
X86.oprc(op, reg, n) |
END |
END oprc; |
PROCEDURE cmprc (reg, n: INTEGER); (* cmp reg, n *) |
BEGIN |
IF n = 0 THEN |
test(reg) |
ELSE |
oprc(0F8H, reg, n, cmprr) |
END |
END cmprc; |
PROCEDURE addrc (reg, n: INTEGER); (* add reg, n *) |
BEGIN |
oprc(0C0H, reg, n, add) |
END addrc; |
PROCEDURE subrc (reg, n: INTEGER); (* sub reg, n *) |
BEGIN |
oprc(0E8H, reg, n, sub) |
END subrc; |
PROCEDURE andrc (reg, n: INTEGER); (* and reg, n *) |
BEGIN |
oprc(0E0H, reg, n, and) |
END andrc; |
PROCEDURE orrc (reg, n: INTEGER); (* or reg, n *) |
BEGIN |
oprc(0C8H, reg, n, _or) |
END orrc; |
PROCEDURE xorrc (reg, n: INTEGER); (* xor reg, n *) |
BEGIN |
oprc(0F0H, reg, n, xor) |
END xorrc; |
PROCEDURE pushc (n: INTEGER); |
VAR |
reg2: INTEGER; |
BEGIN |
IF isLong(n) THEN |
reg2 := GetAnyReg(); |
movabs(reg2, n); |
push(reg2); |
drop |
ELSE |
X86.pushc(n) |
END |
END pushc; |
PROCEDURE not (reg: INTEGER); (* not reg *) |
BEGIN |
Rex(reg, 0); |
OutByte2(0F7H, 0D0H + reg MOD 8) |
END not; |
PROCEDURE neg (reg: INTEGER); (* neg reg *) |
BEGIN |
Rex(reg, 0); |
OutByte2(0F7H, 0D8H + reg MOD 8) |
END neg; |
PROCEDURE movzx (reg1, reg2, offs: INTEGER; word: BOOLEAN); (* movzx reg1, byte/word[reg2 + offs] *) |
BEGIN |
Rex(reg2, reg1); |
X86.movzx(reg1, reg2, offs, word) |
END movzx; |
PROCEDURE movmr32 (reg1, offs, reg2: INTEGER); (* mov dword[reg1+offs], reg2_32 *) |
BEGIN |
X86._movrm(reg2, reg1, offs, 32, TRUE) |
END movmr32; |
PROCEDURE movrm32 (reg1, reg2, offs: INTEGER); (* mov reg1_32, dword[reg2+offs] *) |
BEGIN |
X86._movrm(reg1, reg2, offs, 32, FALSE) |
END movrm32; |
PROCEDURE movmr (reg1, offs, reg2: INTEGER); (* mov qword[reg1+offs], reg2 *) |
BEGIN |
X86._movrm(reg2, reg1, offs, 64, TRUE) |
END movmr; |
PROCEDURE movrm (reg1, reg2, offs: INTEGER); (* mov reg1, qword[reg2+offs] *) |
BEGIN |
X86._movrm(reg1, reg2, offs, 64, FALSE) |
END movrm; |
PROCEDURE comisd (xmm1, xmm2: INTEGER); (* comisd xmm1, xmm2 *) |
BEGIN |
OutByte(66H); |
IF (xmm1 >= 8) OR (xmm2 >= 8) THEN |
OutByte(40H + (xmm1 DIV 8) * 4 + xmm2 DIV 8) |
END; |
OutByte3(0FH, 2FH, 0C0H + (xmm1 MOD 8) * 8 + xmm2 MOD 8) |
END comisd; |
PROCEDURE _movsdrm (xmm, reg, offs: INTEGER; mr: BOOLEAN); |
VAR |
b: BYTE; |
BEGIN |
OutByte(0F2H); |
IF (xmm >= 8) OR (reg >= 8) THEN |
OutByte(40H + (xmm DIV 8) * 4 + reg DIV 8) |
END; |
OutByte2(0FH, 10H + ORD(mr)); |
IF (offs = 0) & (reg # rbp) THEN |
b := 0 |
ELSE |
b := 40H + long(offs) |
END; |
OutByte(b + (xmm MOD 8) * 8 + reg MOD 8); |
IF reg = rsp THEN |
OutByte(24H) |
END; |
IF b # 0 THEN |
OutIntByte(offs) |
END |
END _movsdrm; |
PROCEDURE movsdrm (xmm, reg, offs: INTEGER); (* movsd xmm, qword[reg+offs] *) |
BEGIN |
_movsdrm(xmm, reg, offs, FALSE) |
END movsdrm; |
PROCEDURE movsdmr (reg, offs, xmm: INTEGER); (* movsd qword[reg+offs], xmm *) |
BEGIN |
_movsdrm(xmm, reg, offs, TRUE) |
END movsdmr; |
PROCEDURE opxx (op, xmm1, xmm2: INTEGER); |
BEGIN |
OutByte(0F2H); |
IF (xmm1 >= 8) OR (xmm2 >= 8) THEN |
OutByte(40H + (xmm1 DIV 8) * 4 + xmm2 DIV 8) |
END; |
OutByte3(0FH, op, 0C0H + (xmm1 MOD 8) * 8 + xmm2 MOD 8) |
END opxx; |
PROCEDURE jcc (cc, label: INTEGER); (* jcc label *) |
BEGIN |
X86.jcc(cc, label) |
END jcc; |
PROCEDURE shiftrc (op, reg, n: INTEGER); |
BEGIN |
Rex(reg, 0); |
IF n = 1 THEN |
OutByte(0D1H) |
ELSE |
OutByte(0C1H) |
END; |
X86.shift(op, reg MOD 8); |
IF n # 1 THEN |
OutByte(n) |
END |
END shiftrc; |
PROCEDURE GetRegA; |
BEGIN |
ASSERT(REG.GetReg(R, rax)) |
END GetRegA; |
PROCEDURE Win64Passing (params: INTEGER); |
VAR |
n, i: INTEGER; |
BEGIN |
n := params MOD 32; |
params := params DIV 32; |
FOR i := 0 TO n - 1 DO |
IF i IN BITS(params) THEN |
movsdrm(i, rsp, i * 8) |
ELSE |
movrm(Win64RegPar[i], rsp, i * 8) |
END |
END |
END Win64Passing; |
PROCEDURE SysVPassing (params: INTEGER); |
VAR |
n, i, s, p, ofs: INTEGER; |
i_count, f_count: INTEGER; |
reg: BOOLEAN; |
BEGIN |
ASSERT(r11 IN R.regs); |
n := params MOD 32; |
params := params DIV 32; |
s := 0; |
i_count := 0; |
f_count := 0; |
FOR i := 0 TO n - 1 DO |
IF i IN BITS(params) THEN |
INC(f_count) |
ELSE |
INC(i_count) |
END |
END; |
s := MAX(0, f_count - 8) + MAX(0, i_count - 6); |
p := 0; |
subrc(rsp, s * 8); |
i_count := 0; |
f_count := 0; |
FOR i := 0 TO n - 1 DO |
ofs := (i + s) * 8; |
IF i IN BITS(params) THEN |
reg := f_count <= 7; |
IF reg THEN |
movsdrm(f_count, rsp, ofs); |
INC(f_count) |
END |
ELSE |
reg := i_count <= 5; |
IF reg THEN |
movrm(SystemVRegPar[i_count], rsp, ofs); |
INC(i_count) |
END |
END; |
IF ~reg THEN |
movrm(r11, rsp, ofs); |
movmr(rsp, p, r11); |
INC(p, 8) |
END |
END |
END SysVPassing; |
PROCEDURE fcmp (op: INTEGER; xmm: INTEGER); |
VAR |
cc, reg: INTEGER; |
BEGIN |
reg := GetAnyReg(); |
xor(reg, reg); |
CASE op OF |
|IL.opEQF: |
comisd(xmm - 1, xmm); |
cc := sete |
|IL.opNEF: |
comisd(xmm - 1, xmm); |
cc := setne |
|IL.opLTF: |
comisd(xmm - 1, xmm); |
cc := setc |
|IL.opGTF: |
comisd(xmm, xmm - 1); |
cc := setc |
|IL.opLEF: |
comisd(xmm, xmm - 1); |
cc := setnc |
|IL.opGEF: |
comisd(xmm - 1, xmm); |
cc := setnc |
END; |
OutByte2(7AH, 3 + reg DIV 8); (* jp L *) |
X86.setcc(cc, reg) |
(* L: *) |
END fcmp; |
PROCEDURE translate (commands: LISTS.LIST; stroffs: INTEGER); |
VAR |
cmd, next: COMMAND; |
opcode, param1, param2, param3, a, b, c, n, label, L, i, cc: INTEGER; |
reg1, reg2, xmm: INTEGER; |
float: REAL; |
BEGIN |
xmm := -1; |
cmd := commands.first(COMMAND); |
WHILE cmd # NIL DO |
param1 := cmd.param1; |
param2 := cmd.param2; |
opcode := cmd.opcode; |
CASE opcode OF |
|IL.opJMP: |
X86.jmp(param1) |
|IL.opCALL, IL.opWIN64CALL, IL.opSYSVCALL: |
CASE opcode OF |
|IL.opCALL: |
|IL.opWIN64CALL: Win64Passing(param2) |
|IL.opSYSVCALL: SysVPassing(param2) |
END; |
X86.call(param1) |
|IL.opCALLP, IL.opWIN64CALLP, IL.opSYSVCALLP: |
UnOp(reg1); |
IF reg1 # rax THEN |
mov(rax, reg1) |
END; |
drop; |
CASE opcode OF |
|IL.opCALLP: |
|IL.opWIN64CALLP: Win64Passing(param2) |
|IL.opSYSVCALLP: SysVPassing(param2) |
END; |
OutByte2(0FFH, 0D0H); (* call rax *) |
ASSERT(R.top = -1) |
|IL.opCALLI, IL.opWIN64CALLI, IL.opSYSVCALLI: |
CASE opcode OF |
|IL.opCALLI: |
|IL.opWIN64CALLI: Win64Passing(param2) |
|IL.opSYSVCALLI: SysVPassing(param2) |
END; |
callimp(param1) |
|IL.opLABEL: |
X86.SetLabel(param1) |
|IL.opERR: |
CallRTL(IL._error) |
|IL.opONERR: |
pushc(param2); |
X86.jmp(param1) |
|IL.opPUSHC: |
pushc(param2) |
|IL.opPRECALL: |
PushAll(0); |
IF (param2 # 0) & (xmm >= 0) THEN |
subrc(rsp, 8) |
END; |
INC(Xmm[0]); |
Xmm[Xmm[0]] := xmm + 1; |
WHILE xmm >= 0 DO |
subrc(rsp, 8); |
movsdmr(rsp, 0, xmm); |
DEC(xmm) |
END; |
ASSERT(xmm = -1) |
|IL.opWIN64ALIGN16: |
ASSERT(rax IN R.regs); |
mov(rax, rsp); |
andrc(rsp, -16); |
push(rax); |
subrc(rsp, (MAX(param2 - 4, 0) MOD 2 + MAX(4 - param2, 0) + 1) * 8) |
|IL.opSYSVALIGN16: |
ASSERT(rax IN R.regs); |
mov(rax, rsp); |
andrc(rsp, -16); |
push(rax); |
IF ~ODD(param2) THEN |
push(rax) |
END |
|IL.opRESF, IL.opRES: |
ASSERT(R.top = -1); |
ASSERT(xmm = -1); |
n := Xmm[Xmm[0]]; DEC(Xmm[0]); |
IF opcode = IL.opRESF THEN |
INC(xmm); |
IF n > 0 THEN |
movsdmr(rsp, n * 8, 0); |
DEC(xmm); |
INC(n) |
END; |
IF xmm + n > MAX_XMM THEN |
ERRORS.ErrorMsg(fname, param1, param2, FPR_ERR) |
END |
ELSE |
GetRegA |
END; |
WHILE n > 0 DO |
INC(xmm); |
movsdrm(xmm, rsp, 0); |
addrc(rsp, 8); |
DEC(n) |
END |
|IL.opENTER: |
ASSERT(R.top = -1); |
X86.SetLabel(param1); |
param3 := cmd.param3; |
IF param3 > 0 THEN |
push(rbp); |
mov(rbp, rsp); |
n := param3 MOD 32; |
param3 := param3 DIV 32; |
FOR i := 0 TO n - 1 DO |
IF i IN BITS(param3) THEN |
movsdmr(rbp, i * 8 + 16, i) |
ELSE |
movmr(rbp, i * 8 + 16, Win64RegPar[i]) |
END |
END |
ELSIF param3 < 0 THEN |
param3 := -param3; |
n := (param3 MOD 32) * 8; |
param3 := param3 DIV 32; |
pop(r11); |
subrc(rsp, n); |
push(r11); |
push(rbp); |
mov(rbp, rsp); |
a := 0; |
b := 0; |
c := 0; |
INC(n, 16); |
FOR i := 16 TO n - 8 BY 8 DO |
IF ODD(param3) THEN |
IF b <= 7 THEN |
movsdmr(rbp, i, b); |
INC(b) |
ELSE |
movrm(r11, rbp, n + c); |
movmr(rbp, i, r11); |
INC(c, 8) |
END |
ELSE |
IF a <= 5 THEN |
movmr(rbp, i, SystemVRegPar[a]); |
INC(a) |
ELSE |
movrm(r11, rbp, n + c); |
movmr(rbp, i, r11); |
INC(c, 8) |
END |
END; |
param3 := param3 DIV 2 |
END |
ELSE |
push(rbp); |
mov(rbp, rsp) |
END; |
n := param2; |
IF n > 4 THEN |
movrc(rcx, n); |
(* L: *) |
pushc(0); |
OutByte2(0E2H, 0FCH) (* loop L *) |
ELSE |
WHILE n > 0 DO |
pushc(0); |
DEC(n) |
END |
END |
|IL.opLEAVE, IL.opLEAVER, IL.opLEAVEF: |
IF opcode = IL.opLEAVER THEN |
UnOp(reg1); |
IF reg1 # rax THEN |
mov(rax, reg1) |
END; |
drop |
END; |
ASSERT(R.top = -1); |
IF opcode = IL.opLEAVEF THEN |
DEC(xmm) |
END; |
ASSERT(xmm = -1); |
IF param1 > 0 THEN |
mov(rsp, rbp) |
END; |
pop(rbp); |
IF param2 > 0 THEN |
OutByte3(0C2H, (param2 * 8) MOD 256, (param2 * 8) DIV 256) (* ret param2*8 *) |
ELSE |
X86.ret |
END |
|IL.opSAVES: |
UnOp(reg1); |
REG.PushAll_1(R); |
pushDA(stroffs + param2); |
push(reg1); |
drop; |
pushc(param1); |
CallRTL(IL._move) |
|IL.opSADR: |
lea(GetAnyReg(), stroffs + param2, sDATA) |
|IL.opLOAD8: |
UnOp(reg1); |
movzx(reg1, reg1, 0, FALSE) |
|IL.opLOAD16: |
UnOp(reg1); |
movzx(reg1, reg1, 0, TRUE) |
|IL.opLOAD32: |
UnOp(reg1); |
movrm32(reg1, reg1, 0); |
shiftrc(shl, reg1, 32); |
shiftrc(shr, reg1, 32) |
|IL.opLOAD64: |
UnOp(reg1); |
movrm(reg1, reg1, 0) |
|IL.opLLOAD64: |
reg1 := GetAnyReg(); |
movrm(reg1, rbp, param2 * 8) |
|IL.opLLOAD8, |
IL.opLLOAD16: |
reg1 := GetAnyReg(); |
movzx(reg1, rbp, param2 * 8, opcode = IL.opLLOAD16) |
|IL.opLLOAD32: |
reg1 := GetAnyReg(); |
movrm32(reg1, rbp, param2 * 8); |
shiftrc(shl, reg1, 32); |
shiftrc(shr, reg1, 32) |
|IL.opGLOAD64: |
reg1 := GetAnyReg(); |
Rex(0, reg1); (* mov reg1, qword[rip + param2 + BSS] *) |
OutByte2(8BH, 05H + 8 * (reg1 MOD 8)); |
X86.Reloc(sBSS, param2) |
|IL.opGLOAD8, IL.opGLOAD16: |
reg1 := GetAnyReg(); |
Rex(0, reg1); (* movzx reg1, byte/word[rip + param2 + BSS] *) |
OutByte3(0FH, 0B6H + ORD(opcode = IL.opGLOAD16), 05H + 8 * (reg1 MOD 8)); |
X86.Reloc(sBSS, param2) |
|IL.opGLOAD32: |
reg1 := GetAnyReg(); |
lea(reg1, param2, sBSS); |
movrm32(reg1, reg1, 0); |
shiftrc(shl, reg1, 32); |
shiftrc(shr, reg1, 32) |
|IL.opVLOAD64: |
reg1 := GetAnyReg(); |
movrm(reg1, rbp, param2 * 8); |
movrm(reg1, reg1, 0) |
|IL.opVLOAD8, |
IL.opVLOAD16: |
reg1 := GetAnyReg(); |
movrm(reg1, rbp, param2 * 8); |
movzx(reg1, reg1, 0, opcode = IL.opVLOAD16) |
|IL.opVLOAD32: |
reg1 := GetAnyReg(); |
reg2 := GetAnyReg(); |
movrm(reg2, rbp, param2 * 8); |
movrm32(reg1, reg2, 0); |
shiftrc(shl, reg1, 32); |
shiftrc(shr, reg1, 32); |
drop |
|IL.opLADR: |
n := param2 * 8; |
next := cmd.next(COMMAND); |
IF (next.opcode = IL.opSAVEF) OR (next.opcode = IL.opSAVEFI) THEN |
ASSERT(xmm >= 0); |
movsdmr(rbp, n, xmm); |
DEC(xmm); |
cmd := next |
ELSIF next.opcode = IL.opLOADF THEN |
INC(xmm); |
IF xmm > MAX_XMM THEN |
ERRORS.ErrorMsg(fname, next.param1, next.param2, FPR_ERR) |
END; |
movsdrm(xmm, rbp, n); |
cmd := next |
ELSE |
IF (next.opcode = IL.opADDC) & ~isLong(n + next.param2) THEN |
INC(n, next.param2); |
cmd := next |
END; |
reg1 := GetAnyReg(); |
Rex(0, reg1); |
OutByte2(8DH, 45H + long(n) + (reg1 MOD 8) * 8); (* lea reg1, qword[rbp+n] *) |
OutIntByte(n) |
END |
|IL.opGADR: |
next := cmd.next(COMMAND); |
IF (next.opcode = IL.opADDC) & ~isLong(param2 + next.param2) THEN |
INC(param2, next.param2); |
cmd := next |
END; |
lea(GetAnyReg(), param2, sBSS) |
|IL.opVADR: |
movrm(GetAnyReg(), rbp, param2 * 8) |
|IL.opSAVE8C: |
UnOp(reg1); |
IF reg1 >= 8 THEN |
OutByte(41H) |
END; |
OutByte3(0C6H, reg1 MOD 8, param2); (* mov byte[reg1], param2 *) |
drop |
|IL.opSAVE16C: |
UnOp(reg1); |
OutByte(66H); |
IF reg1 >= 8 THEN |
OutByte(41H) |
END; |
OutByte2(0C7H, reg1 MOD 8); |
OutByte2(param2 MOD 256, param2 DIV 256); (* mov word[reg1], param2 *) |
drop |
|IL.opSAVEC: |
UnOp(reg1); |
IF isLong(param2) THEN |
reg2 := GetAnyReg(); |
movrc(reg2, param2); |
movmr(reg1, 0, reg2); |
drop |
ELSE |
Rex(reg1, 0); |
OutByte2(0C7H, reg1 MOD 8); (* mov qword[reg1], param2 *) |
OutInt(param2) |
END; |
drop |
|IL.opRSET: |
PushAll(2); |
CallRTL(IL._set); |
GetRegA |
|IL.opRSETR: |
PushAll(1); |
pushc(param2); |
CallRTL(IL._set); |
GetRegA |
|IL.opRSETL: |
UnOp(reg1); |
REG.PushAll_1(R); |
pushc(param2); |
push(reg1); |
drop; |
CallRTL(IL._set); |
GetRegA |
|IL.opRSET1: |
PushAll(1); |
CallRTL(IL._set1); |
GetRegA |
|IL.opINCL, IL.opEXCL: |
BinOp(reg1, reg2); |
cmprc(reg1, 64); |
OutByte2(73H, 04H); (* jnb L *) |
Rex(reg2, reg1); |
OutByte3(0FH, 0ABH + 8 * ORD(opcode = IL.opEXCL), 8 * (reg1 MOD 8) + reg2 MOD 8); (* bts/btr qword[reg2], reg1 *) |
(* L: *) |
drop; |
drop |
|IL.opINCLC, IL.opEXCLC: |
UnOp(reg1); |
Rex(reg1, 0); |
OutByte2(0FH, 0BAH); (* bts/btr qword[reg1], param2 *) |
OutByte2(28H + 8 * ORD(opcode = IL.opEXCLC) + reg1 MOD 8, param2); |
drop |
|IL.opEQS .. IL.opGES: |
PushAll(4); |
pushc(opcode - IL.opEQS); |
CallRTL(IL._strcmp); |
GetRegA |
|IL.opEQSW .. IL.opGESW: |
PushAll(4); |
pushc(opcode - IL.opEQSW); |
CallRTL(IL._strcmpw); |
GetRegA |
|IL.opCONST: |
movrc(GetAnyReg(), param2) |
|IL.opEQ..IL.opGE, |
IL.opEQC..IL.opGEC: |
IF (IL.opEQ <= opcode) & (opcode <= IL.opGE) THEN |
BinOp(reg1, reg2); |
cmprr(reg1, reg2); |
drop |
ELSE |
UnOp(reg1); |
cmprc(reg1, param2) |
END; |
drop; |
cc := X86.cond(opcode); |
next := cmd.next(COMMAND); |
IF next.opcode = IL.opJNZ THEN |
jcc(cc, next.param1); |
cmd := next |
ELSIF next.opcode = IL.opJZ THEN |
jcc(X86.inv0(cc), next.param1); |
cmd := next |
ELSE |
reg1 := GetAnyReg(); |
X86.setcc(cc + 16, reg1); |
andrc(reg1, 1) |
END |
|IL.opCODE: |
OutByte(param2) |
|IL.opPUSHIP: |
reg1 := GetAnyReg(); |
lea(reg1, param2, sIMP); |
movrm(reg1, reg1, 0) |
|IL.opPARAM: |
n := param2; |
IF n = 1 THEN |
UnOp(reg1); |
push(reg1); |
drop |
ELSE |
ASSERT(R.top + 1 <= n); |
PushAll(n) |
END |
|IL.opJNZ1: |
UnOp(reg1); |
test(reg1); |
jcc(jne, param1) |
|IL.opJG: |
UnOp(reg1); |
test(reg1); |
jcc(jg, param1) |
|IL.opJNZ: |
UnOp(reg1); |
test(reg1); |
jcc(jne, param1); |
drop |
|IL.opJZ: |
UnOp(reg1); |
test(reg1); |
jcc(je, param1); |
drop |
|IL.opIN, IL.opINR: |
IF opcode = IL.opINR THEN |
reg2 := GetAnyReg(); |
movrc(reg2, param2) |
END; |
label := NewLabel(); |
L := NewLabel(); |
BinOp(reg1, reg2); |
cmprc(reg1, 64); |
jcc(jb, L); |
xor(reg1, reg1); |
X86.jmp(label); |
X86.SetLabel(L); |
Rex(reg2, reg1); |
OutByte3(0FH, 0A3H, 0C0H + 8 * (reg1 MOD 8) + reg2 MOD 8); (* bt reg2, reg1 *) |
X86.setcc(setc, reg1); |
andrc(reg1, 1); |
X86.SetLabel(label); |
drop |
|IL.opINL: |
UnOp(reg1); |
Rex(reg1, 0); |
OutByte2(0FH, 0BAH); (* bt reg1, param2 *) |
OutByte2(0E0H + reg1 MOD 8, param2); |
X86.setcc(setc, reg1); |
andrc(reg1, 1) |
|IL.opNOT: |
UnOp(reg1); |
test(reg1); |
X86.setcc(sete, reg1); |
andrc(reg1, 1) |
|IL.opORD: |
UnOp(reg1); |
test(reg1); |
X86.setcc(setne, reg1); |
andrc(reg1, 1) |
|IL.opABS: |
UnOp(reg1); |
test(reg1); |
OutByte2(7DH, 03H); (* jge L *) |
neg(reg1) |
(* L: *) |
|IL.opEQB, IL.opNEB: |
BinOp(reg1, reg2); |
drop; |
test(reg1); |
label := NewLabel(); |
jcc(je, label); |
movrc(reg1, 1); |
X86.SetLabel(label); |
test(reg2); |
label := NewLabel(); |
jcc(je, label); |
movrc(reg2, 1); |
X86.SetLabel(label); |
cmprr(reg1, reg2); |
IF opcode = IL.opEQB THEN |
X86.setcc(sete, reg1) |
ELSE |
X86.setcc(setne, reg1) |
END; |
andrc(reg1, 1) |
|IL.opMULSC: |
UnOp(reg1); |
andrc(reg1, param2) |
|IL.opDIVSC: |
UnOp(reg1); |
xorrc(reg1, param2) |
|IL.opADDSC: |
UnOp(reg1); |
orrc(reg1, param2) |
|IL.opSUBSL: |
UnOp(reg1); |
not(reg1); |
andrc(reg1, param2) |
|IL.opSUBSR: |
UnOp(reg1); |
andrc(reg1, ORD(-BITS(param2))) |
|IL.opMULS: |
BinOp(reg1, reg2); |
and(reg1, reg2); |
drop |
|IL.opDIVS: |
BinOp(reg1, reg2); |
xor(reg1, reg2); |
drop |
|IL.opUMINS: |
UnOp(reg1); |
not(reg1) |
|IL.opCOPY: |
PushAll(2); |
pushc(param2); |
CallRTL(IL._move) |
|IL.opMOVE: |
PushAll(3); |
CallRTL(IL._move) |
|IL.opCOPYA: |
PushAll(4); |
pushc(param2); |
CallRTL(IL._arrcpy); |
GetRegA |
|IL.opCOPYS: |
PushAll(4); |
pushc(param2); |
CallRTL(IL._strcpy) |
|IL.opROT: |
PushAll(0); |
push(rsp); |
pushc(param2); |
CallRTL(IL._rot) |
|IL.opNEW: |
PushAll(1); |
n := param2 + 8; |
ASSERT(UTILS.Align(n, 8)); |
pushc(n); |
pushc(param1); |
CallRTL(IL._new) |
|IL.opDISP: |
PushAll(1); |
CallRTL(IL._dispose) |
|IL.opPUSHT: |
UnOp(reg1); |
movrm(GetAnyReg(), reg1, -8) |
|IL.opISREC: |
PushAll(2); |
pushc(param2 * tcount); |
CallRTL(IL._isrec); |
GetRegA |
|IL.opIS: |
PushAll(1); |
pushc(param2 * tcount); |
CallRTL(IL._is); |
GetRegA |
|IL.opTYPEGR: |
PushAll(1); |
pushc(param2 * tcount); |
CallRTL(IL._guardrec); |
GetRegA |
|IL.opTYPEGP: |
UnOp(reg1); |
PushAll(0); |
push(reg1); |
pushc(param2 * tcount); |
CallRTL(IL._guard); |
GetRegA |
|IL.opTYPEGD: |
UnOp(reg1); |
PushAll(0); |
X86.pushm(reg1, -8); |
pushc(param2 * tcount); |
CallRTL(IL._guardrec); |
GetRegA |
|IL.opCASET: |
push(rcx); |
push(rcx); |
pushc(param2 * tcount); |
CallRTL(IL._guardrec); |
pop(rcx); |
test(rax); |
jcc(jne, param1) |
|IL.opSAVEP: |
UnOp(reg1); |
reg2 := GetAnyReg(); |
lea(reg2, param2, sCODE); |
movmr(reg1, 0, reg2); |
drop; |
drop |
|IL.opPUSHP: |
lea(GetAnyReg(), param2, sCODE) |
|IL.opINC, IL.opDEC: |
BinOp(reg1, reg2); |
(* add/sub qword[reg2], reg1 *) |
Rex(reg2, reg1); |
OutByte2(01H + 28H * ORD(opcode = IL.opDEC), reg2 MOD 8 + (reg1 MOD 8) * 8); |
drop; |
drop |
|IL.opINCC: |
UnOp(reg1); |
IF isLong(param2) THEN |
reg2 := GetAnyReg(); |
movrc(reg2, param2); |
(* add qword[reg1], reg2 *) |
Rex(reg1, reg2); |
OutByte2(01H, reg1 MOD 8 + (reg2 MOD 8) * 8); |
drop |
ELSIF ABS(param2) = 1 THEN |
Rex(reg1, 0); |
OutByte2(0FFH, reg1 MOD 8 + 8 * ORD(param2 = -1)) (* inc/dec qword[reg1] *) |
ELSE |
(* add qword[reg1], param2 *) |
Rex(reg1, 0); |
OutByte2(81H + short(param2), reg1 MOD 8); |
OutIntByte(param2) |
END; |
drop |
|IL.opDROP: |
UnOp(reg1); |
drop |
|IL.opSAVE, IL.opSAVE64: |
BinOp(reg2, reg1); |
movmr(reg1, 0, reg2); |
drop; |
drop |
|IL.opSAVE8: |
BinOp(reg2, reg1); |
X86.movmr8(reg1, 0, reg2); |
drop; |
drop |
|IL.opSAVE16: |
BinOp(reg2, reg1); |
X86.movmr16(reg1, 0, reg2); |
drop; |
drop |
|IL.opSAVE32: |
BinOp(reg2, reg1); |
movmr32(reg1, 0, reg2); |
drop; |
drop |
|IL.opMAX, IL.opMIN: |
BinOp(reg1, reg2); |
cmprr(reg1, reg2); |
OutByte2(7DH + ORD(opcode = IL.opMIN), 3); (* jge/jle L *) |
mov(reg1, reg2); |
(* L: *) |
drop |
|IL.opMAXC, IL.opMINC: |
UnOp(reg1); |
cmprc(reg1, param2); |
label := NewLabel(); |
IF opcode = IL.opMINC THEN |
cc := jle |
ELSE |
cc := jge |
END; |
jcc(cc, label); |
movrc(reg1, param2); |
X86.SetLabel(label) |
|IL.opSBOOL: |
BinOp(reg2, reg1); |
test(reg2); |
IF reg1 >= 8 THEN |
OutByte(41H) |
END; |
OutByte3(0FH, 95H, reg1 MOD 8); (* setne byte[reg1] *) |
drop; |
drop |
|IL.opSBOOLC: |
UnOp(reg1); |
IF reg1 >= 8 THEN |
OutByte(41H) |
END; |
OutByte3(0C6H, reg1 MOD 8, ORD(param2 # 0)); (* mov byte[reg1], 0/1 *) |
drop |
|IL.opUMINUS: |
UnOp(reg1); |
neg(reg1) |
|IL.opADD: |
BinOp(reg1, reg2); |
add(reg1, reg2); |
drop |
|IL.opSUB: |
BinOp(reg1, reg2); |
sub(reg1, reg2); |
drop |
|IL.opSUBR, IL.opSUBL: |
UnOp(reg1); |
IF param2 = 1 THEN |
decr(reg1) |
ELSIF param2 = -1 THEN |
incr(reg1) |
ELSIF param2 # 0 THEN |
subrc(reg1, param2) |
END; |
IF opcode = IL.opSUBL THEN |
neg(reg1) |
END |
|IL.opADDC: |
IF (param2 # 0) & ~isLong(param2) THEN |
UnOp(reg1); |
next := cmd.next(COMMAND); |
CASE next.opcode OF |
|IL.opLOAD64: |
movrm(reg1, reg1, param2); |
cmd := next |
|IL.opLOAD32: |
movrm32(reg1, reg1, param2); |
shiftrc(shl, reg1, 32); |
shiftrc(shr, reg1, 32); |
cmd := next |
|IL.opLOAD16: |
movzx(reg1, reg1, param2, TRUE); |
cmd := next |
|IL.opLOAD8: |
movzx(reg1, reg1, param2, FALSE); |
cmd := next |
|IL.opLOAD64_PARAM: |
X86.pushm(reg1, param2); |
drop; |
cmd := next |
ELSE |
IF param2 = 1 THEN |
incr(reg1) |
ELSIF param2 = -1 THEN |
decr(reg1) |
ELSE |
addrc(reg1, param2) |
END |
END |
ELSIF isLong(param2) THEN |
UnOp(reg1); |
addrc(reg1, param2) |
END |
|IL.opDIV: |
PushAll(2); |
CallRTL(IL._divmod); |
GetRegA |
|IL.opDIVR: |
n := UTILS.Log2(param2); |
IF n > 0 THEN |
UnOp(reg1); |
shiftrc(sar, reg1, n) |
ELSIF n < 0 THEN |
PushAll(1); |
pushc(param2); |
CallRTL(IL._divmod); |
GetRegA |
END |
|IL.opDIVL: |
UnOp(reg1); |
REG.PushAll_1(R); |
pushc(param2); |
push(reg1); |
drop; |
CallRTL(IL._divmod); |
GetRegA |
|IL.opMOD: |
PushAll(2); |
CallRTL(IL._divmod); |
mov(rax, rdx); |
GetRegA |
|IL.opMODR: |
n := UTILS.Log2(param2); |
IF n > 0 THEN |
UnOp(reg1); |
andrc(reg1, param2 - 1); |
ELSIF n < 0 THEN |
PushAll(1); |
pushc(param2); |
CallRTL(IL._divmod); |
mov(rax, rdx); |
GetRegA |
ELSE |
UnOp(reg1); |
xor(reg1, reg1) |
END |
|IL.opMODL: |
UnOp(reg1); |
REG.PushAll_1(R); |
pushc(param2); |
push(reg1); |
drop; |
CallRTL(IL._divmod); |
mov(rax, rdx); |
GetRegA |
|IL.opMUL: |
BinOp(reg1, reg2); |
oprr2(0FH, 0AFH, reg2, reg1); (* imul reg1, reg2 *) |
drop |
|IL.opMULC: |
IF (cmd.next(COMMAND).opcode = IL.opADD) & ((param2 = 2) OR (param2 = 4) OR (param2 = 8)) THEN |
BinOp(reg1, reg2); |
OutByte2(48H + 5 * (reg1 DIV 8) + 2 * (reg2 DIV 8), 8DH); (* lea reg1, [reg1 + reg2 * param2] *) |
reg1 := reg1 MOD 8; |
reg2 := reg2 MOD 8; |
OutByte2(04H + reg1 * 8, reg1 + reg2 * 8 + 40H * UTILS.Log2(param2)); |
drop; |
cmd := cmd.next(COMMAND) |
ELSE |
UnOp(reg1); |
a := param2; |
IF a > 1 THEN |
n := UTILS.Log2(a) |
ELSIF a < -1 THEN |
n := UTILS.Log2(-a) |
ELSE |
n := -1 |
END; |
IF a = 1 THEN |
ELSIF a = -1 THEN |
neg(reg1) |
ELSIF a = 0 THEN |
xor(reg1, reg1) |
ELSE |
IF n > 0 THEN |
IF a < 0 THEN |
neg(reg1) |
END; |
shiftrc(shl, reg1, n) |
ELSE |
IF isLong(a) THEN |
reg2 := GetAnyReg(); |
movabs(reg2, a); |
ASSERT(reg1 # reg2); |
oprr2(0FH, 0AFH, reg2, reg1); (* imul reg1, reg2 *) |
drop |
ELSE |
(* imul reg1, a *) |
Rex(reg1, reg1); |
OutByte2(69H + short(a), 0C0H + (reg1 MOD 8) * 9); |
OutIntByte(a) |
END |
END |
END |
END |
|IL.opADDS: |
BinOp(reg1, reg2); |
_or(reg1, reg2); |
drop |
|IL.opSUBS: |
BinOp(reg1, reg2); |
not(reg2); |
and(reg1, reg2); |
drop |
|IL.opNOP, IL.opAND, IL.opOR: |
|IL.opSWITCH: |
UnOp(reg1); |
IF param2 = 0 THEN |
reg2 := rax |
ELSE |
reg2 := rcx |
END; |
IF reg1 # reg2 THEN |
ASSERT(REG.GetReg(R, reg2)); |
ASSERT(REG.Exchange(R, reg1, reg2)); |
drop |
END; |
drop |
|IL.opENDSW: |
|IL.opCASEL: |
GetRegA; |
cmprc(rax, param1); |
jcc(jl, param2); |
drop |
|IL.opCASER: |
GetRegA; |
cmprc(rax, param1); |
jcc(jg, param2); |
drop |
|IL.opCASELR: |
GetRegA; |
cmprc(rax, param1); |
IF param2 = cmd.param3 THEN |
jcc(jne, param2) |
ELSE |
jcc(jl, param2); |
jcc(jg, cmd.param3) |
END; |
drop |
|IL.opASR, IL.opROR, IL.opLSL, IL.opLSR: |
UnOp(reg1); |
IF reg1 # rcx THEN |
ASSERT(REG.GetReg(R, rcx)); |
ASSERT(REG.Exchange(R, reg1, rcx)); |
drop |
END; |
BinOp(reg1, reg2); |
ASSERT(reg2 = rcx); |
Rex(reg1, 0); |
OutByte(0D3H); |
X86.shift(opcode, reg1 MOD 8); (* shift reg1, cl *) |
drop |
|IL.opASR1, IL.opROR1, IL.opLSL1, IL.opLSR1: |
UnOp(reg1); |
IF reg1 # rcx THEN |
ASSERT(REG.GetReg(R, rcx)); |
ASSERT(REG.Exchange(R, reg1, rcx)); |
drop |
END; |
reg1 := GetAnyReg(); |
movrc(reg1, param2); |
BinOp(reg1, reg2); |
ASSERT(reg1 = rcx); |
Rex(reg2, 0); |
OutByte(0D3H); |
X86.shift(opcode, reg2 MOD 8); (* shift reg2, cl *) |
drop; |
drop; |
ASSERT(REG.GetReg(R, reg2)) |
|IL.opASR2, IL.opROR2, IL.opLSL2, IL.opLSR2: |
UnOp(reg1); |
shiftrc(opcode, reg1, param2 MOD 64) |
|IL.opGET, IL.opGETC: |
IF opcode = IL.opGET THEN |
BinOp(reg1, reg2) |
ELSIF opcode = IL.opGETC THEN |
UnOp(reg2); |
reg1 := GetAnyReg(); |
movrc(reg1, param1) |
END; |
drop; |
drop; |
X86._movrm(reg1, reg1, 0, param2 * 8, FALSE); |
X86._movrm(reg1, reg2, 0, param2 * 8, TRUE) |
|IL.opCHKBYTE: |
BinOp(reg1, reg2); |
cmprc(reg1, 256); |
jcc(jb, param1) |
|IL.opCHKIDX: |
UnOp(reg1); |
cmprc(reg1, param2); |
jcc(jb, param1) |
|IL.opCHKIDX2: |
BinOp(reg1, reg2); |
IF param2 # -1 THEN |
cmprr(reg2, reg1); |
jcc(jb, param1); |
END; |
INCL(R.regs, reg1); |
DEC(R.top); |
R.stk[R.top] := reg2 |
|IL.opLENGTH: |
PushAll(2); |
CallRTL(IL._length); |
GetRegA |
|IL.opLENGTHW: |
PushAll(2); |
CallRTL(IL._lengthw); |
GetRegA |
|IL.opLEN: |
n := param2; |
UnOp(reg1); |
drop; |
EXCL(R.regs, reg1); |
WHILE n > 0 DO |
UnOp(reg2); |
drop; |
DEC(n) |
END; |
INCL(R.regs, reg1); |
ASSERT(REG.GetReg(R, reg1)) |
|IL.opCHR: |
UnOp(reg1); |
andrc(reg1, 255) |
|IL.opWCHR: |
UnOp(reg1); |
andrc(reg1, 65535) |
|IL.opEQP, IL.opNEP, IL.opEQIP, IL.opNEIP: |
UnOp(reg1); |
reg2 := GetAnyReg(); |
CASE opcode OF |
|IL.opEQP, IL.opNEP: |
lea(reg2, param1, sCODE) |
|IL.opEQIP, IL.opNEIP: |
lea(reg2, param1, sIMP); |
movrm(reg2, reg2, 0) |
END; |
cmprr(reg1, reg2); |
drop; |
drop; |
reg1 := GetAnyReg(); |
CASE opcode OF |
|IL.opEQP, IL.opEQIP: X86.setcc(sete, reg1) |
|IL.opNEP, IL.opNEIP: X86.setcc(setne, reg1) |
END; |
andrc(reg1, 1) |
|IL.opINCCB, IL.opDECCB: |
UnOp(reg1); |
IF reg1 >= 8 THEN |
OutByte(41H) |
END; |
OutByte3(80H, 28H * ORD(opcode = IL.opDECCB) + reg1 MOD 8, param2 MOD 256); (* add/sub byte[reg1], param2 MOD 256 *) |
drop |
|IL.opINCB, IL.opDECB: |
BinOp(reg1, reg2); |
IF (reg1 >= 8) OR (reg2 >= 8) THEN |
OutByte(40H + reg2 DIV 8 + 4 * (reg1 DIV 8)) |
END; |
OutByte2(28H * ORD(opcode = IL.opDECB), reg2 MOD 8 + 8 * (reg1 MOD 8)); (* add/sub byte[reg2], reg1_8 *) |
drop; |
drop |
|IL.opSAVEIP: |
UnOp(reg1); |
reg2 := GetAnyReg(); |
lea(reg2, param2, sIMP); |
movrm(reg2, reg2, 0); |
push(reg2); |
drop; |
IF reg1 >= 8 THEN |
OutByte(41H) |
END; |
OutByte2(8FH, reg1 MOD 8); (* pop qword[reg1] *) |
drop |
|IL.opCLEANUP: |
IF param2 # 0 THEN |
addrc(rsp, param2 * 8) |
END |
|IL.opPOPSP: |
pop(rsp) |
|IL.opLOADF: |
UnOp(reg1); |
INC(xmm); |
IF xmm > MAX_XMM THEN |
ERRORS.ErrorMsg(fname, param1, param2, FPR_ERR) |
END; |
movsdrm(xmm, reg1, 0); |
drop |
|IL.opPUSHF: |
ASSERT(xmm >= 0); |
subrc(rsp, 8); |
movsdmr(rsp, 0, xmm); |
DEC(xmm) |
|IL.opCONSTF: |
float := cmd.float; |
INC(xmm); |
IF xmm > MAX_XMM THEN |
ERRORS.ErrorMsg(fname, param1, param2, FPR_ERR) |
END; |
(* movsd xmm, qword ptr [rip + Numbers_Offs + Numbers_Count * 8 + DATA] *) |
OutByte(0F2H); |
IF xmm >= 8 THEN |
OutByte(44H) |
END; |
OutByte3(0FH, 10H, 05H + 8 * (xmm MOD 8)); |
X86.Reloc(sDATA, Numbers_Offs + Numbers_Count * 8); |
NewNumber(UTILS.splitf(float, a, b)) |
|IL.opSAVEF, IL.opSAVEFI: |
ASSERT(xmm >= 0); |
UnOp(reg1); |
movsdmr(reg1, 0, xmm); |
DEC(xmm); |
drop |
|IL.opADDF: |
ASSERT(xmm >= 1); |
opxx(58H, xmm - 1, xmm); |
DEC(xmm) |
|IL.opSUBF: |
ASSERT(xmm >= 1); |
opxx(5CH, xmm - 1, xmm); |
DEC(xmm) |
|IL.opSUBFI: |
ASSERT(xmm >= 1); |
opxx(5CH, xmm, xmm - 1); |
opxx(10H, xmm - 1, xmm); |
DEC(xmm) |
|IL.opMULF: |
ASSERT(xmm >= 1); |
opxx(59H, xmm - 1, xmm); |
DEC(xmm) |
|IL.opDIVF: |
ASSERT(xmm >= 1); |
opxx(5EH, xmm - 1, xmm); |
DEC(xmm) |
|IL.opDIVFI: |
ASSERT(xmm >= 1); |
opxx(5EH, xmm, xmm - 1); |
opxx(10H, xmm - 1, xmm); |
DEC(xmm) |
|IL.opFABS, IL.opUMINF: (* andpd/xorpd xmm, xmmword[rip + Numbers_Offs + (16) + DATA] *) |
ASSERT(xmm >= 0); |
OutByte(66H); |
IF xmm >= 8 THEN |
OutByte(44H) |
END; |
OutByte3(0FH, 54H + 3 * ORD(opcode = IL.opUMINF), 05H + (xmm MOD 8) * 8); |
X86.Reloc(sDATA, Numbers_Offs + 16 * ORD(opcode = IL.opFABS)) |
|IL.opFLT: |
UnOp(reg1); |
INC(xmm); |
IF xmm > MAX_XMM THEN |
ERRORS.ErrorMsg(fname, param1, param2, FPR_ERR) |
END; |
OutByte(0F2H); Rex(reg1, xmm); OutByte(0FH); (* cvtsi2sd xmm, reg1 *) |
OutByte2(2AH, 0C0H + (xmm MOD 8) * 8 + reg1 MOD 8); |
drop |
|IL.opFLOOR: |
ASSERT(xmm >= 0); |
reg1 := GetAnyReg(); |
subrc(rsp, 8); |
OutByte3(00FH, 0AEH, 05CH); OutByte2(024H, 004H); (* stmxcsr dword[rsp+4]; *) |
OutByte2(00FH, 0AEH); OutByte2(01CH, 024H); (* stmxcsr dword[rsp]; *) |
OutByte3(081H, 024H, 024H); OutByte2(0FFH, 09FH); OutByte2(0FFH, 0FFH); (* and dword[rsp],11111111111111111001111111111111b; *) |
OutByte3(081H, 00CH, 024H); OutByte2(000H, 020H); OutByte2(000H, 000H); (* or dword[rsp],00000000000000000010000000000000b; *) |
OutByte2(00FH, 0AEH); OutByte2(014H, 024H); (* ldmxcsr dword[rsp]; *) |
OutByte(0F2H); Rex(xmm, reg1); OutByte(0FH); (* cvtsd2si reg1, xmm *) |
OutByte2(2DH, 0C0H + xmm MOD 8 + (reg1 MOD 8) * 8); |
OutByte3(00FH, 0AEH, 054H); OutByte2(024H, 004H); (* ldmxcsr dword[rsp+4]; *) |
addrc(rsp, 8); |
DEC(xmm) |
|IL.opEQF .. IL.opGEF: |
ASSERT(xmm >= 1); |
fcmp(opcode, xmm); |
DEC(xmm, 2) |
|IL.opINF: |
INC(xmm); |
IF xmm > MAX_XMM THEN |
ERRORS.ErrorMsg(fname, param1, param2, FPR_ERR) |
END; |
(* movsd xmm, qword ptr [rip + Numbers_Offs + 32 + DATA] *) |
OutByte(0F2H); |
IF xmm >= 8 THEN |
OutByte(44H) |
END; |
OutByte3(0FH, 10H, 05H + 8 * (xmm MOD 8)); |
X86.Reloc(sDATA, Numbers_Offs + 32) |
|IL.opPACK, IL.opPACKC: |
IF opcode = IL.opPACK THEN |
BinOp(reg1, reg2) |
ELSE |
UnOp(reg1); |
reg2 := GetAnyReg(); |
movrc(reg2, param2) |
END; |
push(reg1); |
movrm(reg1, reg1, 0); |
shiftrc(shl, reg1, 1); |
shiftrc(shr, reg1, 53); |
add(reg1, reg2); |
andrc(reg1, ORD({0..10})); |
shiftrc(shl, reg1, 52); |
movrm(reg2, rsp, 0); |
movrm(reg2, reg2, 0); |
push(reg1); |
lea(reg1, Numbers_Offs + 40, sDATA); (* {0..51, 63} *) |
movrm(reg1, reg1, 0); |
and(reg2, reg1); |
pop(reg1); |
_or(reg2, reg1); |
pop(reg1); |
movmr(reg1, 0, reg2); |
drop; |
drop |
|IL.opUNPK, IL.opLADR_UNPK: |
IF opcode = IL.opLADR_UNPK THEN |
n := param2 * 8; |
UnOp(reg1); |
reg2 := GetAnyReg(); |
Rex(0, reg2); |
OutByte2(8DH, 45H + long(n) + (reg2 MOD 8) * 8); (* lea reg2, qword[rbp+n] *) |
OutIntByte(n) |
ELSE |
BinOp(reg1, reg2) |
END; |
push(reg1); |
movrm(reg1, reg1, 0); |
shiftrc(shl, reg1, 1); |
shiftrc(shr, reg1, 53); |
subrc(reg1, 1023); |
movmr(reg2, 0, reg1); |
pop(reg2); |
movrm(reg1, reg2, 0); |
push(reg2); |
lea(reg2, Numbers_Offs + 48, sDATA); (* {52..61} *) |
movrm(reg2, reg2, 0); |
_or(reg1, reg2); |
pop(reg2); |
Rex(reg1, 0); |
OutByte2(0FH, 0BAH); |
OutByte2(0F0H + reg1 MOD 8, 3EH); (* btr reg1, 62 *) |
movmr(reg2, 0, reg1); |
drop; |
drop |
|IL.opSADR_PARAM: |
pushDA(stroffs + param2) |
|IL.opVADR_PARAM: |
X86.pushm(rbp, param2 * 8) |
|IL.opLOAD64_PARAM: |
UnOp(reg1); |
X86.pushm(reg1, 0); |
drop |
|IL.opLLOAD64_PARAM: |
X86.pushm(rbp, param2 * 8) |
|IL.opGLOAD64_PARAM: |
OutByte2(0FFH, 35H); (* push qword[rip + param2 + BSS] *) |
X86.Reloc(sBSS, param2) |
|IL.opCONST_PARAM: |
pushc(param2) |
|IL.opGLOAD32_PARAM, IL.opLOAD32_PARAM: |
IF opcode = IL.opGLOAD32_PARAM THEN |
reg1 := GetAnyReg(); |
lea(reg1, param2, sBSS) |
ELSE |
UnOp(reg1) |
END; |
movrm32(reg1, reg1, 0); |
shiftrc(shl, reg1, 32); |
shiftrc(shr, reg1, 32); |
push(reg1); |
drop |
|IL.opLLOAD32_PARAM: |
reg1 := GetAnyReg(); |
movrm32(reg1, rbp, param2 * 8); |
shiftrc(shl, reg1, 32); |
shiftrc(shr, reg1, 32); |
push(reg1); |
drop |
|IL.opLADR_SAVEC: |
n := param1 * 8; |
IF isLong(param2) THEN |
reg2 := GetAnyReg(); |
movrc(reg2, param2); |
movmr(rbp, n, reg2); |
drop |
ELSE |
OutByte3(48H, 0C7H, 45H + long(n)); (* mov qword[rbp+n], param2 *) |
OutIntByte(n); |
OutInt(param2) |
END |
|IL.opGADR_SAVEC: |
IF isLong(param2) THEN |
reg1 := GetAnyReg(); |
movrc(reg1, param2); |
reg2 := GetAnyReg(); |
lea(reg2, param1, sBSS); |
movmr(reg2, 0, reg1); |
drop; |
drop |
ELSE |
(* mov qword[rip + param1 - 4 + BSS], param2 *) |
OutByte3(48H, 0C7H, 05H); |
X86.Reloc(sBSS, param1 - 4); |
OutInt(param2) |
END |
|IL.opLADR_SAVE: |
UnOp(reg1); |
movmr(rbp, param2 * 8, reg1); |
drop |
|IL.opLADR_INCC: |
IF isLong(param2) THEN |
reg2 := GetAnyReg(); |
movrc(reg2, param2); |
n := param1 * 8; |
Rex(0, reg2); |
OutByte2(01H, 45H + long(n) + (reg2 MOD 8) * 8); |
OutIntByte(n); (* add qword[rbp+n], reg2 *) |
drop |
ELSIF ABS(param2) = 1 THEN |
n := param1 * 8; |
OutByte3(48H, 0FFH, 45H + 8 * ORD(param2 = -1) + long(n)); (* inc/dec qword[rbp+n] *) |
OutIntByte(n) |
ELSE |
n := param1 * 8; |
OutByte3(48H, 81H + short(param2), 45H + long(n)); |
OutIntByte(n); |
OutIntByte(param2) (* add qword[rbp+n], param2 *) |
END |
|IL.opLADR_INCCB, IL.opLADR_DECCB: |
param2 := param2 MOD 256; |
n := param1 * 8; |
OutByte2(80H, 45H + long(n) + 28H * ORD(opcode = IL.opLADR_DECCB)); |
OutIntByte(n); |
OutByte(param2) (* add/sub byte[rbp+n], param2 *) |
|IL.opLADR_INC, IL.opLADR_DEC: |
UnOp(reg1); |
n := param2 * 8; |
Rex(0, reg1); |
OutByte2(01H + 28H * ORD(opcode = IL.opLADR_DEC), 45H + long(n) + (reg1 MOD 8) * 8); |
OutIntByte(n); (* add/sub qword[rbp+n], reg1 *) |
drop |
|IL.opLADR_INCB, IL.opLADR_DECB: |
UnOp(reg1); |
n := param2 * 8; |
IF reg1 >= 8 THEN |
OutByte(44H) |
END; |
OutByte2(28H * ORD(opcode = IL.opLADR_DECB), 45H + long(n) + 8 * (reg1 MOD 8)); |
OutIntByte(n); (* add/sub byte[rbp+n], reg1_8 *) |
drop |
|IL.opLADR_INCL, IL.opLADR_EXCL: |
UnOp(reg1); |
cmprc(reg1, 64); |
n := param2 * 8; |
OutByte2(73H, 5 + 3 * ORD(~X86.isByte(n))); (* jnb L *) |
Rex(0, reg1); |
OutByte3(0FH, 0ABH + 8 * ORD(opcode = IL.opLADR_EXCL), 45H + long(n) + 8 * (reg1 MOD 8)); |
OutIntByte(n); (* bts/btr qword[rbp+n], reg1 *) |
(* L: *) |
drop |
|IL.opLADR_INCLC, IL.opLADR_EXCLC: |
n := param1 * 8; |
OutByte3(48H, 0FH, 0BAH); (* bts/btr qword[rbp+n], param2 *) |
OutByte(6DH + long(n) + 8 * ORD(opcode = IL.opLADR_EXCLC)); |
OutIntByte(n); |
OutByte(param2) |
|IL.opFNAME: |
fname := cmd(IL.FNAMECMD).fname |
END; |
cmd := cmd.next(COMMAND) |
END; |
ASSERT(R.pushed = 0); |
ASSERT(R.top = -1); |
ASSERT(xmm = -1) |
END translate; |
PROCEDURE prolog (modname: ARRAY OF CHAR; target, stack_size: INTEGER); |
VAR |
ModName_Offs, entry, L: INTEGER; |
BEGIN |
ModName_Offs := tcount * 8 + CHL.Length(IL.codes.data); |
Numbers_Offs := ModName_Offs + LENGTH(modname) + 1; |
ASSERT(UTILS.Align(Numbers_Offs, 16)); |
entry := NewLabel(); |
X86.SetLabel(entry); |
IF target = TARGETS.Win64DLL THEN |
dllret := NewLabel(); |
push(r8); |
push(rdx); |
push(rcx); |
CallRTL(IL._dllentry); |
test(rax); |
jcc(je, dllret); |
pushc(0) |
ELSIF target = TARGETS.Linux64 THEN |
push(rsp) |
ELSE |
pushc(0) |
END; |
lea(rax, entry, sCODE); |
push(rax); |
pushDA(0); (* TYPES *) |
pushc(tcount); |
pushDA(ModName_Offs); (* MODNAME *) |
CallRTL(IL._init); |
IF target IN {TARGETS.Win64C, TARGETS.Win64GUI, TARGETS.Linux64} THEN |
L := NewLabel(); |
pushc(0); |
push(rsp); |
pushc(1024 * 1024 * stack_size); |
pushc(0); |
CallRTL(IL._new); |
pop(rax); |
test(rax); |
jcc(je, L); |
GetRegA; |
addrc(rax, 1024 * 1024 * stack_size - 8); |
drop; |
mov(rsp, rax); |
X86.SetLabel(L) |
END |
END prolog; |
PROCEDURE epilog (modname: ARRAY OF CHAR; target: INTEGER); |
VAR |
i, n: INTEGER; |
number: Number; |
exp: IL.EXPORT_PROC; |
PROCEDURE _import (imp: LISTS.LIST); |
VAR |
lib: IL.IMPORT_LIB; |
proc: IL.IMPORT_PROC; |
BEGIN |
lib := imp.first(IL.IMPORT_LIB); |
WHILE lib # NIL DO |
BIN.Import(prog, lib.name, 0); |
proc := lib.procs.first(IL.IMPORT_PROC); |
WHILE proc # NIL DO |
BIN.Import(prog, proc.name, proc.label); |
proc := proc.next(IL.IMPORT_PROC) |
END; |
lib := lib.next(IL.IMPORT_LIB) |
END |
END _import; |
BEGIN |
IF target = TARGETS.Win64DLL THEN |
X86.SetLabel(dllret); |
X86.ret |
ELSIF target = TARGETS.Linux64SO THEN |
sofinit := NewLabel(); |
X86.ret; |
X86.SetLabel(sofinit); |
CallRTL(IL._sofinit); |
X86.ret |
ELSE |
pushc(0); |
CallRTL(IL._exit) |
END; |
X86.fixup; |
i := 0; |
WHILE i < tcount DO |
BIN.PutData64LE(prog, CHL.GetInt(IL.codes.types, i)); |
INC(i) |
END; |
i := 0; |
WHILE i < CHL.Length(IL.codes.data) DO |
BIN.PutData(prog, CHL.GetByte(IL.codes.data, i)); |
INC(i) |
END; |
BIN.PutDataStr(prog, modname); |
BIN.PutData(prog, 0); |
n := CHL.Length(prog.data); |
ASSERT(UTILS.Align(n, 16)); |
i := n - CHL.Length(prog.data); |
WHILE i > 0 DO |
BIN.PutData(prog, 0); |
DEC(i) |
END; |
number := Numbers.first(Number); |
FOR i := 0 TO Numbers_Count - 1 DO |
BIN.PutData64LE(prog, number.value); |
number := number.next(Number) |
END; |
exp := IL.codes.export.first(IL.EXPORT_PROC); |
WHILE exp # NIL DO |
BIN.Export(prog, exp.name, exp.label); |
exp := exp.next(IL.EXPORT_PROC) |
END; |
_import(IL.codes._import) |
END epilog; |
PROCEDURE CodeGen* (outname: ARRAY OF CHAR; target: INTEGER; options: PROG.OPTIONS); |
VAR |
path, modname, ext: PATHS.PATH; |
BEGIN |
Xmm[0] := 0; |
tcount := CHL.Length(IL.codes.types); |
Win64RegPar[0] := rcx; |
Win64RegPar[1] := rdx; |
Win64RegPar[2] := r8; |
Win64RegPar[3] := r9; |
SystemVRegPar[0] := rdi; |
SystemVRegPar[1] := rsi; |
SystemVRegPar[2] := rdx; |
SystemVRegPar[3] := rcx; |
SystemVRegPar[4] := r8; |
SystemVRegPar[5] := r9; |
PATHS.split(outname, path, modname, ext); |
S.append(modname, ext); |
REG.Init(R, push, pop, mov, xchg, {rax, rcx, rdx, r8, r9, r10, r11}); |
IL.set_bss(MAX(IL.codes.bss, MAX(IL.codes.dmin - CHL.Length(IL.codes.data), 8))); |
Numbers := LISTS.create(NIL); |
Numbers_Count := 0; |
NewNumber(ROR(1, 1)); (* 8000000000000000H *) |
NewNumber(0); |
NewNumber(ROR(-2, 1)); (* 7FFFFFFFFFFFFFFFH *) |
NewNumber(-1); |
NewNumber(ROR(7FFH, 12)); (* +Infinity *) |
NewNumber(ORD(-BITS(LSR(ASR(ROR(1, 1), 10), 1)))); (* {0..51, 63} *) |
NewNumber(LSR(ASR(ROR(1, 1), 9), 2)); (* {52..61} *) |
prog := BIN.create(IL.codes.lcount); |
BIN.SetParams(prog, IL.codes.bss, 1, WCHR(1), WCHR(0)); |
X86.SetProgram(prog); |
prolog(modname, target, options.stack); |
translate(IL.codes.commands, tcount * 8); |
epilog(modname, target); |
BIN.fixup(prog); |
IF TARGETS.OS = TARGETS.osWIN64 THEN |
PE32.write(prog, outname, target = TARGETS.Win64C, target = TARGETS.Win64DLL, TRUE) |
ELSIF TARGETS.OS = TARGETS.osLINUX64 THEN |
ELF.write(prog, outname, sofinit, target = TARGETS.Linux64SO, TRUE) |
END |
END CodeGen; |
END AMD64. |
/programs/develop/oberon07/source/ARITH.ob07 |
---|
0,0 → 1,806 |
(* |
BSD 2-Clause License |
Copyright (c) 2018-2021, Anton Krotov |
All rights reserved. |
*) |
MODULE ARITH; |
IMPORT STRINGS, UTILS, LISTS; |
CONST |
tINTEGER* = 1; tREAL* = 2; tSET* = 3; |
tBOOLEAN* = 4; tCHAR* = 5; tWCHAR* = 6; |
tSTRING* = 7; |
opEQ* = 0; opNE* = 1; opLT* = 2; opLE* = 3; opGT* = 4; opGE* = 5; |
opIN* = 6; opIS* = 7; |
TYPE |
VALUE* = RECORD |
typ*: INTEGER; |
int: INTEGER; |
float: REAL; |
set: SET; |
bool: BOOLEAN; |
string*: LISTS.ITEM |
END; |
VAR |
digit: ARRAY 256 OF INTEGER; |
PROCEDURE Int* (v: VALUE): INTEGER; |
VAR |
res: INTEGER; |
BEGIN |
CASE v.typ OF |
|tINTEGER, tCHAR, tWCHAR: |
res := v.int |
|tSET: |
res := UTILS.Long(ORD(v.set)) |
|tBOOLEAN: |
res := ORD(v.bool) |
END |
RETURN res |
END Int; |
PROCEDURE getBool* (v: VALUE): BOOLEAN; |
BEGIN |
ASSERT(v.typ = tBOOLEAN); |
RETURN v.bool |
END getBool; |
PROCEDURE Float* (v: VALUE): REAL; |
BEGIN |
ASSERT(v.typ = tREAL); |
RETURN v.float |
END Float; |
PROCEDURE range* (i: VALUE; a, b: INTEGER): BOOLEAN; |
RETURN (a <= i.int) & (i.int <= b) |
END range; |
PROCEDURE check* (v: VALUE): BOOLEAN; |
VAR |
res: BOOLEAN; |
BEGIN |
CASE v.typ OF |
|tINTEGER: res := range(v, UTILS.target.minInt, UTILS.target.maxInt) |
|tCHAR: res := range(v, 0, 255) |
|tWCHAR: res := range(v, 0, 65535) |
|tREAL: res := (-UTILS.target.maxReal <= v.float) & (v.float <= UTILS.target.maxReal) |
END |
RETURN res |
END check; |
PROCEDURE isZero* (v: VALUE): BOOLEAN; |
VAR |
res: BOOLEAN; |
BEGIN |
CASE v.typ OF |
|tINTEGER: res := v.int = 0 |
|tREAL: res := v.float = 0.0 |
END |
RETURN res |
END isZero; |
PROCEDURE iconv* (s: ARRAY OF CHAR; VAR v: VALUE; VAR error: INTEGER); |
VAR |
value: INTEGER; |
i: INTEGER; |
d: INTEGER; |
BEGIN |
error := 0; |
value := 0; |
i := 0; |
WHILE STRINGS.digit(s[i]) & (error = 0) DO |
d := digit[ORD(s[i])]; |
IF value <= (UTILS.maxint - d) DIV 10 THEN |
value := value * 10 + d; |
INC(i) |
ELSE |
error := 1 |
END |
END; |
IF error = 0 THEN |
v.int := value; |
v.typ := tINTEGER; |
IF ~check(v) THEN |
error := 1 |
END |
END |
END iconv; |
PROCEDURE hconv* (s: ARRAY OF CHAR; VAR v: VALUE; VAR error: INTEGER); |
VAR |
value: INTEGER; |
i: INTEGER; |
n: INTEGER; |
d: INTEGER; |
BEGIN |
ASSERT(STRINGS.digit(s[0])); |
error := 0; |
value := 0; |
n := -1; |
i := 0; |
WHILE (s[i] # "H") & (s[i] # "X") & (s[i] # "h") & (s[i] # "x") & (error = 0) DO |
d := digit[ORD(s[i])]; |
IF (n = -1) & (d # 0) THEN |
n := i |
END; |
IF (n # -1) & (i - n + 1 > UTILS.target.maxHex) THEN |
error := 2 |
ELSE |
value := value * 16 + d; |
INC(i) |
END |
END; |
value := UTILS.Long(value); |
IF ((s[i] = "X") OR (s[i] = "x")) & (n # -1) & (i - n > 4) THEN |
error := 3 |
END; |
IF error = 0 THEN |
v.int := value; |
IF (s[i] = "X") OR (s[i] = "x") THEN |
v.typ := tCHAR; |
IF ~check(v) THEN |
v.typ := tWCHAR; |
IF ~check(v) THEN |
error := 3 |
END |
END |
ELSE |
v.typ := tINTEGER; |
IF ~check(v) THEN |
error := 2 |
END |
END |
END |
END hconv; |
PROCEDURE opFloat2 (VAR a: REAL; b: REAL; op: CHAR): BOOLEAN; |
BEGIN |
CASE op OF |
|"+": a := a + b |
|"-": a := a - b |
|"*": a := a * b |
|"/": a := a / b |
END |
RETURN (-UTILS.maxreal <= a) & (a <= UTILS.maxreal) (* +inf > UTILS.maxreal *) |
END opFloat2; |
PROCEDURE fconv* (s: ARRAY OF CHAR; VAR v: VALUE; VAR error: INTEGER); |
VAR |
value: REAL; |
frac: REAL; |
exp10: REAL; |
i, n, d: INTEGER; |
minus: BOOLEAN; |
BEGIN |
error := 0; |
value := 0.0; |
frac := 0.0; |
exp10 := 1.0; |
minus := FALSE; |
n := 0; |
i := 0; |
WHILE (error = 0) & STRINGS.digit(s[i]) DO |
IF opFloat2(value, 10.0, "*") & opFloat2(value, FLT(digit[ORD(s[i])]), "+") THEN |
INC(i) |
ELSE |
error := 4 |
END |
END; |
INC(i); |
WHILE (error = 0) & STRINGS.digit(s[i]) DO |
IF opFloat2(frac, 10.0, "*") & opFloat2(frac, FLT(digit[ORD(s[i])]), "+") THEN |
exp10 := exp10 * 10.0; |
INC(i) |
ELSE |
error := 4 |
END |
END; |
IF ~opFloat2(value, frac / exp10, "+") THEN |
error := 4 |
END; |
IF (s[i] = "E") OR (s[i] = "e") THEN |
INC(i) |
END; |
IF (s[i] = "-") OR (s[i] = "+") THEN |
minus := s[i] = "-"; |
INC(i) |
END; |
WHILE (error = 0) & STRINGS.digit(s[i]) DO |
d := digit[ORD(s[i])]; |
IF n <= (UTILS.maxint - d) DIV 10 THEN |
n := n * 10 + d; |
INC(i) |
ELSE |
error := 5 |
END |
END; |
exp10 := 1.0; |
WHILE (error = 0) & (n > 0) DO |
IF opFloat2(exp10, 10.0, "*") THEN |
DEC(n) |
ELSE |
error := 4 |
END |
END; |
IF error = 0 THEN |
IF minus THEN |
IF ~opFloat2(value, exp10, "/") THEN |
error := 4 |
END |
ELSE |
IF ~opFloat2(value, exp10, "*") THEN |
error := 4 |
END |
END |
END; |
IF error = 0 THEN |
v.float := value; |
v.typ := tREAL; |
IF ~check(v) THEN |
error := 4 |
END |
END |
END fconv; |
PROCEDURE setChar* (VAR v: VALUE; ord: INTEGER); |
BEGIN |
v.typ := tCHAR; |
v.int := ord |
END setChar; |
PROCEDURE setWChar* (VAR v: VALUE; ord: INTEGER); |
BEGIN |
v.typ := tWCHAR; |
v.int := ord |
END setWChar; |
PROCEDURE addInt (VAR a: INTEGER; b: INTEGER): BOOLEAN; |
VAR |
error: BOOLEAN; |
BEGIN |
IF (a > 0) & (b > 0) THEN |
error := a > UTILS.maxint - b |
ELSIF (a < 0) & (b < 0) THEN |
error := a < UTILS.minint - b |
ELSE |
error := FALSE |
END; |
IF ~error THEN |
a := a + b |
ELSE |
a := 0 |
END |
RETURN ~error |
END addInt; |
PROCEDURE subInt (VAR a: INTEGER; b: INTEGER): BOOLEAN; |
VAR |
error: BOOLEAN; |
BEGIN |
IF (a > 0) & (b < 0) THEN |
error := a > UTILS.maxint + b |
ELSIF (a < 0) & (b > 0) THEN |
error := a < UTILS.minint + b |
ELSIF (a = 0) & (b < 0) THEN |
error := b = UTILS.minint |
ELSE |
error := FALSE |
END; |
IF ~error THEN |
a := a - b |
ELSE |
a := 0 |
END |
RETURN ~error |
END subInt; |
PROCEDURE lg2 (x: INTEGER): INTEGER; |
VAR |
n: INTEGER; |
BEGIN |
ASSERT(x > 0); |
n := UTILS.Log2(x); |
IF n = -1 THEN |
n := 255 |
END |
RETURN n |
END lg2; |
PROCEDURE mulInt* (VAR a: INTEGER; b: INTEGER): BOOLEAN; |
VAR |
error: BOOLEAN; |
min, max: INTEGER; |
BEGIN |
min := UTILS.minint; |
max := UTILS.maxint; |
IF ((a > 1) & (b > 1)) OR ((a < 0) & (b < 0)) THEN |
error := (a = min) OR (b = min) OR (ABS(a) > max DIV ABS(b)) |
ELSIF ((a > 1) & (b < 0)) OR ((a < 0) & (b > 1)) THEN |
error := (a = min) OR (b = min); |
IF ~error THEN |
IF lg2(ABS(a)) + lg2(ABS(b)) >= UTILS.bit_depth THEN |
error := ABS(a) > max DIV ABS(b) |
END |
END |
ELSE |
error := FALSE |
END; |
IF ~error THEN |
a := a * b |
ELSE |
a := 0 |
END |
RETURN ~error |
END mulInt; |
PROCEDURE _ASR (x, n: INTEGER): INTEGER; |
RETURN ASR(UTILS.Long(x), n) |
END _ASR; |
PROCEDURE _LSR (x, n: INTEGER): INTEGER; |
RETURN UTILS.Long(LSR(UTILS.Short(x), n)) |
END _LSR; |
PROCEDURE _LSL (x, n: INTEGER): INTEGER; |
RETURN UTILS.Long(LSL(x, n)) |
END _LSL; |
PROCEDURE _ROR1_32 (x: INTEGER): INTEGER; |
BEGIN |
x := UTILS.Short(x); |
x := ORD(BITS(LSR(x, 1)) + BITS(LSL(x, 31))) |
RETURN UTILS.Long(x) |
END _ROR1_32; |
PROCEDURE _ROR1_16 (x: INTEGER): INTEGER; |
BEGIN |
x := x MOD 65536; |
x := ORD(BITS(LSR(x, 1)) + BITS(LSL(x, 15))) |
RETURN UTILS.Long(x) |
END _ROR1_16; |
PROCEDURE _ROR (x, n: INTEGER): INTEGER; |
BEGIN |
CASE UTILS.bit_diff OF |
|0: x := ROR(x, n) |
|16, 48: |
n := n MOD 16; |
WHILE n > 0 DO |
x := _ROR1_16(x); |
DEC(n) |
END |
|32: |
n := n MOD 32; |
WHILE n > 0 DO |
x := _ROR1_32(x); |
DEC(n) |
END |
END |
RETURN x |
END _ROR; |
PROCEDURE opInt* (VAR a: VALUE; b: VALUE; op: CHAR): BOOLEAN; |
VAR |
success: BOOLEAN; |
BEGIN |
success := TRUE; |
CASE op OF |
|"+": success := addInt(a.int, b.int) |
|"-": success := subInt(a.int, b.int) |
|"*": success := mulInt(a.int, b.int) |
|"/": success := FALSE |
|"D": a.int := a.int DIV b.int |
|"M": a.int := a.int MOD b.int |
|"L": a.int := _LSL(a.int, b.int) |
|"A": a.int := _ASR(a.int, b.int) |
|"O": a.int := _ROR(a.int, b.int) |
|"R": a.int := _LSR(a.int, b.int) |
|"m": a.int := MIN(a.int, b.int) |
|"x": a.int := MAX(a.int, b.int) |
END; |
a.typ := tINTEGER |
RETURN success & check(a) |
END opInt; |
PROCEDURE charToStr* (c: VALUE; VAR s: ARRAY OF CHAR); |
BEGIN |
s[0] := CHR(c.int); |
s[1] := 0X |
END charToStr; |
PROCEDURE opSet* (VAR a: VALUE; b: VALUE; op: CHAR); |
BEGIN |
CASE op OF |
|"+": a.set := a.set + b.set |
|"-": a.set := a.set - b.set |
|"*": a.set := a.set * b.set |
|"/": a.set := a.set / b.set |
END; |
a.typ := tSET |
END opSet; |
PROCEDURE opFloat* (VAR a: VALUE; b: VALUE; op: CHAR): BOOLEAN; |
BEGIN |
a.typ := tREAL |
RETURN opFloat2(a.float, b.float, op) & check(a) |
END opFloat; |
PROCEDURE ord* (VAR v: VALUE); |
BEGIN |
CASE v.typ OF |
|tCHAR, tWCHAR: |
|tBOOLEAN: v.int := ORD(v.bool) |
|tSET: v.int := UTILS.Long(ORD(v.set)) |
END; |
v.typ := tINTEGER |
END ord; |
PROCEDURE odd* (VAR v: VALUE); |
BEGIN |
v.typ := tBOOLEAN; |
v.bool := ODD(v.int) |
END odd; |
PROCEDURE bits* (VAR v: VALUE); |
BEGIN |
v.typ := tSET; |
v.set := BITS(v.int) |
END bits; |
PROCEDURE abs* (VAR v: VALUE): BOOLEAN; |
VAR |
res: BOOLEAN; |
BEGIN |
res := FALSE; |
CASE v.typ OF |
|tREAL: |
v.float := ABS(v.float); |
res := TRUE |
|tINTEGER: |
IF v.int # UTILS.minint THEN |
v.int := ABS(v.int); |
res := TRUE |
END |
END |
RETURN res |
END abs; |
PROCEDURE floor* (VAR v: VALUE): BOOLEAN; |
VAR |
res: BOOLEAN; |
BEGIN |
v.typ := tINTEGER; |
res := (FLT(UTILS.minint) <= v.float) & (v.float <= FLT(UTILS.maxint)); |
IF res THEN |
v.int := FLOOR(v.float) |
END |
RETURN res |
END floor; |
PROCEDURE flt* (VAR v: VALUE); |
BEGIN |
v.typ := tREAL; |
v.float := FLT(v.int) |
END flt; |
PROCEDURE neg* (VAR v: VALUE): BOOLEAN; |
VAR |
z: VALUE; |
res: BOOLEAN; |
BEGIN |
res := TRUE; |
z.typ := tINTEGER; |
z.int := 0; |
CASE v.typ OF |
|tREAL: v.float := -v.float |
|tSET: v.set := -v.set |
|tINTEGER: res := opInt(z, v, "-"); v := z |
|tBOOLEAN: v.bool := ~v.bool |
END |
RETURN res |
END neg; |
PROCEDURE setbool* (VAR v: VALUE; b: BOOLEAN); |
BEGIN |
v.bool := b; |
v.typ := tBOOLEAN |
END setbool; |
PROCEDURE opBoolean* (VAR a: VALUE; b: VALUE; op: CHAR); |
BEGIN |
CASE op OF |
|"&": a.bool := a.bool & b.bool |
|"|": a.bool := a.bool OR b.bool |
END; |
a.typ := tBOOLEAN |
END opBoolean; |
PROCEDURE less (v, v2: VALUE; VAR error: INTEGER): BOOLEAN; |
VAR |
res: BOOLEAN; |
BEGIN |
res := FALSE; |
IF (v.typ = v2.typ) OR (v.typ IN {tCHAR, tWCHAR}) & (v2.typ IN {tCHAR, tWCHAR}) THEN |
CASE v.typ OF |
|tINTEGER, |
tWCHAR, |
tCHAR: res := v.int < v2.int |
|tREAL: res := v.float < v2.float |
|tBOOLEAN, |
tSET: error := 1 |
END |
ELSE |
error := 1 |
END |
RETURN res |
END less; |
PROCEDURE equal (v, v2: VALUE; VAR error: INTEGER): BOOLEAN; |
VAR |
res: BOOLEAN; |
BEGIN |
res := FALSE; |
IF (v.typ = v2.typ) OR (v.typ IN {tCHAR, tWCHAR}) & (v2.typ IN {tCHAR, tWCHAR}) THEN |
CASE v.typ OF |
|tINTEGER, |
tWCHAR, |
tCHAR: res := v.int = v2.int |
|tREAL: res := v.float = v2.float |
|tBOOLEAN: res := v.bool = v2.bool |
|tSET: res := v.set = v2.set |
END |
ELSE |
error := 1 |
END |
RETURN res |
END equal; |
PROCEDURE relation* (VAR v: VALUE; v2: VALUE; op: INTEGER; VAR error: INTEGER); |
VAR |
res: BOOLEAN; |
BEGIN |
error := 0; |
res := FALSE; |
CASE op OF |
|opEQ: |
res := equal(v, v2, error) |
|opNE: |
res := ~equal(v, v2, error) |
|opLT: |
res := less(v, v2, error) |
|opLE: |
res := less(v, v2, error); |
IF error = 0 THEN |
res := equal(v, v2, error) OR res |
END |
|opGE: |
res := ~less(v, v2, error) |
|opGT: |
res := less(v, v2, error); |
IF error = 0 THEN |
res := equal(v, v2, error) OR res |
END; |
res := ~res |
|opIN: |
IF (v.typ = tINTEGER) & (v2.typ = tSET) THEN |
IF range(v, 0, UTILS.target.maxSet) THEN |
res := v.int IN v2.set |
ELSE |
error := 2 |
END |
ELSE |
error := 1 |
END |
END; |
IF error = 0 THEN |
v.bool := res; |
v.typ := tBOOLEAN |
END |
END relation; |
PROCEDURE emptySet* (VAR v: VALUE); |
BEGIN |
v.typ := tSET; |
v.set := {} |
END emptySet; |
PROCEDURE constrSet* (VAR v: VALUE; a, b: VALUE); |
BEGIN |
v.typ := tSET; |
v.set := {a.int .. b.int} |
END constrSet; |
PROCEDURE getInt* (v: VALUE): INTEGER; |
BEGIN |
ASSERT(check(v)) |
RETURN v.int |
END getInt; |
PROCEDURE setInt* (VAR v: VALUE; i: INTEGER): BOOLEAN; |
BEGIN |
v.int := i; |
v.typ := tINTEGER |
RETURN check(v) |
END setInt; |
PROCEDURE concat* (VAR s: ARRAY OF CHAR; s1: ARRAY OF CHAR): BOOLEAN; |
VAR |
res: BOOLEAN; |
BEGIN |
res := LENGTH(s) + LENGTH(s1) < LEN(s); |
IF res THEN |
STRINGS.append(s, s1) |
END |
RETURN res |
END concat; |
PROCEDURE init; |
VAR |
i: INTEGER; |
BEGIN |
FOR i := 0 TO LEN(digit) - 1 DO |
digit[i] := -1 |
END; |
FOR i := ORD("0") TO ORD("9") DO |
digit[i] := i - ORD("0") |
END; |
FOR i := ORD("A") TO ORD("F") DO |
digit[i] := i - ORD("A") + 10 |
END |
END init; |
BEGIN |
init |
END ARITH. |
/programs/develop/oberon07/source/CHUNKLISTS.ob07 |
---|
0,0 → 1,255 |
(* |
BSD 2-Clause License |
Copyright (c) 2018-2021, Anton Krotov |
All rights reserved. |
*) |
MODULE CHUNKLISTS; |
IMPORT LISTS, WR := WRITER; |
CONST |
LENOFBYTECHUNK = 65536; |
LENOFINTCHUNK = 16384; |
TYPE |
ANYLIST = POINTER TO RECORD (LISTS.LIST) |
length: INTEGER |
END; |
BYTELIST* = POINTER TO RECORD (ANYLIST) END; |
BYTECHUNK = POINTER TO RECORD (LISTS.ITEM) |
data: ARRAY LENOFBYTECHUNK OF BYTE; |
count: INTEGER |
END; |
INTLIST* = POINTER TO RECORD (ANYLIST) END; |
INTCHUNK = POINTER TO RECORD (LISTS.ITEM) |
data: ARRAY LENOFINTCHUNK OF INTEGER; |
count: INTEGER |
END; |
PROCEDURE SetByte* (list: BYTELIST; idx: INTEGER; byte: BYTE); |
VAR |
chunk: BYTECHUNK; |
item: LISTS.ITEM; |
BEGIN |
ASSERT(idx >= 0); |
ASSERT(list # NIL); |
item := LISTS.getidx(list, idx DIV LENOFBYTECHUNK); |
ASSERT(item # NIL); |
chunk := item(BYTECHUNK); |
idx := idx MOD LENOFBYTECHUNK; |
ASSERT(idx < chunk.count); |
chunk.data[idx] := byte |
END SetByte; |
PROCEDURE GetByte* (list: BYTELIST; idx: INTEGER): BYTE; |
VAR |
chunk: BYTECHUNK; |
item: LISTS.ITEM; |
BEGIN |
ASSERT(idx >= 0); |
ASSERT(list # NIL); |
item := LISTS.getidx(list, idx DIV LENOFBYTECHUNK); |
ASSERT(item # NIL); |
chunk := item(BYTECHUNK); |
idx := idx MOD LENOFBYTECHUNK; |
ASSERT(idx < chunk.count) |
RETURN chunk.data[idx] |
END GetByte; |
PROCEDURE PushByte* (list: BYTELIST; byte: BYTE); |
VAR |
chunk: BYTECHUNK; |
BEGIN |
ASSERT(list # NIL); |
chunk := list.last(BYTECHUNK); |
IF chunk.count = LENOFBYTECHUNK THEN |
NEW(chunk); |
chunk.count := 0; |
LISTS.push(list, chunk) |
END; |
chunk.data[chunk.count] := byte; |
INC(chunk.count); |
INC(list.length) |
END PushByte; |
PROCEDURE PushStr* (list: BYTELIST; str: ARRAY OF CHAR): INTEGER; |
VAR |
i, res: INTEGER; |
BEGIN |
res := list.length; |
i := 0; |
REPEAT |
PushByte(list, ORD(str[i])); |
INC(i) |
UNTIL str[i - 1] = 0X |
RETURN res |
END PushStr; |
PROCEDURE GetStr* (list: BYTELIST; pos: INTEGER; VAR str: ARRAY OF CHAR): BOOLEAN; |
VAR |
i: INTEGER; |
res: BOOLEAN; |
BEGIN |
res := FALSE; |
i := 0; |
WHILE (pos < list.length) & (i < LEN(str)) & ~res DO |
str[i] := CHR(GetByte(list, pos)); |
res := str[i] = 0X; |
INC(pos); |
INC(i) |
END |
RETURN res |
END GetStr; |
PROCEDURE WriteToFile* (list: BYTELIST); |
VAR |
chunk: BYTECHUNK; |
BEGIN |
chunk := list.first(BYTECHUNK); |
WHILE chunk # NIL DO |
WR.Write(chunk.data, chunk.count); |
chunk := chunk.next(BYTECHUNK) |
END |
END WriteToFile; |
PROCEDURE CreateByteList* (): BYTELIST; |
VAR |
bytelist: BYTELIST; |
list: LISTS.LIST; |
chunk: BYTECHUNK; |
BEGIN |
NEW(bytelist); |
list := LISTS.create(bytelist); |
bytelist.length := 0; |
NEW(chunk); |
chunk.count := 0; |
LISTS.push(list, chunk) |
RETURN list(BYTELIST) |
END CreateByteList; |
PROCEDURE SetInt* (list: INTLIST; idx: INTEGER; int: INTEGER); |
VAR |
chunk: INTCHUNK; |
item: LISTS.ITEM; |
BEGIN |
ASSERT(idx >= 0); |
ASSERT(list # NIL); |
item := LISTS.getidx(list, idx DIV LENOFINTCHUNK); |
ASSERT(item # NIL); |
chunk := item(INTCHUNK); |
idx := idx MOD LENOFINTCHUNK; |
ASSERT(idx < chunk.count); |
chunk.data[idx] := int |
END SetInt; |
PROCEDURE GetInt* (list: INTLIST; idx: INTEGER): INTEGER; |
VAR |
chunk: INTCHUNK; |
item: LISTS.ITEM; |
BEGIN |
ASSERT(idx >= 0); |
ASSERT(list # NIL); |
item := LISTS.getidx(list, idx DIV LENOFINTCHUNK); |
ASSERT(item # NIL); |
chunk := item(INTCHUNK); |
idx := idx MOD LENOFINTCHUNK; |
ASSERT(idx < chunk.count) |
RETURN chunk.data[idx] |
END GetInt; |
PROCEDURE PushInt* (list: INTLIST; int: INTEGER); |
VAR |
chunk: INTCHUNK; |
BEGIN |
ASSERT(list # NIL); |
chunk := list.last(INTCHUNK); |
IF chunk.count = LENOFINTCHUNK THEN |
NEW(chunk); |
chunk.count := 0; |
LISTS.push(list, chunk) |
END; |
chunk.data[chunk.count] := int; |
INC(chunk.count); |
INC(list.length) |
END PushInt; |
PROCEDURE CreateIntList* (): INTLIST; |
VAR |
intlist: INTLIST; |
list: LISTS.LIST; |
chunk: INTCHUNK; |
BEGIN |
NEW(intlist); |
list := LISTS.create(intlist); |
intlist.length := 0; |
NEW(chunk); |
chunk.count := 0; |
LISTS.push(list, chunk) |
RETURN list(INTLIST) |
END CreateIntList; |
PROCEDURE Length* (list: ANYLIST): INTEGER; |
RETURN list.length |
END Length; |
END CHUNKLISTS. |
/programs/develop/oberon07/source/CONSOLE.ob07 |
---|
0,0 → 1,78 |
(* |
BSD 2-Clause License |
Copyright (c) 2018-2021, Anton Krotov |
All rights reserved. |
*) |
MODULE CONSOLE; |
IMPORT UTILS, STRINGS; |
PROCEDURE String* (s: ARRAY OF CHAR); |
VAR |
i: INTEGER; |
BEGIN |
i := 0; |
WHILE (i < LEN(s)) & (s[i] # 0X) DO |
UTILS.OutChar(s[i]); |
INC(i) |
END |
END String; |
PROCEDURE Int* (x: INTEGER); |
VAR |
s: ARRAY 24 OF CHAR; |
BEGIN |
STRINGS.IntToStr(x, s); |
String(s) |
END Int; |
PROCEDURE Int2* (x: INTEGER); |
BEGIN |
IF x < 10 THEN |
String("0") |
END; |
Int(x) |
END Int2; |
PROCEDURE Ln*; |
BEGIN |
String(UTILS.eol) |
END Ln; |
PROCEDURE StringLn* (s: ARRAY OF CHAR); |
BEGIN |
String(s); |
Ln |
END StringLn; |
PROCEDURE IntLn* (x: INTEGER); |
BEGIN |
Int(x); |
Ln |
END IntLn; |
PROCEDURE Int2Ln* (x: INTEGER); |
BEGIN |
Int2(x); |
Ln |
END Int2Ln; |
PROCEDURE Dashes*; |
BEGIN |
StringLn("------------------------------------------------") |
END Dashes; |
END CONSOLE. |
/programs/develop/oberon07/source/Compiler.ob07 |
---|
0,0 → 1,333 |
(* |
BSD 2-Clause License |
Copyright (c) 2018-2021, Anton Krotov |
All rights reserved. |
*) |
MODULE Compiler; |
IMPORT ST := STATEMENTS, PARS, UTILS, PATHS, PROG, C := CONSOLE, |
ERRORS, STRINGS, WRITER, MSP430, THUMB, TARGETS, SCAN; |
CONST |
DEF_WINDOWS = "WINDOWS"; |
DEF_LINUX = "LINUX"; |
DEF_KOLIBRIOS = "KOLIBRIOS"; |
DEF_CPU_X86 = "CPU_X86"; |
DEF_CPU_X8664 = "CPU_X8664"; |
PROCEDURE keys (VAR options: PROG.OPTIONS; VAR out: PARS.PATH); |
VAR |
param: PARS.PATH; |
i, j: INTEGER; |
_end: BOOLEAN; |
value: INTEGER; |
minor, |
major: INTEGER; |
checking: SET; |
BEGIN |
out := ""; |
checking := options.checking; |
_end := FALSE; |
i := 3; |
REPEAT |
UTILS.GetArg(i, param); |
IF param = "-stk" THEN |
INC(i); |
UTILS.GetArg(i, param); |
IF STRINGS.StrToInt(param, value) & (1 <= value) & (value <= 32) THEN |
options.stack := value |
END; |
IF param[0] = "-" THEN |
DEC(i) |
END |
ELSIF param = "-out" THEN |
INC(i); |
UTILS.GetArg(i, param); |
IF param[0] = "-" THEN |
DEC(i) |
ELSE |
out := param |
END |
ELSIF param = "-ram" THEN |
INC(i); |
UTILS.GetArg(i, param); |
IF STRINGS.StrToInt(param, value) THEN |
options.ram := value |
END; |
IF param[0] = "-" THEN |
DEC(i) |
END |
ELSIF param = "-rom" THEN |
INC(i); |
UTILS.GetArg(i, param); |
IF STRINGS.StrToInt(param, value) THEN |
options.rom := value |
END; |
IF param[0] = "-" THEN |
DEC(i) |
END |
ELSIF param = "-nochk" THEN |
INC(i); |
UTILS.GetArg(i, param); |
IF param[0] = "-" THEN |
DEC(i) |
ELSE |
j := 0; |
WHILE param[j] # 0X DO |
IF param[j] = "p" THEN |
EXCL(checking, ST.chkPTR) |
ELSIF param[j] = "t" THEN |
EXCL(checking, ST.chkGUARD) |
ELSIF param[j] = "i" THEN |
EXCL(checking, ST.chkIDX) |
ELSIF param[j] = "b" THEN |
EXCL(checking, ST.chkBYTE) |
ELSIF param[j] = "c" THEN |
EXCL(checking, ST.chkCHR) |
ELSIF param[j] = "w" THEN |
EXCL(checking, ST.chkWCHR) |
ELSIF param[j] = "r" THEN |
EXCL(checking, ST.chkCHR); |
EXCL(checking, ST.chkWCHR); |
EXCL(checking, ST.chkBYTE) |
ELSIF param[j] = "s" THEN |
EXCL(checking, ST.chkSTK) |
ELSIF param[j] = "a" THEN |
checking := {} |
END; |
INC(j) |
END; |
END |
ELSIF param = "-ver" THEN |
INC(i); |
UTILS.GetArg(i, param); |
IF STRINGS.StrToVer(param, major, minor) THEN |
options.version := major * 65536 + minor |
END; |
IF param[0] = "-" THEN |
DEC(i) |
END |
ELSIF param = "-lower" THEN |
options.lower := TRUE |
ELSIF param = "-pic" THEN |
options.pic := TRUE |
ELSIF param = "-def" THEN |
INC(i); |
UTILS.GetArg(i, param); |
SCAN.NewDef(param) |
ELSIF param = "" THEN |
_end := TRUE |
ELSE |
ERRORS.BadParam(param) |
END; |
INC(i) |
UNTIL _end; |
options.checking := checking |
END keys; |
PROCEDURE OutTargetItem (target: INTEGER; text: ARRAY OF CHAR); |
VAR |
width: INTEGER; |
BEGIN |
width := 15; |
width := width - LENGTH(TARGETS.Targets[target].ComLinePar) - 4; |
C.String(" '"); C.String(TARGETS.Targets[target].ComLinePar); C.String("'"); |
WHILE width > 0 DO |
C.String(20X); |
DEC(width) |
END; |
C.StringLn(text) |
END OutTargetItem; |
PROCEDURE main; |
VAR |
path: PARS.PATH; |
inname: PARS.PATH; |
ext: PARS.PATH; |
app_path: PARS.PATH; |
lib_path: PARS.PATH; |
modname: PARS.PATH; |
outname: PARS.PATH; |
param: PARS.PATH; |
temp: PARS.PATH; |
target: INTEGER; |
time: INTEGER; |
options: PROG.OPTIONS; |
BEGIN |
options.stack := 2; |
options.version := 65536; |
options.pic := FALSE; |
options.lower := FALSE; |
options.checking := ST.chkALL; |
PATHS.GetCurrentDirectory(app_path); |
UTILS.GetArg(0, temp); |
PATHS.split(temp, path, modname, ext); |
IF PATHS.isRelative(path) THEN |
PATHS.RelPath(app_path, path, temp); |
path := temp |
END; |
lib_path := path; |
UTILS.GetArg(1, inname); |
STRINGS.replace(inname, "\", UTILS.slash); |
STRINGS.replace(inname, "/", UTILS.slash); |
C.Ln; |
C.String("Akron Oberon Compiler v"); C.Int(UTILS.vMajor); C.String("."); C.Int2(UTILS.vMinor); |
C.String(" ("); C.Int(UTILS.bit_depth); C.StringLn("-bit) " + UTILS.Date); |
C.StringLn("Copyright (c) 2018-2021, Anton Krotov"); |
IF inname = "" THEN |
C.Ln; |
C.StringLn("Usage: Compiler <main module> <target> [optional settings]"); C.Ln; |
C.StringLn("target ="); |
IF UTILS.bit_depth = 64 THEN |
OutTargetItem(TARGETS.Win64C, "Windows64 Console"); |
OutTargetItem(TARGETS.Win64GUI, "Windows64 GUI"); |
OutTargetItem(TARGETS.Win64DLL, "Windows64 DLL"); |
OutTargetItem(TARGETS.Linux64, "Linux64 Exec"); |
OutTargetItem(TARGETS.Linux64SO, "Linux64 SO") |
END; |
OutTargetItem(TARGETS.Win32C, "Windows32 Console"); |
OutTargetItem(TARGETS.Win32GUI, "Windows32 GUI"); |
OutTargetItem(TARGETS.Win32DLL, "Windows32 DLL"); |
OutTargetItem(TARGETS.Linux32, "Linux32 Exec"); |
OutTargetItem(TARGETS.Linux32SO, "Linux32 SO"); |
OutTargetItem(TARGETS.KolibriOS, "KolibriOS Exec"); |
OutTargetItem(TARGETS.KolibriOSDLL, "KolibriOS DLL"); |
OutTargetItem(TARGETS.MSP430, "MSP430x{1,2}xx microcontrollers"); |
OutTargetItem(TARGETS.STM32CM3, "STM32 Cortex-M3 microcontrollers"); |
C.Ln; |
C.StringLn("optional settings:"); C.Ln; |
C.StringLn(" -out <file name> output"); C.Ln; |
C.StringLn(" -stk <size> set size of stack in Mbytes (Windows, Linux, KolibriOS)"); C.Ln; |
C.StringLn(" -nochk <'ptibcwra'> disable runtime checking (pointers, types, indexes,"); |
C.StringLn(" BYTE, CHR, WCHR)"); C.Ln; |
C.StringLn(" -lower allow lower case for keywords"); C.Ln; |
C.StringLn(" -def <identifier> define conditional compilation symbol"); C.Ln; |
C.StringLn(" -ver <major.minor> set version of program (KolibriOS DLL)"); C.Ln; |
C.StringLn(" -ram <size> set size of RAM in bytes (MSP430) or Kbytes (STM32)"); C.Ln; |
C.StringLn(" -rom <size> set size of ROM in bytes (MSP430) or Kbytes (STM32)"); C.Ln; |
UTILS.Exit(0) |
END; |
C.Dashes; |
PATHS.split(inname, path, modname, ext); |
IF ext # UTILS.FILE_EXT THEN |
ERRORS.Error(207) |
END; |
IF PATHS.isRelative(path) THEN |
PATHS.RelPath(app_path, path, temp); |
path := temp |
END; |
UTILS.GetArg(2, param); |
IF param = "" THEN |
ERRORS.Error(205) |
END; |
SCAN.NewDef(param); |
IF TARGETS.Select(param) THEN |
target := TARGETS.target |
ELSE |
ERRORS.Error(206) |
END; |
IF TARGETS.CPU = TARGETS.cpuMSP430 THEN |
options.ram := MSP430.minRAM; |
options.rom := MSP430.minROM |
END; |
IF (TARGETS.CPU = TARGETS.cpuTHUMB) & (TARGETS.OS = TARGETS.osNONE) THEN |
options.ram := THUMB.minRAM; |
options.rom := THUMB.minROM |
END; |
IF UTILS.bit_depth < TARGETS.BitDepth THEN |
ERRORS.Error(206) |
END; |
STRINGS.append(lib_path, "lib"); |
STRINGS.append(lib_path, UTILS.slash); |
STRINGS.append(lib_path, TARGETS.LibDir); |
STRINGS.append(lib_path, UTILS.slash); |
keys(options, outname); |
IF outname = "" THEN |
outname := path; |
STRINGS.append(outname, modname); |
STRINGS.append(outname, TARGETS.FileExt) |
ELSE |
IF PATHS.isRelative(outname) THEN |
PATHS.RelPath(app_path, outname, temp); |
outname := temp |
END |
END; |
PARS.init(options); |
CASE TARGETS.OS OF |
|TARGETS.osNONE: |
|TARGETS.osWIN32, |
TARGETS.osWIN64: SCAN.NewDef(DEF_WINDOWS) |
|TARGETS.osLINUX32, |
TARGETS.osLINUX64: SCAN.NewDef(DEF_LINUX) |
|TARGETS.osKOS: SCAN.NewDef(DEF_KOLIBRIOS) |
END; |
CASE TARGETS.CPU OF |
|TARGETS.cpuX86: SCAN.NewDef(DEF_CPU_X86) |
|TARGETS.cpuAMD64: SCAN.NewDef(DEF_CPU_X8664) |
|TARGETS.cpuMSP430: |
|TARGETS.cpuTHUMB: |
|TARGETS.cpuRVM32I: |
|TARGETS.cpuRVM64I: |
END; |
ST.compile(path, lib_path, modname, outname, target, options); |
time := UTILS.GetTickCount() - UTILS.time; |
C.Dashes; |
C.Int(PARS.lines); C.String(" lines, "); |
C.Int(time DIV 100); C.String("."); C.Int2(time MOD 100); C.String(" sec, "); |
C.Int(WRITER.counter); C.StringLn(" bytes"); |
UTILS.Exit(0) |
END main; |
BEGIN |
main |
END Compiler. |
/programs/develop/oberon07/source/ELF.ob07 |
---|
0,0 → 1,592 |
(* |
BSD 2-Clause License |
Copyright (c) 2019-2021, Anton Krotov |
All rights reserved. |
*) |
MODULE ELF; |
IMPORT BIN, WR := WRITER, CHL := CHUNKLISTS, LISTS, PE32, UTILS, STRINGS; |
CONST |
EI_NIDENT = 16; |
ET_EXEC = 2; |
ET_DYN = 3; |
EM_386 = 3; |
EM_8664 = 3EH; |
ELFCLASS32 = 1; |
ELFCLASS64 = 2; |
ELFDATA2LSB = 1; |
ELFDATA2MSB = 2; |
PF_X = 1; |
PF_W = 2; |
PF_R = 4; |
TYPE |
Elf32_Ehdr = RECORD |
e_ident: ARRAY EI_NIDENT OF BYTE; |
e_type, |
e_machine: WCHAR; |
e_version, |
e_entry, |
e_phoff, |
e_shoff, |
e_flags: INTEGER; |
e_ehsize, |
e_phentsize, |
e_phnum, |
e_shentsize, |
e_shnum, |
e_shstrndx: WCHAR |
END; |
Elf32_Phdr = RECORD |
p_type, |
p_offset, |
p_vaddr, |
p_paddr, |
p_filesz, |
p_memsz, |
p_flags, |
p_align: INTEGER |
END; |
Elf32_Dyn = POINTER TO RECORD (LISTS.ITEM) |
d_tag, d_val: INTEGER |
END; |
Elf32_Sym = POINTER TO RECORD (LISTS.ITEM) |
name, value, size: INTEGER; |
info, other: CHAR; |
shndx: WCHAR |
END; |
VAR |
dynamic: LISTS.LIST; |
strtab: CHL.BYTELIST; |
symtab: LISTS.LIST; |
hashtab, bucket, chain: CHL.INTLIST; |
PROCEDURE Write16 (w: WCHAR); |
BEGIN |
WR.Write16LE(ORD(w)) |
END Write16; |
PROCEDURE WritePH (ph: Elf32_Phdr); |
BEGIN |
WR.Write32LE(ph.p_type); |
WR.Write32LE(ph.p_offset); |
WR.Write32LE(ph.p_vaddr); |
WR.Write32LE(ph.p_paddr); |
WR.Write32LE(ph.p_filesz); |
WR.Write32LE(ph.p_memsz); |
WR.Write32LE(ph.p_flags); |
WR.Write32LE(ph.p_align) |
END WritePH; |
PROCEDURE WritePH64 (ph: Elf32_Phdr); |
BEGIN |
WR.Write32LE(ph.p_type); |
WR.Write32LE(ph.p_flags); |
WR.Write64LE(ph.p_offset); |
WR.Write64LE(ph.p_vaddr); |
WR.Write64LE(ph.p_paddr); |
WR.Write64LE(ph.p_filesz); |
WR.Write64LE(ph.p_memsz); |
WR.Write64LE(ph.p_align) |
END WritePH64; |
PROCEDURE NewDyn (tag, val: INTEGER); |
VAR |
dyn: Elf32_Dyn; |
BEGIN |
NEW(dyn); |
dyn.d_tag := tag; |
dyn.d_val := val; |
LISTS.push(dynamic, dyn) |
END NewDyn; |
PROCEDURE NewSym (name, value, size: INTEGER; info, other: CHAR; shndx: WCHAR); |
VAR |
sym: Elf32_Sym; |
BEGIN |
NEW(sym); |
sym.name := name; |
sym.value := value; |
sym.size := size; |
sym.info := info; |
sym.other := other; |
sym.shndx := shndx; |
LISTS.push(symtab, sym) |
END NewSym; |
PROCEDURE MakeHash (bucket, chain: CHL.INTLIST; symCount: INTEGER); |
VAR |
symi, hi, k: INTEGER; |
BEGIN |
FOR symi := 0 TO symCount - 1 DO |
CHL.SetInt(chain, symi, 0); |
hi := CHL.GetInt(hashtab, symi) MOD symCount; |
IF CHL.GetInt(bucket, hi) # 0 THEN |
k := symi; |
WHILE CHL.GetInt(chain, k) # 0 DO |
k := CHL.GetInt(chain, k) |
END; |
CHL.SetInt(chain, k, CHL.GetInt(bucket, hi)) |
END; |
CHL.SetInt(bucket, hi, symi) |
END |
END MakeHash; |
PROCEDURE write* (program: BIN.PROGRAM; FileName: ARRAY OF CHAR; fini: INTEGER; so, amd64: BOOLEAN); |
CONST |
interp = 0; |
dyn = 1; |
header = 2; |
text = 3; |
data = 4; |
bss = 5; |
linuxInterpreter64 = "/lib64/ld-linux-x86-64.so.2"; |
linuxInterpreter32 = "/lib/ld-linux.so.2"; |
exeBaseAddress32 = 8048000H; |
exeBaseAddress64 = 400000H; |
dllBaseAddress = 0; |
DT_NULL = 0; |
DT_NEEDED = 1; |
DT_HASH = 4; |
DT_STRTAB = 5; |
DT_SYMTAB = 6; |
DT_RELA = 7; |
DT_RELASZ = 8; |
DT_RELAENT = 9; |
DT_STRSZ = 10; |
DT_SYMENT = 11; |
DT_INIT = 12; |
DT_FINI = 13; |
DT_SONAME = 14; |
DT_REL = 17; |
DT_RELSZ = 18; |
DT_RELENT = 19; |
VAR |
ehdr: Elf32_Ehdr; |
phdr: ARRAY 16 OF Elf32_Phdr; |
i, BaseAdr, DynAdr, offset, pad, VA, symCount: INTEGER; |
SizeOf: RECORD header, code, data, bss: INTEGER END; |
Offset: RECORD symtab, reltab, hash, strtab: INTEGER END; |
Interpreter: ARRAY 40 OF CHAR; lenInterpreter: INTEGER; |
item: LISTS.ITEM; |
Name: ARRAY 2048 OF CHAR; |
Address: PE32.VIRTUAL_ADDR; |
BEGIN |
dynamic := LISTS.create(NIL); |
symtab := LISTS.create(NIL); |
strtab := CHL.CreateByteList(); |
IF amd64 THEN |
BaseAdr := exeBaseAddress64; |
Interpreter := linuxInterpreter64 |
ELSE |
BaseAdr := exeBaseAddress32; |
Interpreter := linuxInterpreter32 |
END; |
IF so THEN |
BaseAdr := dllBaseAddress |
END; |
lenInterpreter := LENGTH(Interpreter) + 1; |
SizeOf.code := CHL.Length(program.code); |
SizeOf.data := CHL.Length(program.data); |
SizeOf.bss := program.bss; |
ehdr.e_ident[0] := 7FH; |
ehdr.e_ident[1] := ORD("E"); |
ehdr.e_ident[2] := ORD("L"); |
ehdr.e_ident[3] := ORD("F"); |
IF amd64 THEN |
ehdr.e_ident[4] := ELFCLASS64 |
ELSE |
ehdr.e_ident[4] := ELFCLASS32 |
END; |
ehdr.e_ident[5] := ELFDATA2LSB; |
ehdr.e_ident[6] := 1; |
ehdr.e_ident[7] := 3; |
FOR i := 8 TO EI_NIDENT - 1 DO |
ehdr.e_ident[i] := 0 |
END; |
IF so THEN |
ehdr.e_type := WCHR(ET_DYN) |
ELSE |
ehdr.e_type := WCHR(ET_EXEC) |
END; |
ehdr.e_version := 1; |
ehdr.e_shoff := 0; |
ehdr.e_flags := 0; |
ehdr.e_shnum := WCHR(0); |
ehdr.e_shstrndx := WCHR(0); |
ehdr.e_phnum := WCHR(6); |
IF amd64 THEN |
ehdr.e_machine := WCHR(EM_8664); |
ehdr.e_phoff := 40H; |
ehdr.e_ehsize := WCHR(40H); |
ehdr.e_phentsize := WCHR(38H); |
ehdr.e_shentsize := WCHR(40H) |
ELSE |
ehdr.e_machine := WCHR(EM_386); |
ehdr.e_phoff := 34H; |
ehdr.e_ehsize := WCHR(34H); |
ehdr.e_phentsize := WCHR(20H); |
ehdr.e_shentsize := WCHR(28H) |
END; |
SizeOf.header := ORD(ehdr.e_ehsize) + ORD(ehdr.e_phentsize) * ORD(ehdr.e_phnum); |
phdr[interp].p_type := 3; |
phdr[interp].p_offset := SizeOf.header; |
phdr[interp].p_vaddr := BaseAdr + phdr[interp].p_offset; |
phdr[interp].p_paddr := phdr[interp].p_vaddr; |
phdr[interp].p_filesz := lenInterpreter; |
phdr[interp].p_memsz := lenInterpreter; |
phdr[interp].p_flags := PF_R; |
phdr[interp].p_align := 1; |
phdr[dyn].p_type := 2; |
phdr[dyn].p_offset := phdr[interp].p_offset + phdr[interp].p_filesz; |
phdr[dyn].p_vaddr := BaseAdr + phdr[dyn].p_offset; |
phdr[dyn].p_paddr := phdr[dyn].p_vaddr; |
hashtab := CHL.CreateIntList(); |
CHL.PushInt(hashtab, STRINGS.HashStr("")); |
NewSym(CHL.PushStr(strtab, ""), 0, 0, 0X, 0X, 0X); |
CHL.PushInt(hashtab, STRINGS.HashStr("dlopen")); |
NewSym(CHL.PushStr(strtab, "dlopen"), 0, 0, 12X, 0X, 0X); |
CHL.PushInt(hashtab, STRINGS.HashStr("dlsym")); |
NewSym(CHL.PushStr(strtab, "dlsym"), 0, 0, 12X, 0X, 0X); |
IF so THEN |
item := program.exp_list.first; |
WHILE item # NIL DO |
ASSERT(CHL.GetStr(program.export, item(BIN.EXPRT).nameoffs, Name)); |
CHL.PushInt(hashtab, STRINGS.HashStr(Name)); |
NewSym(CHL.PushStr(strtab, Name), item(BIN.EXPRT).label, 0, 12X, 0X, 0X); |
item := item.next |
END; |
ASSERT(CHL.GetStr(program.data, program.modname, Name)) |
END; |
symCount := LISTS.count(symtab); |
bucket := CHL.CreateIntList(); |
chain := CHL.CreateIntList(); |
FOR i := 1 TO symCount DO |
CHL.PushInt(bucket, 0); |
CHL.PushInt(chain, 0) |
END; |
MakeHash(bucket, chain, symCount); |
NewDyn(DT_NEEDED, CHL.PushStr(strtab, "libdl.so.2")); |
NewDyn(DT_STRTAB, 0); |
NewDyn(DT_STRSZ, CHL.Length(strtab)); |
NewDyn(DT_SYMTAB, 0); |
IF amd64 THEN |
NewDyn(DT_SYMENT, 24); |
NewDyn(DT_RELA, 0); |
NewDyn(DT_RELASZ, 48); |
NewDyn(DT_RELAENT, 24) |
ELSE |
NewDyn(DT_SYMENT, 16); |
NewDyn(DT_REL, 0); |
NewDyn(DT_RELSZ, 16); |
NewDyn(DT_RELENT, 8) |
END; |
NewDyn(DT_HASH, 0); |
IF so THEN |
NewDyn(DT_SONAME, CHL.PushStr(strtab, Name)); |
NewDyn(DT_INIT, 0); |
NewDyn(DT_FINI, 0) |
END; |
NewDyn(DT_NULL, 0); |
Offset.symtab := LISTS.count(dynamic) * (8 + 8 * ORD(amd64)); |
Offset.reltab := Offset.symtab + symCount * (16 + 8 * ORD(amd64)); |
Offset.hash := Offset.reltab + (8 + 16 * ORD(amd64)) * 2; |
Offset.strtab := Offset.hash + (symCount * 2 + 2) * 4; |
DynAdr := phdr[dyn].p_offset + BaseAdr; |
item := LISTS.getidx(dynamic, 1); item(Elf32_Dyn).d_val := Offset.strtab + DynAdr; |
item := LISTS.getidx(dynamic, 3); item(Elf32_Dyn).d_val := Offset.symtab + DynAdr; |
item := LISTS.getidx(dynamic, 5); item(Elf32_Dyn).d_val := Offset.reltab + DynAdr; |
item := LISTS.getidx(dynamic, 8); item(Elf32_Dyn).d_val := Offset.hash + DynAdr; |
phdr[dyn].p_filesz := Offset.strtab + CHL.Length(strtab) + 8 + 8 * ORD(amd64); |
phdr[dyn].p_memsz := phdr[dyn].p_filesz; |
phdr[dyn].p_flags := PF_R; |
phdr[dyn].p_align := 1; |
offset := 0; |
phdr[header].p_type := 1; |
phdr[header].p_offset := offset; |
phdr[header].p_vaddr := BaseAdr; |
phdr[header].p_paddr := BaseAdr; |
phdr[header].p_filesz := SizeOf.header + lenInterpreter + phdr[dyn].p_filesz; |
phdr[header].p_memsz := phdr[header].p_filesz; |
phdr[header].p_flags := PF_R + PF_W; |
phdr[header].p_align := 1000H; |
INC(offset, phdr[header].p_filesz); |
VA := BaseAdr + offset + 1000H; |
phdr[text].p_type := 1; |
phdr[text].p_offset := offset; |
phdr[text].p_vaddr := VA; |
phdr[text].p_paddr := VA; |
phdr[text].p_filesz := SizeOf.code; |
phdr[text].p_memsz := SizeOf.code; |
phdr[text].p_flags := PF_X + PF_R; |
phdr[text].p_align := 1000H; |
ehdr.e_entry := phdr[text].p_vaddr; |
INC(offset, phdr[text].p_filesz); |
VA := BaseAdr + offset + 2000H; |
pad := (16 - VA MOD 16) MOD 16; |
phdr[data].p_type := 1; |
phdr[data].p_offset := offset; |
phdr[data].p_vaddr := VA; |
phdr[data].p_paddr := VA; |
phdr[data].p_filesz := SizeOf.data + pad; |
phdr[data].p_memsz := SizeOf.data + pad; |
phdr[data].p_flags := PF_R + PF_W; |
phdr[data].p_align := 1000H; |
INC(offset, phdr[data].p_filesz); |
VA := BaseAdr + offset + 3000H; |
phdr[bss].p_type := 1; |
phdr[bss].p_offset := offset; |
phdr[bss].p_vaddr := VA; |
phdr[bss].p_paddr := VA; |
phdr[bss].p_filesz := 0; |
phdr[bss].p_memsz := SizeOf.bss + 16; |
phdr[bss].p_flags := PF_R + PF_W; |
phdr[bss].p_align := 1000H; |
Address.Code := ehdr.e_entry; |
Address.Data := phdr[data].p_vaddr + pad; |
Address.Bss := WR.align(phdr[bss].p_vaddr, 16); |
Address.Import := 0; |
PE32.fixup(program, Address, amd64); |
item := symtab.first; |
WHILE item # NIL DO |
IF item(Elf32_Sym).value # 0 THEN |
INC(item(Elf32_Sym).value, ehdr.e_entry) |
END; |
item := item.next |
END; |
IF so THEN |
item := LISTS.getidx(dynamic, 10); item(Elf32_Dyn).d_val := ehdr.e_entry; |
item := LISTS.getidx(dynamic, 11); item(Elf32_Dyn).d_val := BIN.GetLabel(program, fini) + ehdr.e_entry |
END; |
WR.Create(FileName); |
FOR i := 0 TO EI_NIDENT - 1 DO |
WR.WriteByte(ehdr.e_ident[i]) |
END; |
Write16(ehdr.e_type); |
Write16(ehdr.e_machine); |
WR.Write32LE(ehdr.e_version); |
IF amd64 THEN |
WR.Write64LE(ehdr.e_entry); |
WR.Write64LE(ehdr.e_phoff); |
WR.Write64LE(ehdr.e_shoff) |
ELSE |
WR.Write32LE(ehdr.e_entry); |
WR.Write32LE(ehdr.e_phoff); |
WR.Write32LE(ehdr.e_shoff) |
END; |
WR.Write32LE(ehdr.e_flags); |
Write16(ehdr.e_ehsize); |
Write16(ehdr.e_phentsize); |
Write16(ehdr.e_phnum); |
Write16(ehdr.e_shentsize); |
Write16(ehdr.e_shnum); |
Write16(ehdr.e_shstrndx); |
IF amd64 THEN |
WritePH64(phdr[interp]); |
WritePH64(phdr[dyn]); |
WritePH64(phdr[header]); |
WritePH64(phdr[text]); |
WritePH64(phdr[data]); |
WritePH64(phdr[bss]) |
ELSE |
WritePH(phdr[interp]); |
WritePH(phdr[dyn]); |
WritePH(phdr[header]); |
WritePH(phdr[text]); |
WritePH(phdr[data]); |
WritePH(phdr[bss]) |
END; |
FOR i := 0 TO lenInterpreter - 1 DO |
WR.WriteByte(ORD(Interpreter[i])) |
END; |
IF amd64 THEN |
item := dynamic.first; |
WHILE item # NIL DO |
WR.Write64LE(item(Elf32_Dyn).d_tag); |
WR.Write64LE(item(Elf32_Dyn).d_val); |
item := item.next |
END; |
item := symtab.first; |
WHILE item # NIL DO |
WR.Write32LE(item(Elf32_Sym).name); |
WR.WriteByte(ORD(item(Elf32_Sym).info)); |
WR.WriteByte(ORD(item(Elf32_Sym).other)); |
Write16(item(Elf32_Sym).shndx); |
WR.Write64LE(item(Elf32_Sym).value); |
WR.Write64LE(item(Elf32_Sym).size); |
item := item.next |
END; |
WR.Write64LE(phdr[dyn].p_filesz + DynAdr - 16); |
WR.Write32LE(1); |
WR.Write32LE(1); |
WR.Write64LE(0); |
WR.Write64LE(phdr[dyn].p_filesz + DynAdr - 8); |
WR.Write32LE(1); |
WR.Write32LE(2); |
WR.Write64LE(0) |
ELSE |
item := dynamic.first; |
WHILE item # NIL DO |
WR.Write32LE(item(Elf32_Dyn).d_tag); |
WR.Write32LE(item(Elf32_Dyn).d_val); |
item := item.next |
END; |
item := symtab.first; |
WHILE item # NIL DO |
WR.Write32LE(item(Elf32_Sym).name); |
WR.Write32LE(item(Elf32_Sym).value); |
WR.Write32LE(item(Elf32_Sym).size); |
WR.WriteByte(ORD(item(Elf32_Sym).info)); |
WR.WriteByte(ORD(item(Elf32_Sym).other)); |
Write16(item(Elf32_Sym).shndx); |
item := item.next |
END; |
WR.Write32LE(phdr[dyn].p_filesz + DynAdr - 8); |
WR.Write32LE(00000101H); |
WR.Write32LE(phdr[dyn].p_filesz + DynAdr - 4); |
WR.Write32LE(00000201H) |
END; |
WR.Write32LE(symCount); |
WR.Write32LE(symCount); |
FOR i := 0 TO symCount - 1 DO |
WR.Write32LE(CHL.GetInt(bucket, i)) |
END; |
FOR i := 0 TO symCount - 1 DO |
WR.Write32LE(CHL.GetInt(chain, i)) |
END; |
CHL.WriteToFile(strtab); |
IF amd64 THEN |
WR.Write64LE(0); |
WR.Write64LE(0) |
ELSE |
WR.Write32LE(0); |
WR.Write32LE(0) |
END; |
CHL.WriteToFile(program.code); |
WHILE pad > 0 DO |
WR.WriteByte(0); |
DEC(pad) |
END; |
CHL.WriteToFile(program.data); |
WR.Close; |
UTILS.chmod(FileName) |
END write; |
END ELF. |
/programs/develop/oberon07/source/ERRORS.ob07 |
---|
0,0 → 1,221 |
(* |
BSD 2-Clause License |
Copyright (c) 2018-2021, Anton Krotov |
All rights reserved. |
*) |
MODULE ERRORS; |
IMPORT C := CONSOLE, UTILS; |
PROCEDURE HintMsg* (name: ARRAY OF CHAR; line, col, hint: INTEGER); |
BEGIN |
IF hint = 0 THEN |
C.String(" hint ("); C.Int(line); C.String(":"); C.Int(col); C.String(") "); |
C.String("variable '"); C.String(name); C.StringLn("' never used") |
END |
END HintMsg; |
PROCEDURE WarningMsg* (line, col, warning: INTEGER); |
BEGIN |
C.String(" warning ("); C.Int(line); C.String(":"); C.Int(col); C.String(") "); |
CASE warning OF |
|0: C.StringLn("passing a string value as a fixed array") |
|1: C.StringLn("endless FOR loop") |
|2: C.StringLn("identifier too long") |
END |
END WarningMsg; |
PROCEDURE ErrorMsg* (fname: ARRAY OF CHAR; line, col, errno: INTEGER); |
VAR |
str: ARRAY 80 OF CHAR; |
BEGIN |
C.Ln; |
C.String(" error ("); C.Int(errno); C.String(") ("); C.Int(line); C.String(":"); C.Int(col); C.String(") "); |
CASE errno OF |
| 1: str := "missing 'H' or 'X'" |
| 2: str := "missing scale" |
| 3: str := "unclosed string" |
| 4: str := "illegal character" |
| 5: str := "string too long" |
| 7: str := "number too long" |
| 8..12: str := "number too large" |
| 13: str := "real numbers not supported" |
| 21: str := "'MODULE' expected" |
| 22: str := "identifier expected" |
| 23: str := "module name does not match file name" |
| 24: str := "';' expected" |
| 25: str := "identifier does not match module name" |
| 26: str := "'.' expected" |
| 27: str := "'END' expected" |
| 28: str := "',', ';' or ':=' expected" |
| 29: str := "module not found" |
| 30: str := "multiply defined identifier" |
| 31: str := "recursive import" |
| 32: str := "'=' expected" |
| 33: str := "')' expected" |
| 34: str := "syntax error in expression" |
| 35: str := "'}' expected" |
| 36: str := "incompatible operand" |
| 37: str := "incompatible operands" |
| 38: str := "'RETURN' expected" |
| 39: str := "integer overflow" |
| 40: str := "floating point overflow" |
| 41: str := "not enough floating point registers; simplify expression" |
| 42: str := "out of range 0..255" |
| 43: str := "expression is not an integer" |
| 44: str := "out of range 0..MAXSET" |
| 45: str := "division by zero" |
| 46: str := "IV out of range" |
| 47: str := "'OF' or ',' expected" |
| 48: str := "undeclared identifier" |
| 49: str := "type expected" |
| 50: str := "recursive type definition" |
| 51: str := "illegal value of constant" |
| 52: str := "not a record type" |
| 53: str := "':' expected" |
| 54: str := "need to import SYSTEM" |
| 55: str := "pointer type not defined" |
| 56: str := "out of range 0..MAXSET" |
| 57: str := "'TO' expected" |
| 58: str := "not a record type" |
| 59: str := "this expression cannot be a procedure" |
| 60: str := "identifier does not match procedure name" |
| 61: str := "illegally marked identifier" |
| 62: str := "expression should be constant" |
| 63: str := "not enough RAM" |
| 64: str := "'(' expected" |
| 65: str := "',' expected" |
| 66: str := "incompatible parameter" |
| 67: str := "'OF' expected" |
| 68: str := "type expected" |
| 69: str := "result type of procedure is not a basic type" |
| 70: str := "import not supported" |
| 71: str := "']' expected" |
| 72: str := "expression is not BOOLEAN" |
| 73: str := "not a record" |
| 74: str := "undefined record field" |
| 75: str := "not an array" |
| 76: str := "expression is not an integer" |
| 77: str := "not a pointer" |
| 78: str := "type guard not allowed" |
| 79: str := "not a type" |
| 80: str := "not a record type" |
| 81: str := "not a pointer type" |
| 82: str := "type guard not allowed" |
| 83: str := "index out of range" |
| 84: str := "dimension too large" |
| 85: str := "procedure must have level 0" |
| 86: str := "not a procedure" |
| 87: str := "incompatible expression (RETURN)" |
| 88: str := "'THEN' expected" |
| 89: str := "'DO' expected" |
| 90: str := "'UNTIL' expected" |
| 91: str := "incompatible assignment" |
| 92: str := "procedure call of a function" |
| 93: str := "not a variable" |
| 94: str := "read only variable" |
| 95: str := "invalid type of expression (CASE)" |
| 96: str := "':=' expected" |
| 97: str := "not INTEGER variable" |
| 98: str := "illegal value of constant (0)" |
| 99: str := "incompatible label" |
|100: str := "multiply defined label" |
|101: str := "too large parameter of WCHR" |
|102: str := "label expected" |
|103: str := "illegal value of constant" |
|104: str := "type too large" |
|105: str := "access to intermediate variables not allowed" |
|106: str := "qualified identifier expected" |
|107: str := "too large parameter of CHR" |
|108: str := "a variable or a procedure expected" |
|109: str := "expression should be constant" |
|110: str := "out of range 0..65535" |
|111: str := "record [noalign] cannot have a base type" |
|112: str := "record [noalign] cannot be a base type" |
|113: str := "result type of procedure should not be REAL" |
|114: str := "identifiers 'lib_init' and 'version' are reserved" |
|115: str := "recursive constant definition" |
|116: str := "procedure too deep nested" |
|117: str := "string expected" |
|118: str := "'$END', '$ELSE' or '$ELSIF' without '$IF'" |
|119: str := "'$IF', '$ELSIF', '$ELSE' or '$END' expected" |
|120: str := "too many formal parameters" |
|121: str := "multiply defined handler" |
|122: str := "bad divisor" |
|123: str := "illegal flag" |
|124: str := "unknown flag" |
|125: str := "flag not supported" |
END; |
C.StringLn(str); |
C.String(" file: "); C.StringLn(fname); |
UTILS.Exit(1) |
END ErrorMsg; |
PROCEDURE Error1 (s1: ARRAY OF CHAR); |
BEGIN |
C.Ln; |
C.StringLn(s1); |
UTILS.Exit(1) |
END Error1; |
PROCEDURE Error3 (s1, s2, s3: ARRAY OF CHAR); |
BEGIN |
C.Ln; |
C.String(s1); C.String(s2); C.StringLn(s3); |
UTILS.Exit(1) |
END Error3; |
PROCEDURE Error5 (s1, s2, s3, s4, s5: ARRAY OF CHAR); |
BEGIN |
C.Ln; |
C.String(s1); C.String(s2); C.String(s3); C.String(s4); C.StringLn(s5); |
UTILS.Exit(1) |
END Error5; |
PROCEDURE WrongRTL* (ProcName: ARRAY OF CHAR); |
BEGIN |
Error5("procedure ", UTILS.RTL_NAME, ".", ProcName, " not found") |
END WrongRTL; |
PROCEDURE BadParam* (param: ARRAY OF CHAR); |
BEGIN |
Error3("bad parameter: ", param, "") |
END BadParam; |
PROCEDURE FileNotFound* (Path, Name, Ext: ARRAY OF CHAR); |
BEGIN |
Error5("file ", Path, Name, Ext, " not found") |
END FileNotFound; |
PROCEDURE Error* (n: INTEGER); |
BEGIN |
CASE n OF |
|201: Error1("writing file error") |
|202: Error1("too many relocations") |
|203: Error1("size of program is too large") |
|204: Error1("size of variables is too large") |
|205: Error1("not enough parameters") |
|206: Error1("bad parameter <target>") |
|207: Error3('inputfile name extension must be "', UTILS.FILE_EXT, '"') |
|208: Error1("not enough RAM") |
END |
END Error; |
END ERRORS. |
/programs/develop/oberon07/source/FILES.ob07 |
---|
0,0 → 1,200 |
(* |
BSD 2-Clause License |
Copyright (c) 2018-2021, Anton Krotov |
All rights reserved. |
*) |
MODULE FILES; |
IMPORT UTILS, C := COLLECTIONS, CONSOLE; |
TYPE |
FILE* = POINTER TO RECORD (C.ITEM) |
ptr: INTEGER; |
buffer: ARRAY 64*1024 OF BYTE; |
count: INTEGER |
END; |
VAR |
files: C.COLLECTION; |
PROCEDURE copy (src: ARRAY OF BYTE; src_idx: INTEGER; VAR dst: ARRAY OF BYTE; dst_idx: INTEGER; bytes: INTEGER); |
BEGIN |
WHILE bytes > 0 DO |
dst[dst_idx] := src[src_idx]; |
INC(dst_idx); |
INC(src_idx); |
DEC(bytes) |
END |
END copy; |
PROCEDURE flush (file: FILE): INTEGER; |
VAR |
res: INTEGER; |
BEGIN |
IF file # NIL THEN |
res := UTILS.FileWrite(file.ptr, file.buffer, file.count); |
IF res < 0 THEN |
res := 0 |
END |
ELSE |
res := 0 |
END |
RETURN res |
END flush; |
PROCEDURE NewFile (): FILE; |
VAR |
file: FILE; |
citem: C.ITEM; |
BEGIN |
citem := C.pop(files); |
IF citem = NIL THEN |
NEW(file) |
ELSE |
file := citem(FILE) |
END |
RETURN file |
END NewFile; |
PROCEDURE create* (name: ARRAY OF CHAR): FILE; |
VAR |
file: FILE; |
ptr: INTEGER; |
BEGIN |
ptr := UTILS.FileCreate(name); |
IF ptr > 0 THEN |
file := NewFile(); |
file.ptr := ptr; |
file.count := 0 |
ELSE |
file := NIL |
END |
RETURN file |
END create; |
PROCEDURE open* (name: ARRAY OF CHAR): FILE; |
VAR |
file: FILE; |
ptr: INTEGER; |
BEGIN |
ptr := UTILS.FileOpen(name); |
IF ptr > 0 THEN |
file := NewFile(); |
file.ptr := ptr; |
file.count := -1 |
ELSE |
file := NIL |
END |
RETURN file |
END open; |
PROCEDURE close* (VAR file: FILE); |
VAR |
n: INTEGER; |
BEGIN |
IF file # NIL THEN |
IF file.count > 0 THEN |
n := flush(file) |
END; |
file.count := -1; |
UTILS.FileClose(file.ptr); |
file.ptr := 0; |
C.push(files, file); |
file := NIL |
END |
END close; |
PROCEDURE read* (file: FILE; VAR chunk: ARRAY OF CHAR; bytes: INTEGER): INTEGER; |
VAR |
res: INTEGER; |
BEGIN |
IF file # NIL THEN |
res := UTILS.FileRead(file.ptr, chunk, MAX(MIN(bytes, LEN(chunk)), 0)); |
IF res < 0 THEN |
res := 0 |
END |
ELSE |
res := 0 |
END |
RETURN res |
END read; |
PROCEDURE write* (file: FILE; chunk: ARRAY OF BYTE; bytes: INTEGER): INTEGER; |
VAR |
free, n, idx: INTEGER; |
BEGIN |
idx := 0; |
IF (file # NIL) & (file.count >= 0) THEN |
free := LEN(file.buffer) - file.count; |
WHILE bytes > 0 DO |
n := MIN(free, bytes); |
copy(chunk, idx, file.buffer, file.count, n); |
DEC(free, n); |
DEC(bytes, n); |
INC(idx, n); |
INC(file.count, n); |
IF free = 0 THEN |
IF flush(file) # LEN(file.buffer) THEN |
bytes := 0; |
DEC(idx, n) |
ELSE |
file.count := 0; |
free := LEN(file.buffer) |
END |
END |
END |
END |
RETURN idx |
END write; |
PROCEDURE WriteByte* (file: FILE; byte: BYTE): BOOLEAN; |
VAR |
arr: ARRAY 1 OF BYTE; |
BEGIN |
arr[0] := byte |
RETURN write(file, arr, 1) = 1 |
END WriteByte; |
BEGIN |
files := C.create() |
END FILES. |
/programs/develop/oberon07/source/IL.ob07 |
---|
0,0 → 1,1171 |
(* |
BSD 2-Clause License |
Copyright (c) 2018-2021, Anton Krotov |
All rights reserved. |
*) |
MODULE IL; |
IMPORT LISTS, SCAN, STRINGS, CHL := CHUNKLISTS, C := COLLECTIONS, TARGETS, PATHS; |
CONST |
call_stack* = 0; |
call_win64* = 1; |
call_sysv* = 2; |
begin_loop* = 1; end_loop* = 2; |
opJMP* = 0; opLABEL* = 1; opCOPYS* = 2; opGADR* = 3; opCONST* = 4; opLLOAD32* = 5; |
opCOPYA* = 6; opCASET* = 7; opMULC* = 8; opMUL* = 9; opDIV* = 10; opMOD* = 11; |
opDIVL* = 12; opMODL* = 13; opDIVR* = 14; opMODR* = 15; opUMINUS* = 16; |
opADD* = 17; opSUB* = 18; opONERR* = 19; opSUBL* = 20; opADDC* = 21; opSUBR* = 22; |
opSAVE* = 23; opSAVEC* = 24; opSAVE8* = 25; opSAVE8C* = 26; opCHKBYTE* = 27; opDROP* = 28; |
opNOT* = 29; |
opEQ* = 30; opNE* = opEQ + 1; opLT* = opEQ + 2; opLE* = opEQ + 3; opGT* = opEQ + 4; opGE* = opEQ + 5 (* 35 *); |
opEQC* = 36; opNEC* = opEQC + 1; opLTC* = opEQC + 2; opLEC* = opEQC + 3; opGTC* = opEQC + 4; opGEC* = opEQC + 5; (* 41 *) |
opEQF* = 42; opNEF* = opEQF + 1; opLTF* = opEQF + 2; opLEF* = opEQF + 3; opGTF* = opEQF + 4; opGEF* = opEQF + 5; (* 47 *) |
opEQS* = 48; opNES* = opEQS + 1; opLTS* = opEQS + 2; opLES* = opEQS + 3; opGTS* = opEQS + 4; opGES* = opEQS + 5; (* 53 *) |
opEQSW* = 54; opNESW* = opEQSW + 1; opLTSW* = opEQSW + 2; opLESW* = opEQSW + 3; opGTSW* = opEQSW + 4; opGESW* = opEQSW + 5 (* 59 *); |
opVLOAD32* = 60; opGLOAD32* = 61; |
opJZ* = 62; opJNZ* = 63; |
opSAVE32* = 64; opLLOAD8* = 65; |
opCONSTF* = 66; opLOADF* = 67; opSAVEF* = 68; opMULF* = 69; opDIVF* = 70; opDIVFI* = 71; |
opUMINF* = 72; opSAVEFI* = 73; opSUBFI* = 74; opADDF* = 75; opSUBF* = 76; |
opJNZ1* = 77; opJG* = 78; |
opINCCB* = 79; opDECCB* = 80; opINCB* = 81; opDECB* = 82; |
opCASEL* = 83; opCASER* = 84; opCASELR* = 85; |
opPOPSP* = 86; |
opWIN64CALL* = 87; opWIN64CALLI* = 88; opWIN64CALLP* = 89; opAND* = 90; opOR* = 91; |
opLOAD8* = 92; opLOAD16* = 93; opLOAD32* = 94; opPRECALL* = 95; opRES* = 96; opRESF* = 97; |
opPUSHC* = 98; opSWITCH* = 99; |
opSBOOL* = 100; opSBOOLC* = 101; opNOP* = 102; |
opMULS* = 103; opMULSC* = 104; opDIVS* = 105; opDIVSC* = 106; |
opADDS* = 107; opSUBS* = 108; opERR* = 109; opSUBSL* = 110; opADDSC* = 111; opSUBSR* = 112; |
opUMINS* = 113; opIN* = 114; opINL* = 115; opINR* = 116; |
opRSET* = 117; opRSETL* = 118; opRSETR* = 119; opRSET1* = 120; opLENGTH* = 121; |
opLEAVEC* = 122; opCODE* = 123; opALIGN16* = 124; |
opINCC* = 125; opINC* = 126; opDEC* = 127; |
opINCL* = 128; opEXCL* = 129; opINCLC* = 130; opEXCLC* = 131; opNEW* = 132; opDISP* = 133; |
opPACK* = 134; opPACKC* = 135; opUNPK* = 136; opCOPY* = 137; opENTER* = 138; opLEAVE* = 139; |
opCALL* = 140; opSAVEP* = 141; opCALLP* = 142; opEQP* = 143; opNEP* = 144; opLEAVER* = 145; |
opGET* = 146; opSAVE16* = 147; opABS* = 148; opFABS* = 149; opFLOOR* = 150; opFLT* = 151; |
opGETC* = 152; opORD* = 153; opASR* = 154; opLSL* = 155; opROR* = 156; |
opASR1* = 157; opLSL1* = 158; opROR1* = 159; opASR2* = 160; opLSL2* = 161; opROR2* = 162; |
opPUSHP* = 163; opLADR* = 164; opTYPEGP* = 165; opIS* = 166; opPUSHF* = 167; opVADR* = 168; |
opPUSHT* = 169; opTYPEGR* = 170; opISREC* = 171; opCHKIDX* = 172; opPARAM* = 173; |
opCHKIDX2* = 174; opLEN* = 175; opROT* = 176; opSAVES* = 177; opSADR* = 178; opLENGTHW* = 179; |
opCHR* = 180; opENDSW* = 181; opLEAVEF* = 182; opCLEANUP* = 183; opMOVE* = 184; |
opLSR* = 185; opLSR1* = 186; opLSR2* = 187; |
opMIN* = 188; opMINC* = 189; opMAX* = 190; opMAXC* = 191; opSYSVALIGN16* = 192; |
opEQB* = 193; opNEB* = 194; opINF* = 195; opWIN64ALIGN16* = 196; opVLOAD8* = 197; opGLOAD8* = 198; |
opLLOAD16* = 199; opVLOAD16* = 200; opGLOAD16* = 201; |
opLOAD64* = 202; opLLOAD64* = 203; opVLOAD64* = 204; opGLOAD64* = 205; opSAVE64* = 206; |
opTYPEGD* = 207; opCALLI* = 208; opPUSHIP* = 209; opSAVEIP* = 210; opEQIP* = 211; opNEIP* = 212; |
opSAVE16C* = 213; opWCHR* = 214; opHANDLER* = 215; |
opSYSVCALL* = 216; opSYSVCALLI* = 217; opSYSVCALLP* = 218; opFNAME* = 219; |
opSADR_PARAM* = -1; opLOAD64_PARAM* = -2; opLLOAD64_PARAM* = -3; opGLOAD64_PARAM* = -4; |
opVADR_PARAM* = -5; opCONST_PARAM* = -6; opGLOAD32_PARAM* = -7; opLLOAD32_PARAM* = -8; |
opLOAD32_PARAM* = -9; |
opLADR_SAVEC* = -10; opGADR_SAVEC* = -11; opLADR_SAVE* = -12; |
opLADR_INCC* = -13; opLADR_INCCB* = -14; opLADR_DECCB* = -15; |
opLADR_INC* = -16; opLADR_DEC* = -17; opLADR_INCB* = -18; opLADR_DECB* = -19; |
opLADR_INCL* = -20; opLADR_EXCL* = -21; opLADR_INCLC* = -22; opLADR_EXCLC* = -23; |
opLADR_UNPK* = -24; |
_init *= 0; |
_move *= 1; |
_strcmpw *= 2; |
_exit *= 3; |
_set *= 4; |
_set1 *= 5; |
_lengthw *= 6; |
_strcpy *= 7; |
_length *= 8; |
_divmod *= 9; |
_dllentry *= 10; |
_sofinit *= 11; |
_arrcpy *= 12; |
_rot *= 13; |
_new *= 14; |
_dispose *= 15; |
_strcmp *= 16; |
_error *= 17; |
_is *= 18; |
_isrec *= 19; |
_guard *= 20; |
_guardrec *= 21; |
_fmul *= 22; |
_fdiv *= 23; |
_fdivi *= 24; |
_fadd *= 25; |
_fsub *= 26; |
_fsubi *= 27; |
_fcmp *= 28; |
_floor *= 29; |
_flt *= 30; |
_pack *= 31; |
_unpk *= 32; |
TYPE |
COMMAND* = POINTER TO RECORD (LISTS.ITEM) |
opcode*: INTEGER; |
param1*: INTEGER; |
param2*: INTEGER; |
param3*: INTEGER; |
float*: REAL |
END; |
FNAMECMD* = POINTER TO RECORD (COMMAND) |
fname*: PATHS.PATH |
END; |
CMDSTACK = POINTER TO RECORD |
data: ARRAY 1000 OF COMMAND; |
top: INTEGER |
END; |
EXPORT_PROC* = POINTER TO RECORD (LISTS.ITEM) |
label*: INTEGER; |
name*: SCAN.IDSTR |
END; |
IMPORT_LIB* = POINTER TO RECORD (LISTS.ITEM) |
name*: SCAN.TEXTSTR; |
procs*: LISTS.LIST |
END; |
IMPORT_PROC* = POINTER TO RECORD (LISTS.ITEM) |
label*: INTEGER; |
lib*: IMPORT_LIB; |
name*: SCAN.TEXTSTR; |
count: INTEGER |
END; |
CODES = RECORD |
last: COMMAND; |
begcall: CMDSTACK; |
endcall: CMDSTACK; |
commands*: LISTS.LIST; |
export*: LISTS.LIST; |
_import*: LISTS.LIST; |
types*: CHL.INTLIST; |
data*: CHL.BYTELIST; |
dmin*: INTEGER; |
lcount*: INTEGER; |
bss*: INTEGER; |
rtl*: ARRAY 33 OF INTEGER; |
errlabels*: ARRAY 12 OF INTEGER; |
charoffs: ARRAY 256 OF INTEGER; |
wcharoffs: ARRAY 65536 OF INTEGER; |
wstr: ARRAY 4*1024 OF WCHAR |
END; |
VAR |
codes*: CODES; |
CPU: INTEGER; |
commands: C.COLLECTION; |
PROCEDURE set_dmin* (value: INTEGER); |
BEGIN |
codes.dmin := value |
END set_dmin; |
PROCEDURE set_bss* (value: INTEGER); |
BEGIN |
codes.bss := value |
END set_bss; |
PROCEDURE set_rtl* (idx, label: INTEGER); |
BEGIN |
codes.rtl[idx] := label |
END set_rtl; |
PROCEDURE NewCmd (): COMMAND; |
VAR |
cmd: COMMAND; |
citem: C.ITEM; |
BEGIN |
citem := C.pop(commands); |
IF citem = NIL THEN |
NEW(cmd) |
ELSE |
cmd := citem(COMMAND) |
END |
RETURN cmd |
END NewCmd; |
PROCEDURE setlast* (cmd: COMMAND); |
BEGIN |
codes.last := cmd |
END setlast; |
PROCEDURE getlast* (): COMMAND; |
RETURN codes.last |
END getlast; |
PROCEDURE PutByte (b: BYTE); |
BEGIN |
CHL.PushByte(codes.data, b) |
END PutByte; |
PROCEDURE putstr* (s: ARRAY OF CHAR): INTEGER; |
VAR |
i, n, res: INTEGER; |
BEGIN |
res := CHL.Length(codes.data); |
i := 0; |
n := LENGTH(s); |
WHILE i < n DO |
PutByte(ORD(s[i])); |
INC(i) |
END; |
PutByte(0) |
RETURN res |
END putstr; |
PROCEDURE putstr1* (c: INTEGER): INTEGER; |
VAR |
res: INTEGER; |
BEGIN |
IF codes.charoffs[c] = -1 THEN |
res := CHL.Length(codes.data); |
PutByte(c); |
PutByte(0); |
codes.charoffs[c] := res |
ELSE |
res := codes.charoffs[c] |
END |
RETURN res |
END putstr1; |
PROCEDURE putstrW* (s: ARRAY OF CHAR): INTEGER; |
VAR |
i, n, res: INTEGER; |
BEGIN |
res := CHL.Length(codes.data); |
IF ODD(res) THEN |
PutByte(0); |
INC(res) |
END; |
n := STRINGS.Utf8To16(s, codes.wstr); |
i := 0; |
WHILE i < n DO |
IF TARGETS.LittleEndian THEN |
PutByte(ORD(codes.wstr[i]) MOD 256); |
PutByte(ORD(codes.wstr[i]) DIV 256) |
ELSE |
PutByte(ORD(codes.wstr[i]) DIV 256); |
PutByte(ORD(codes.wstr[i]) MOD 256) |
END; |
INC(i) |
END; |
PutByte(0); |
PutByte(0) |
RETURN res |
END putstrW; |
PROCEDURE putstrW1* (c: INTEGER): INTEGER; |
VAR |
res: INTEGER; |
BEGIN |
IF codes.wcharoffs[c] = -1 THEN |
res := CHL.Length(codes.data); |
IF ODD(res) THEN |
PutByte(0); |
INC(res) |
END; |
IF TARGETS.LittleEndian THEN |
PutByte(c MOD 256); |
PutByte(c DIV 256) |
ELSE |
PutByte(c DIV 256); |
PutByte(c MOD 256) |
END; |
PutByte(0); |
PutByte(0); |
codes.wcharoffs[c] := res |
ELSE |
res := codes.wcharoffs[c] |
END |
RETURN res |
END putstrW1; |
PROCEDURE push (stk: CMDSTACK; cmd: COMMAND); |
BEGIN |
INC(stk.top); |
stk.data[stk.top] := cmd |
END push; |
PROCEDURE pop (stk: CMDSTACK): COMMAND; |
VAR |
res: COMMAND; |
BEGIN |
res := stk.data[stk.top]; |
DEC(stk.top) |
RETURN res |
END pop; |
PROCEDURE pushBegEnd* (VAR beg, _end: COMMAND); |
BEGIN |
push(codes.begcall, beg); |
push(codes.endcall, _end); |
beg := codes.last; |
_end := beg.next(COMMAND) |
END pushBegEnd; |
PROCEDURE popBegEnd* (VAR beg, _end: COMMAND); |
BEGIN |
beg := pop(codes.begcall); |
_end := pop(codes.endcall) |
END popBegEnd; |
PROCEDURE AddRec* (base: INTEGER); |
BEGIN |
CHL.PushInt(codes.types, base) |
END AddRec; |
PROCEDURE insert (cur, nov: COMMAND); |
VAR |
old_opcode, param2: INTEGER; |
PROCEDURE set (cur: COMMAND; opcode, param2: INTEGER); |
BEGIN |
cur.opcode := opcode; |
cur.param1 := cur.param2; |
cur.param2 := param2 |
END set; |
BEGIN |
IF CPU IN {TARGETS.cpuX86, TARGETS.cpuAMD64, TARGETS.cpuMSP430} THEN |
old_opcode := cur.opcode; |
param2 := nov.param2; |
IF (nov.opcode = opPARAM) & (param2 = 1) THEN |
CASE old_opcode OF |
|opGLOAD64: cur.opcode := opGLOAD64_PARAM |
|opLLOAD64: cur.opcode := opLLOAD64_PARAM |
|opLOAD64: cur.opcode := opLOAD64_PARAM |
|opGLOAD32: cur.opcode := opGLOAD32_PARAM |
|opLLOAD32: cur.opcode := opLLOAD32_PARAM |
|opLOAD32: cur.opcode := opLOAD32_PARAM |
|opSADR: cur.opcode := opSADR_PARAM |
|opVADR: cur.opcode := opVADR_PARAM |
|opCONST: cur.opcode := opCONST_PARAM |
ELSE |
old_opcode := -1 |
END |
ELSIF old_opcode = opLADR THEN |
CASE nov.opcode OF |
|opSAVEC: set(cur, opLADR_SAVEC, param2) |
|opSAVE: cur.opcode := opLADR_SAVE |
|opINC: cur.opcode := opLADR_INC |
|opDEC: cur.opcode := opLADR_DEC |
|opINCB: cur.opcode := opLADR_INCB |
|opDECB: cur.opcode := opLADR_DECB |
|opINCL: cur.opcode := opLADR_INCL |
|opEXCL: cur.opcode := opLADR_EXCL |
|opUNPK: cur.opcode := opLADR_UNPK |
|opINCC: set(cur, opLADR_INCC, param2) |
|opINCCB: set(cur, opLADR_INCCB, param2) |
|opDECCB: set(cur, opLADR_DECCB, param2) |
|opINCLC: set(cur, opLADR_INCLC, param2) |
|opEXCLC: set(cur, opLADR_EXCLC, param2) |
ELSE |
old_opcode := -1 |
END |
ELSIF (nov.opcode = opSAVEC) & (old_opcode = opGADR) THEN |
set(cur, opGADR_SAVEC, param2) |
ELSIF (nov.opcode = opMULC) & (old_opcode = opMULC) THEN |
cur.param2 := cur.param2 * param2 |
ELSIF (nov.opcode = opADDC) & (old_opcode = opADDC) THEN |
INC(cur.param2, param2) |
ELSE |
old_opcode := -1 |
END |
ELSIF CPU IN {TARGETS.cpuTHUMB, TARGETS.cpuRVM32I, TARGETS.cpuRVM64I} THEN |
old_opcode := cur.opcode; |
param2 := nov.param2; |
IF (old_opcode = opLADR) & (nov.opcode = opSAVE) THEN |
cur.opcode := opLADR_SAVE |
ELSIF (old_opcode = opLADR) & (nov.opcode = opINCC) THEN |
set(cur, opLADR_INCC, param2) |
ELSIF (nov.opcode = opMULC) & (old_opcode = opMULC) THEN |
cur.param2 := cur.param2 * param2 |
ELSIF (nov.opcode = opADDC) & (old_opcode = opADDC) THEN |
INC(cur.param2, param2) |
ELSE |
old_opcode := -1 |
END |
ELSE |
old_opcode := -1 |
END; |
IF old_opcode = -1 THEN |
LISTS.insert(codes.commands, cur, nov); |
codes.last := nov |
ELSE |
C.push(commands, nov); |
codes.last := cur |
END |
END insert; |
PROCEDURE AddCmd* (opcode: INTEGER; param: INTEGER); |
VAR |
cmd: COMMAND; |
BEGIN |
cmd := NewCmd(); |
cmd.opcode := opcode; |
cmd.param1 := 0; |
cmd.param2 := param; |
insert(codes.last, cmd) |
END AddCmd; |
PROCEDURE AddCmd2* (opcode: INTEGER; param1, param2: INTEGER); |
VAR |
cmd: COMMAND; |
BEGIN |
cmd := NewCmd(); |
cmd.opcode := opcode; |
cmd.param1 := param1; |
cmd.param2 := param2; |
insert(codes.last, cmd) |
END AddCmd2; |
PROCEDURE Const* (val: INTEGER); |
BEGIN |
AddCmd(opCONST, val) |
END Const; |
PROCEDURE StrAdr* (adr: INTEGER); |
BEGIN |
AddCmd(opSADR, adr) |
END StrAdr; |
PROCEDURE Param1*; |
BEGIN |
AddCmd(opPARAM, 1) |
END Param1; |
PROCEDURE NewLabel* (): INTEGER; |
BEGIN |
INC(codes.lcount) |
RETURN codes.lcount - 1 |
END NewLabel; |
PROCEDURE SetLabel* (label: INTEGER); |
BEGIN |
AddCmd2(opLABEL, label, 0) |
END SetLabel; |
PROCEDURE SetErrLabel* (errno: INTEGER); |
BEGIN |
codes.errlabels[errno] := NewLabel(); |
SetLabel(codes.errlabels[errno]) |
END SetErrLabel; |
PROCEDURE AddCmd0* (opcode: INTEGER); |
BEGIN |
AddCmd(opcode, 0) |
END AddCmd0; |
PROCEDURE delete (cmd: COMMAND); |
BEGIN |
LISTS.delete(codes.commands, cmd); |
C.push(commands, cmd) |
END delete; |
PROCEDURE delete2* (first, last: LISTS.ITEM); |
VAR |
cur, next: LISTS.ITEM; |
BEGIN |
cur := first; |
IF first # last THEN |
REPEAT |
next := cur.next; |
LISTS.delete(codes.commands, cur); |
C.push(commands, cur); |
cur := next |
UNTIL cur = last |
END; |
LISTS.delete(codes.commands, cur); |
C.push(commands, cur) |
END delete2; |
PROCEDURE Jmp* (opcode: INTEGER; label: INTEGER); |
VAR |
prev: COMMAND; |
not: BOOLEAN; |
BEGIN |
prev := codes.last; |
not := prev.opcode = opNOT; |
IF not THEN |
IF opcode = opJNZ THEN |
opcode := opJZ |
ELSIF opcode = opJZ THEN |
opcode := opJNZ |
ELSE |
not := FALSE |
END |
END; |
AddCmd2(opcode, label, label); |
IF not THEN |
delete(prev) |
END |
END Jmp; |
PROCEDURE AndOrOpt* (VAR label: INTEGER); |
VAR |
cur, prev: COMMAND; |
i, op, l: INTEGER; |
jz, not: BOOLEAN; |
BEGIN |
cur := codes.last; |
not := cur.opcode = opNOT; |
IF not THEN |
cur := cur.prev(COMMAND) |
END; |
IF cur.opcode = opAND THEN |
op := opAND |
ELSIF cur.opcode = opOR THEN |
op := opOR |
ELSE |
op := -1 |
END; |
cur := codes.last; |
IF op # -1 THEN |
IF not THEN |
IF op = opAND THEN |
op := opOR |
ELSE (* op = opOR *) |
op := opAND |
END; |
prev := cur.prev(COMMAND); |
delete(cur); |
cur := prev |
END; |
FOR i := 1 TO 9 DO |
IF i = 8 THEN |
l := cur.param1 |
ELSIF i = 9 THEN |
jz := cur.opcode = opJZ |
END; |
prev := cur.prev(COMMAND); |
delete(cur); |
cur := prev |
END; |
setlast(cur); |
IF op = opAND THEN |
label := l; |
jz := ~jz |
END; |
IF jz THEN |
Jmp(opJZ, label) |
ELSE |
Jmp(opJNZ, label) |
END; |
IF op = opOR THEN |
SetLabel(l) |
END |
ELSE |
Jmp(opJZ, label) |
END; |
setlast(codes.last) |
END AndOrOpt; |
PROCEDURE OnError* (line, error: INTEGER); |
BEGIN |
AddCmd2(opONERR, codes.errlabels[error], line) |
END OnError; |
PROCEDURE TypeGuard* (op, t: INTEGER; line, error: INTEGER); |
VAR |
label: INTEGER; |
BEGIN |
AddCmd(op, t); |
label := NewLabel(); |
Jmp(opJNZ, label); |
OnError(line, error); |
SetLabel(label) |
END TypeGuard; |
PROCEDURE TypeCheck* (t: INTEGER); |
BEGIN |
AddCmd(opIS, t) |
END TypeCheck; |
PROCEDURE TypeCheckRec* (t: INTEGER); |
BEGIN |
AddCmd(opISREC, t) |
END TypeCheckRec; |
PROCEDURE New* (size, typenum: INTEGER); |
BEGIN |
AddCmd2(opNEW, typenum, size) |
END New; |
PROCEDURE not*; |
VAR |
prev: COMMAND; |
BEGIN |
prev := codes.last; |
IF prev.opcode = opNOT THEN |
codes.last := prev.prev(COMMAND); |
delete(prev) |
ELSE |
AddCmd0(opNOT) |
END |
END not; |
PROCEDURE _ord*; |
BEGIN |
IF (codes.last.opcode # opAND) & (codes.last.opcode # opOR) THEN |
AddCmd0(opORD) |
END |
END _ord; |
PROCEDURE Enter* (label, params: INTEGER): COMMAND; |
VAR |
cmd: COMMAND; |
BEGIN |
cmd := NewCmd(); |
cmd.opcode := opENTER; |
cmd.param1 := label; |
cmd.param3 := params; |
insert(codes.last, cmd) |
RETURN codes.last |
END Enter; |
PROCEDURE Leave* (result, float: BOOLEAN; locsize, paramsize: INTEGER): COMMAND; |
BEGIN |
IF result THEN |
IF float THEN |
AddCmd2(opLEAVEF, locsize, paramsize) |
ELSE |
AddCmd2(opLEAVER, locsize, paramsize) |
END |
ELSE |
AddCmd2(opLEAVE, locsize, paramsize) |
END |
RETURN codes.last |
END Leave; |
PROCEDURE EnterC* (label: INTEGER): COMMAND; |
BEGIN |
SetLabel(label) |
RETURN codes.last |
END EnterC; |
PROCEDURE LeaveC* (): COMMAND; |
BEGIN |
AddCmd0(opLEAVEC) |
RETURN codes.last |
END LeaveC; |
PROCEDURE Call* (proc, callconv, fparams: INTEGER); |
BEGIN |
CASE callconv OF |
|call_stack: Jmp(opCALL, proc) |
|call_win64: Jmp(opWIN64CALL, proc) |
|call_sysv: Jmp(opSYSVCALL, proc) |
END; |
codes.last(COMMAND).param2 := fparams |
END Call; |
PROCEDURE CallImp* (proc: LISTS.ITEM; callconv, fparams: INTEGER); |
BEGIN |
CASE callconv OF |
|call_stack: Jmp(opCALLI, proc(IMPORT_PROC).label) |
|call_win64: Jmp(opWIN64CALLI, proc(IMPORT_PROC).label) |
|call_sysv: Jmp(opSYSVCALLI, proc(IMPORT_PROC).label) |
END; |
codes.last(COMMAND).param2 := fparams |
END CallImp; |
PROCEDURE CallP* (callconv, fparams: INTEGER); |
BEGIN |
CASE callconv OF |
|call_stack: AddCmd0(opCALLP) |
|call_win64: AddCmd(opWIN64CALLP, fparams) |
|call_sysv: AddCmd(opSYSVCALLP, fparams) |
END |
END CallP; |
PROCEDURE AssignProc* (proc: INTEGER); |
BEGIN |
Jmp(opSAVEP, proc) |
END AssignProc; |
PROCEDURE AssignImpProc* (proc: LISTS.ITEM); |
BEGIN |
Jmp(opSAVEIP, proc(IMPORT_PROC).label) |
END AssignImpProc; |
PROCEDURE PushProc* (proc: INTEGER); |
BEGIN |
Jmp(opPUSHP, proc) |
END PushProc; |
PROCEDURE PushImpProc* (proc: LISTS.ITEM); |
BEGIN |
Jmp(opPUSHIP, proc(IMPORT_PROC).label) |
END PushImpProc; |
PROCEDURE ProcCmp* (proc: INTEGER; eq: BOOLEAN); |
BEGIN |
IF eq THEN |
Jmp(opEQP, proc) |
ELSE |
Jmp(opNEP, proc) |
END |
END ProcCmp; |
PROCEDURE ProcImpCmp* (proc: LISTS.ITEM; eq: BOOLEAN); |
BEGIN |
IF eq THEN |
Jmp(opEQIP, proc(IMPORT_PROC).label) |
ELSE |
Jmp(opNEIP, proc(IMPORT_PROC).label) |
END |
END ProcImpCmp; |
PROCEDURE load* (size: INTEGER); |
VAR |
last: COMMAND; |
BEGIN |
last := codes.last; |
CASE size OF |
|1: |
IF last.opcode = opLADR THEN |
last.opcode := opLLOAD8 |
ELSIF last.opcode = opVADR THEN |
last.opcode := opVLOAD8 |
ELSIF last.opcode = opGADR THEN |
last.opcode := opGLOAD8 |
ELSE |
AddCmd0(opLOAD8) |
END |
|2: |
IF last.opcode = opLADR THEN |
last.opcode := opLLOAD16 |
ELSIF last.opcode = opVADR THEN |
last.opcode := opVLOAD16 |
ELSIF last.opcode = opGADR THEN |
last.opcode := opGLOAD16 |
ELSE |
AddCmd0(opLOAD16) |
END |
|4: |
IF last.opcode = opLADR THEN |
last.opcode := opLLOAD32 |
ELSIF last.opcode = opVADR THEN |
last.opcode := opVLOAD32 |
ELSIF last.opcode = opGADR THEN |
last.opcode := opGLOAD32 |
ELSE |
AddCmd0(opLOAD32) |
END |
|8: |
IF last.opcode = opLADR THEN |
last.opcode := opLLOAD64 |
ELSIF last.opcode = opVADR THEN |
last.opcode := opVLOAD64 |
ELSIF last.opcode = opGADR THEN |
last.opcode := opGLOAD64 |
ELSE |
AddCmd0(opLOAD64) |
END |
END |
END load; |
PROCEDURE SysPut* (size: INTEGER); |
BEGIN |
CASE size OF |
|1: AddCmd0(opSAVE8) |
|2: AddCmd0(opSAVE16) |
|4: AddCmd0(opSAVE32) |
|8: AddCmd0(opSAVE64) |
END |
END SysPut; |
PROCEDURE savef* (inv: BOOLEAN); |
BEGIN |
IF inv THEN |
AddCmd0(opSAVEFI) |
ELSE |
AddCmd0(opSAVEF) |
END |
END savef; |
PROCEDURE saves* (offset, length: INTEGER); |
BEGIN |
AddCmd2(opSAVES, length, offset) |
END saves; |
PROCEDURE abs* (real: BOOLEAN); |
BEGIN |
IF real THEN |
AddCmd0(opFABS) |
ELSE |
AddCmd0(opABS) |
END |
END abs; |
PROCEDURE shift_minmax* (op: CHAR); |
BEGIN |
CASE op OF |
|"A": AddCmd0(opASR) |
|"L": AddCmd0(opLSL) |
|"O": AddCmd0(opROR) |
|"R": AddCmd0(opLSR) |
|"m": AddCmd0(opMIN) |
|"x": AddCmd0(opMAX) |
END |
END shift_minmax; |
PROCEDURE shift_minmax1* (op: CHAR; x: INTEGER); |
BEGIN |
CASE op OF |
|"A": AddCmd(opASR1, x) |
|"L": AddCmd(opLSL1, x) |
|"O": AddCmd(opROR1, x) |
|"R": AddCmd(opLSR1, x) |
|"m": AddCmd(opMINC, x) |
|"x": AddCmd(opMAXC, x) |
END |
END shift_minmax1; |
PROCEDURE shift_minmax2* (op: CHAR; x: INTEGER); |
BEGIN |
CASE op OF |
|"A": AddCmd(opASR2, x) |
|"L": AddCmd(opLSL2, x) |
|"O": AddCmd(opROR2, x) |
|"R": AddCmd(opLSR2, x) |
|"m": AddCmd(opMINC, x) |
|"x": AddCmd(opMAXC, x) |
END |
END shift_minmax2; |
PROCEDURE len* (dim: INTEGER); |
BEGIN |
AddCmd(opLEN, dim) |
END len; |
PROCEDURE Float* (r: REAL; line, col: INTEGER); |
VAR |
cmd: COMMAND; |
BEGIN |
cmd := NewCmd(); |
cmd.opcode := opCONSTF; |
cmd.float := r; |
cmd.param1 := line; |
cmd.param2 := col; |
insert(codes.last, cmd) |
END Float; |
PROCEDURE drop*; |
BEGIN |
AddCmd0(opDROP) |
END drop; |
PROCEDURE _case* (a, b, L, R: INTEGER); |
VAR |
cmd: COMMAND; |
BEGIN |
IF a = b THEN |
cmd := NewCmd(); |
cmd.opcode := opCASELR; |
cmd.param1 := a; |
cmd.param2 := L; |
cmd.param3 := R; |
insert(codes.last, cmd) |
ELSE |
AddCmd2(opCASEL, a, L); |
AddCmd2(opCASER, b, R) |
END |
END _case; |
PROCEDURE fname* (name: PATHS.PATH); |
VAR |
cmd: FNAMECMD; |
BEGIN |
NEW(cmd); |
cmd.opcode := opFNAME; |
cmd.fname := name; |
insert(codes.last, cmd) |
END fname; |
PROCEDURE AddExp* (label: INTEGER; name: SCAN.IDSTR); |
VAR |
exp: EXPORT_PROC; |
BEGIN |
NEW(exp); |
exp.label := label; |
exp.name := name; |
LISTS.push(codes.export, exp) |
END AddExp; |
PROCEDURE AddImp* (dll, proc: SCAN.TEXTSTR): IMPORT_PROC; |
VAR |
lib: IMPORT_LIB; |
p: IMPORT_PROC; |
BEGIN |
lib := codes._import.first(IMPORT_LIB); |
WHILE (lib # NIL) & (lib.name # dll) DO |
lib := lib.next(IMPORT_LIB) |
END; |
IF lib = NIL THEN |
NEW(lib); |
lib.name := dll; |
lib.procs := LISTS.create(NIL); |
LISTS.push(codes._import, lib) |
END; |
p := lib.procs.first(IMPORT_PROC); |
WHILE (p # NIL) & (p.name # proc) DO |
p := p.next(IMPORT_PROC) |
END; |
IF p = NIL THEN |
NEW(p); |
p.name := proc; |
p.label := NewLabel(); |
p.lib := lib; |
p.count := 1; |
LISTS.push(lib.procs, p) |
ELSE |
INC(p.count) |
END |
RETURN p |
END AddImp; |
PROCEDURE DelImport* (imp: LISTS.ITEM); |
VAR |
lib: IMPORT_LIB; |
BEGIN |
DEC(imp(IMPORT_PROC).count); |
IF imp(IMPORT_PROC).count = 0 THEN |
lib := imp(IMPORT_PROC).lib; |
LISTS.delete(lib.procs, imp); |
IF lib.procs.first = NIL THEN |
LISTS.delete(codes._import, lib) |
END |
END |
END DelImport; |
PROCEDURE init* (pCPU: INTEGER); |
VAR |
cmd: COMMAND; |
i: INTEGER; |
BEGIN |
commands := C.create(); |
CPU := pCPU; |
NEW(codes.begcall); |
codes.begcall.top := -1; |
NEW(codes.endcall); |
codes.endcall.top := -1; |
codes.commands := LISTS.create(NIL); |
codes.export := LISTS.create(NIL); |
codes._import := LISTS.create(NIL); |
codes.types := CHL.CreateIntList(); |
codes.data := CHL.CreateByteList(); |
NEW(cmd); cmd.opcode := opNOP; LISTS.push(codes.commands, cmd); |
codes.last := cmd; |
NEW(cmd); cmd.opcode := opNOP; LISTS.push(codes.commands, cmd); |
AddRec(0); |
codes.lcount := 0; |
FOR i := 0 TO LEN(codes.charoffs) - 1 DO |
codes.charoffs[i] := -1 |
END; |
FOR i := 0 TO LEN(codes.wcharoffs) - 1 DO |
codes.wcharoffs[i] := -1 |
END |
END init; |
END IL. |
/programs/develop/oberon07/source/LISTS.ob07 |
---|
0,0 → 1,199 |
(* |
BSD 2-Clause License |
Copyright (c) 2018-2021, Anton Krotov |
All rights reserved. |
*) |
MODULE LISTS; |
IMPORT C := COLLECTIONS; |
TYPE |
ITEM* = POINTER TO RECORD (C.ITEM) |
prev*, next*: ITEM |
END; |
LIST* = POINTER TO RECORD |
first*, last*: ITEM |
END; |
PROCEDURE push* (list: LIST; item: ITEM); |
BEGIN |
ASSERT(list # NIL); |
ASSERT(item # NIL); |
IF list.first = NIL THEN |
list.first := item; |
item.prev := NIL |
ELSE |
ASSERT(list.last # NIL); |
item.prev := list.last; |
list.last.next := item |
END; |
list.last := item; |
item.next := NIL |
END push; |
PROCEDURE pop* (list: LIST): ITEM; |
VAR |
last: ITEM; |
BEGIN |
ASSERT(list # NIL); |
last := list.last; |
IF last # NIL THEN |
IF last = list.first THEN |
list.first := NIL; |
list.last := NIL |
ELSE |
list.last := last.prev; |
list.last.next := NIL |
END; |
last.next := NIL; |
last.prev := NIL |
END |
RETURN last |
END pop; |
PROCEDURE insert* (list: LIST; cur, nov: ITEM); |
VAR |
next: ITEM; |
BEGIN |
ASSERT(list # NIL); |
ASSERT(nov # NIL); |
ASSERT(cur # NIL); |
next := cur.next; |
IF next # NIL THEN |
next.prev := nov; |
nov.next := next; |
cur.next := nov; |
nov.prev := cur |
ELSE |
push(list, nov) |
END |
END insert; |
PROCEDURE insertL* (list: LIST; cur, nov: ITEM); |
VAR |
prev: ITEM; |
BEGIN |
ASSERT(list # NIL); |
ASSERT(nov # NIL); |
ASSERT(cur # NIL); |
prev := cur.prev; |
IF prev # NIL THEN |
prev.next := nov; |
nov.prev := prev |
ELSE |
nov.prev := NIL; |
list.first := nov |
END; |
cur.prev := nov; |
nov.next := cur |
END insertL; |
PROCEDURE delete* (list: LIST; item: ITEM); |
VAR |
prev, next: ITEM; |
BEGIN |
ASSERT(list # NIL); |
ASSERT(item # NIL); |
prev := item.prev; |
next := item.next; |
IF next # NIL THEN |
IF prev # NIL THEN |
prev.next := next; |
next.prev := prev |
ELSE |
next.prev := NIL; |
list.first := next |
END |
ELSE |
IF prev # NIL THEN |
prev.next := NIL; |
list.last := prev |
ELSE |
list.first := NIL; |
list.last := NIL |
END |
END |
END delete; |
PROCEDURE count* (list: LIST): INTEGER; |
VAR |
item: ITEM; |
res: INTEGER; |
BEGIN |
ASSERT(list # NIL); |
res := 0; |
item := list.first; |
WHILE item # NIL DO |
INC(res); |
item := item.next |
END |
RETURN res |
END count; |
PROCEDURE getidx* (list: LIST; idx: INTEGER): ITEM; |
VAR |
item: ITEM; |
BEGIN |
ASSERT(list # NIL); |
ASSERT(idx >= 0); |
item := list.first; |
WHILE (item # NIL) & (idx > 0) DO |
item := item.next; |
DEC(idx) |
END |
RETURN item |
END getidx; |
PROCEDURE create* (list: LIST): LIST; |
BEGIN |
IF list = NIL THEN |
NEW(list) |
END; |
list.first := NIL; |
list.last := NIL |
RETURN list |
END create; |
END LISTS. |
/programs/develop/oberon07/source/MSP430.ob07 |
---|
0,0 → 1,1780 |
(* |
BSD 2-Clause License |
Copyright (c) 2019-2021, Anton Krotov |
All rights reserved. |
*) |
MODULE MSP430; |
IMPORT IL, LISTS, REG, CHL := CHUNKLISTS, ERRORS, WR := WRITER, HEX, |
UTILS, C := CONSOLE, PROG, RTL := MSP430RTL; |
CONST |
chkSTK* = 6; |
minRAM* = 128; maxRAM* = 2048; |
minROM* = 2048; maxROM* = 24576; |
StkReserve = RTL.StkReserve; |
IntVectorSize* = RTL.IntVectorSize; |
PC = 0; SP = 1; SR = 2; CG = 3; |
R4 = 4; R5 = 5; R6 = 6; R7 = 7; |
HP = RTL.HP; |
ACC = R4; |
opRRC = 1000H; opSWPB = 1080H; opRRA = 1100H; opSXT = 1180H; |
opPUSH = 1200H; opCALL = 1280H; opRETI = 1300H; |
opMOV = 04000H; opADD = 05000H; opADDC = 06000H; opSUBC = 07000H; |
opSUB = 08000H; opCMP = 09000H; opDADD = 0A000H; opBIT = 0B000H; |
opBIC = 0C000H; opBIS = 0D000H; opXOR = 0E000H; opAND = 0F000H; |
opJNE = 2000H; opJEQ = 2400H; opJNC = 2800H; opJC = 2C00H; |
opJN = 3000H; opJGE = 3400H; opJL = 3800H; opJMP = 3C00H; |
sREG = 0; sIDX = 16; sINDIR = 32; sINCR = 48; BW = 64; dIDX = 128; |
NOWORD = 10000H; |
RCODE = 0; RDATA = 1; RBSS = 2; |
je = 0; jne = je + 1; |
jge = 2; jl = jge + 1; |
jle = 4; jg = jle + 1; |
jb = 6; |
TYPE |
ANYCODE = POINTER TO RECORD (LISTS.ITEM) |
offset: INTEGER |
END; |
WORD = POINTER TO RECORD (ANYCODE) |
val: INTEGER |
END; |
LABEL = POINTER TO RECORD (ANYCODE) |
num: INTEGER |
END; |
JMP = POINTER TO RECORD (ANYCODE) |
cc, label: INTEGER; |
short: BOOLEAN |
END; |
CALL = POINTER TO RECORD (ANYCODE) |
label: INTEGER |
END; |
COMMAND = IL.COMMAND; |
RELOC = POINTER TO RECORD (LISTS.ITEM) |
section: INTEGER; |
WordPtr: WORD |
END; |
VAR |
R: REG.REGS; |
CodeList: LISTS.LIST; |
RelList: LISTS.LIST; |
mem: ARRAY 65536 OF BYTE; |
Labels: CHL.INTLIST; |
IV: ARRAY RTL.LenIV OF INTEGER; |
IdxWords: RECORD src, dst: INTEGER END; |
StkCnt, MaxStkCnt: INTEGER; |
PROCEDURE CheckProcDataSize* (VarSize, RamSize: INTEGER): BOOLEAN; |
RETURN (VarSize + 1) * 2 + StkReserve + RTL.VarSize < RamSize |
END CheckProcDataSize; |
PROCEDURE EmitLabel (L: INTEGER); |
VAR |
label: LABEL; |
BEGIN |
NEW(label); |
label.num := L; |
LISTS.push(CodeList, label) |
END EmitLabel; |
PROCEDURE EmitWord (val: INTEGER); |
VAR |
word: WORD; |
BEGIN |
IF val < 0 THEN |
ASSERT(val >= -32768); |
val := val MOD 65536 |
ELSE |
ASSERT(val <= 65535) |
END; |
NEW(word); |
word.val := val; |
LISTS.push(CodeList, word) |
END EmitWord; |
PROCEDURE EmitJmp (cc, label: INTEGER); |
VAR |
jmp: JMP; |
BEGIN |
NEW(jmp); |
jmp.cc := cc; |
jmp.label := label; |
jmp.short := FALSE; |
LISTS.push(CodeList, jmp) |
END EmitJmp; |
PROCEDURE EmitCall (label: INTEGER); |
VAR |
call: CALL; |
BEGIN |
NEW(call); |
call.label := label; |
LISTS.push(CodeList, call) |
END EmitCall; |
PROCEDURE IncStk; |
BEGIN |
INC(StkCnt); |
MaxStkCnt := MAX(StkCnt, MaxStkCnt) |
END IncStk; |
PROCEDURE bw (b: BOOLEAN): INTEGER; |
RETURN BW * ORD(b) |
END bw; |
PROCEDURE src_x (x, Rn: INTEGER): INTEGER; |
VAR |
res: INTEGER; |
BEGIN |
IF (x = 0) & ~(Rn IN {PC, SR, CG}) THEN |
res := Rn * 256 + sINDIR |
ELSE |
IdxWords.src := x; |
res := Rn * 256 + sIDX |
END |
RETURN res |
END src_x; |
PROCEDURE dst_x (x, Rn: INTEGER): INTEGER; |
BEGIN |
IdxWords.dst := x |
RETURN Rn + dIDX |
END dst_x; |
PROCEDURE indir (Rn: INTEGER): INTEGER; |
RETURN Rn * 256 + sINDIR |
END indir; |
PROCEDURE incr (Rn: INTEGER): INTEGER; |
RETURN Rn * 256 + sINCR |
END incr; |
PROCEDURE imm (x: INTEGER): INTEGER; |
VAR |
res: INTEGER; |
BEGIN |
CASE x OF |
| 0: res := CG * 256 |
| 1: res := CG * 256 + sIDX |
| 2: res := indir(CG) |
| 4: res := indir(SR) |
| 8: res := incr(SR) |
|-1: res := incr(CG) |
ELSE |
res := incr(PC); |
IdxWords.src := x |
END |
RETURN res |
END imm; |
PROCEDURE Op2 (op, src, dst: INTEGER); |
BEGIN |
ASSERT(BITS(op) - {6, 12..15} = {}); |
ASSERT(BITS(src) - {4, 5, 8..11} = {}); |
ASSERT(BITS(dst) - {0..3, 7} = {}); |
EmitWord(op + src + dst); |
IF IdxWords.src # NOWORD THEN |
EmitWord(IdxWords.src); |
IdxWords.src := NOWORD |
END; |
IF IdxWords.dst # NOWORD THEN |
EmitWord(IdxWords.dst); |
IdxWords.dst := NOWORD |
END |
END Op2; |
PROCEDURE Op1 (op, reg, As: INTEGER); |
BEGIN |
EmitWord(op + reg + As) |
END Op1; |
PROCEDURE MovRR (src, dst: INTEGER); |
BEGIN |
Op2(opMOV, src * 256, dst) |
END MovRR; |
PROCEDURE PushImm (imm: INTEGER); |
BEGIN |
imm := UTILS.Long(imm); |
CASE imm OF |
| 0: Op1(opPUSH, CG, sREG) |
| 1: Op1(opPUSH, CG, sIDX) |
| 2: Op1(opPUSH, CG, sINDIR) |
|-1: Op1(opPUSH, CG, sINCR) |
ELSE |
Op1(opPUSH, PC, sINCR); |
EmitWord(imm) |
END; |
IncStk |
END PushImm; |
PROCEDURE PutWord (word: INTEGER; VAR adr: INTEGER); |
BEGIN |
ASSERT(~ODD(adr)); |
ASSERT((0 <= word) & (word <= 65535)); |
mem[adr] := word MOD 256; |
mem[adr + 1] := word DIV 256; |
INC(adr, 2) |
END PutWord; |
PROCEDURE NewLabel (): INTEGER; |
BEGIN |
CHL.PushInt(Labels, 0) |
RETURN IL.NewLabel() |
END NewLabel; |
PROCEDURE LabelOffs (n: INTEGER): INTEGER; |
RETURN CHL.GetInt(Labels, n) |
END LabelOffs; |
PROCEDURE Fixup (CodeAdr, IntVectorSize: INTEGER): INTEGER; |
VAR |
cmd: ANYCODE; |
adr: INTEGER; |
offset: INTEGER; |
diff: INTEGER; |
cc: INTEGER; |
shorted: BOOLEAN; |
BEGIN |
REPEAT |
shorted := FALSE; |
offset := CodeAdr DIV 2; |
cmd := CodeList.first(ANYCODE); |
WHILE cmd # NIL DO |
cmd.offset := offset; |
CASE cmd OF |
|LABEL: CHL.SetInt(Labels, cmd.num, offset) |
|JMP: INC(offset); |
IF ~cmd.short THEN |
INC(offset); |
IF cmd.cc # opJMP THEN |
INC(offset) |
END |
END |
|CALL: INC(offset, 2) |
|WORD: INC(offset) |
END; |
cmd := cmd.next(ANYCODE) |
END; |
cmd := CodeList.first(ANYCODE); |
WHILE cmd # NIL DO |
IF (cmd IS JMP) & ~cmd(JMP).short THEN |
diff := LabelOffs(cmd(JMP).label) - cmd.offset - 1; |
IF ABS(diff) <= 512 THEN |
cmd(JMP).short := TRUE; |
shorted := TRUE |
END |
END; |
cmd := cmd.next(ANYCODE) |
END |
UNTIL ~shorted; |
IF offset * 2 > 10000H - IntVectorSize THEN |
ERRORS.Error(203) |
END; |
adr := CodeAdr; |
cmd := CodeList.first(ANYCODE); |
WHILE cmd # NIL DO |
CASE cmd OF |
|LABEL: |
|JMP: IF ~cmd.short THEN |
CASE cmd.cc OF |
|opJNE: cc := opJEQ |
|opJEQ: cc := opJNE |
|opJNC: cc := opJC |
|opJC: cc := opJNC |
|opJGE: cc := opJL |
|opJL: cc := opJGE |
|opJMP: cc := opJMP |
END; |
IF cc # opJMP THEN |
PutWord(cc + 2, adr) (* jcc L *) |
END; |
PutWord(4030H, adr); (* MOV @PC+, PC *) |
PutWord(LabelOffs(cmd.label) * 2, adr) |
(* L: *) |
ELSE |
diff := LabelOffs(cmd.label) - cmd.offset - 1; |
ASSERT((-512 <= diff) & (diff <= 511)); |
PutWord(cmd.cc + diff MOD 1024, adr) |
END |
|CALL: PutWord(12B0H, adr); (* CALL @PC+ *) |
PutWord(LabelOffs(cmd.label) * 2, adr) |
|WORD: PutWord(cmd.val, adr) |
END; |
cmd := cmd.next(ANYCODE) |
END |
RETURN adr - CodeAdr |
END Fixup; |
PROCEDURE Push (reg: INTEGER); |
BEGIN |
Op1(opPUSH, reg, sREG); |
IncStk |
END Push; |
PROCEDURE Pop (reg: INTEGER); |
BEGIN |
Op2(opMOV, incr(SP), reg); |
DEC(StkCnt) |
END Pop; |
PROCEDURE Test (reg: INTEGER); |
BEGIN |
Op2(opCMP, imm(0), reg) |
END Test; |
PROCEDURE Clear (reg: INTEGER); |
BEGIN |
Op2(opMOV, imm(0), reg) |
END Clear; |
PROCEDURE mov (dst, src: INTEGER); |
BEGIN |
MovRR(src, dst) |
END mov; |
PROCEDURE xchg (reg1, reg2: INTEGER); |
BEGIN |
Push(reg1); |
mov(reg1, reg2); |
Pop(reg2) |
END xchg; |
PROCEDURE Reloc (section: INTEGER); |
VAR |
reloc: RELOC; |
BEGIN |
NEW(reloc); |
reloc.section := section; |
reloc.WordPtr := CodeList.last(WORD); |
LISTS.push(RelList, reloc) |
END Reloc; |
PROCEDURE CallRTL (proc, params: INTEGER); |
BEGIN |
IncStk; |
DEC(StkCnt); |
EmitCall(RTL.rtl[proc].label); |
RTL.Used(proc); |
IF params > 0 THEN |
Op2(opADD, imm(params * 2), SP); |
DEC(StkCnt, params) |
END |
END CallRTL; |
PROCEDURE UnOp (VAR reg: INTEGER); |
BEGIN |
REG.UnOp(R, reg) |
END UnOp; |
PROCEDURE BinOp (VAR reg1, reg2: INTEGER); |
BEGIN |
REG.BinOp(R, reg1, reg2) |
END BinOp; |
PROCEDURE GetRegA; |
BEGIN |
ASSERT(REG.GetReg(R, ACC)) |
END GetRegA; |
PROCEDURE drop; |
BEGIN |
REG.Drop(R) |
END drop; |
PROCEDURE GetAnyReg (): INTEGER; |
RETURN REG.GetAnyReg(R) |
END GetAnyReg; |
PROCEDURE PushAll (NumberOfParameters: INTEGER); |
BEGIN |
REG.PushAll(R); |
DEC(R.pushed, NumberOfParameters) |
END PushAll; |
PROCEDURE PushAll_1; |
BEGIN |
REG.PushAll_1(R) |
END PushAll_1; |
PROCEDURE cond (op: INTEGER): INTEGER; |
VAR |
res: INTEGER; |
BEGIN |
CASE op OF |
|IL.opGT, IL.opGTC: res := jg |
|IL.opGE, IL.opGEC: res := jge |
|IL.opLT, IL.opLTC: res := jl |
|IL.opLE, IL.opLEC: res := jle |
|IL.opEQ, IL.opEQC: res := je |
|IL.opNE, IL.opNEC: res := jne |
END |
RETURN res |
END cond; |
PROCEDURE jcc (cc, label: INTEGER); |
VAR |
L: INTEGER; |
BEGIN |
CASE cc OF |
|jne: |
EmitJmp(opJNE, label) |
|je: |
EmitJmp(opJEQ, label) |
|jge: |
EmitJmp(opJGE, label) |
|jl: |
EmitJmp(opJL, label) |
|jle: |
EmitJmp(opJL, label); |
EmitJmp(opJEQ, label) |
|jg: |
L := NewLabel(); |
EmitJmp(opJEQ, L); |
EmitJmp(opJGE, label); |
EmitLabel(L) |
|jb: |
EmitJmp(opJNC, label) |
END |
END jcc; |
PROCEDURE setcc (cc, reg: INTEGER); |
VAR |
L: INTEGER; |
BEGIN |
L := NewLabel(); |
Op2(opMOV, imm(1), reg); |
jcc(cc, L); |
Clear(reg); |
EmitLabel(L) |
END setcc; |
PROCEDURE Shift2 (op, reg, n: INTEGER); |
VAR |
reg2: INTEGER; |
BEGIN |
IF n >= 8 THEN |
CASE op OF |
|IL.opASR2: Op1(opSWPB, reg, sREG); Op1(opSXT, reg, sREG) |
|IL.opROR2: Op1(opSWPB, reg, sREG) |
|IL.opLSL2: Op1(opSWPB, reg, sREG); Op2(opBIC, imm(255), reg) |
|IL.opLSR2: Op2(opBIC, imm(255), reg); Op1(opSWPB, reg, sREG) |
END; |
DEC(n, 8) |
END; |
IF (op = IL.opROR2) & (n > 0) THEN |
reg2 := GetAnyReg(); |
MovRR(reg, reg2) |
ELSE |
reg2 := -1 |
END; |
WHILE n > 0 DO |
CASE op OF |
|IL.opASR2: Op1(opRRA, reg, sREG) |
|IL.opROR2: Op1(opRRC, reg2, sREG); Op1(opRRC, reg, sREG) |
|IL.opLSL2: Op2(opADD, reg * 256, reg) |
|IL.opLSR2: Op2(opBIC, imm(1), SR); Op1(opRRC, reg, sREG) |
END; |
DEC(n) |
END; |
IF reg2 # -1 THEN |
drop |
END |
END Shift2; |
PROCEDURE Neg (reg: INTEGER); |
BEGIN |
Op2(opXOR, imm(-1), reg); |
Op2(opADD, imm(1), reg) |
END Neg; |
PROCEDURE LocalOffset (offset: INTEGER): INTEGER; |
RETURN (offset + StkCnt - ORD(offset > 0)) * 2 |
END LocalOffset; |
PROCEDURE LocalDst (offset: INTEGER): INTEGER; |
RETURN dst_x(LocalOffset(offset), SP) |
END LocalDst; |
PROCEDURE LocalSrc (offset: INTEGER): INTEGER; |
RETURN src_x(LocalOffset(offset), SP) |
END LocalSrc; |
PROCEDURE translate (chk_stk: BOOLEAN); |
VAR |
cmd, next: COMMAND; |
opcode, param1, param2, L, a, n, c1, c2: INTEGER; |
reg1, reg2: INTEGER; |
cc: INTEGER; |
word: WORD; |
BEGIN |
cmd := IL.codes.commands.first(COMMAND); |
WHILE cmd # NIL DO |
param1 := cmd.param1; |
param2 := cmd.param2; |
opcode := cmd.opcode; |
CASE opcode OF |
|IL.opJMP: |
EmitJmp(opJMP, param1) |
|IL.opCALL: |
IncStk; |
DEC(StkCnt); |
EmitCall(param1) |
|IL.opCALLP: |
IncStk; |
DEC(StkCnt); |
UnOp(reg1); |
Op1(opCALL, reg1, sREG); |
drop; |
ASSERT(R.top = -1) |
|IL.opPRECALL: |
PushAll(0) |
|IL.opLABEL: |
EmitLabel(param1) |
|IL.opSADR_PARAM: |
Op1(opPUSH, PC, sINCR); |
IncStk; |
EmitWord(param2); |
Reloc(RDATA) |
|IL.opERR: |
CallRTL(RTL._error, 2) |
|IL.opPUSHC: |
PushImm(param2) |
|IL.opONERR: |
DEC(StkCnt); |
EmitWord(0C232H); (* BIC #8, SR; DINT *) |
EmitWord(4303H); (* MOV R3, R3; NOP *) |
PushImm(param2); |
EmitJmp(opJMP, param1) |
|IL.opLEAVEC: |
Pop(PC) |
|IL.opENTER: |
ASSERT(R.top = -1); |
EmitLabel(param1); |
n := param2 MOD 65536; |
param2 := param2 DIV 65536; |
StkCnt := 0; |
IF chk_stk THEN |
L := NewLabel(); |
Op2(opMOV, SP * 256, R4); |
Op2(opSUB, HP * 256, R4); |
Op2(opCMP, imm(StkReserve), R4); |
word := CodeList.last(WORD); |
jcc(jge, L); |
DEC(StkCnt); |
EmitWord(0C232H); (* BIC #8, SR; DINT *) |
EmitWord(4303H); (* MOV R3, R3; NOP *) |
PushImm(n); |
EmitJmp(opJMP, cmd.param3); |
EmitLabel(L) |
END; |
IF param2 > 8 THEN |
Op2(opMOV, imm(param2), R4); |
L := NewLabel(); |
EmitLabel(L); |
Push(CG); |
Op2(opSUB, imm(1), R4); |
jcc(jne, L) |
ELSE |
FOR n := 1 TO param2 DO |
Push(CG) |
END |
END; |
StkCnt := param2; |
MaxStkCnt := StkCnt |
|IL.opLEAVE, IL.opLEAVER: |
ASSERT(param2 = 0); |
IF opcode = IL.opLEAVER THEN |
UnOp(reg1); |
IF reg1 # ACC THEN |
mov(ACC, reg1) |
END; |
drop |
END; |
ASSERT(R.top = -1); |
ASSERT(StkCnt = param1); |
IF chk_stk THEN |
INC(word.val, MaxStkCnt * 2) |
END; |
IF param1 > 0 THEN |
Op2(opADD, imm(param1 * 2), SP) |
END; |
Pop(PC) |
|IL.opRES: |
ASSERT(R.top = -1); |
GetRegA |
|IL.opCLEANUP: |
IF param2 # 0 THEN |
Op2(opADD, imm(param2 * 2), SP); |
DEC(StkCnt, param2) |
END |
|IL.opCONST: |
next := cmd.next(COMMAND); |
IF next.opcode = IL.opCONST THEN |
c1 := param2; |
c2 := next.param2; |
next := next.next(COMMAND); |
IF (next.opcode = IL.opSAVE) OR (next.opcode = IL.opSAVE16) OR (next.opcode = IL.opSAVE8) THEN |
Op2(opMOV + bw(next.opcode = IL.opSAVE8), imm(c1), dst_x(c2, SR)); |
cmd := next |
ELSE |
Op2(opMOV, imm(param2), GetAnyReg()) |
END |
ELSIF (next.opcode = IL.opSAVE) OR (next.opcode = IL.opSAVE16) OR (next.opcode = IL.opSAVE8) THEN |
UnOp(reg1); |
Op2(opMOV + bw(next.opcode = IL.opSAVE8), reg1 * 256, dst_x(param2, SR)); |
drop; |
cmd := next |
ELSE |
Op2(opMOV, imm(param2), GetAnyReg()) |
END |
|IL.opSADR: |
Op2(opMOV, incr(PC), GetAnyReg()); |
EmitWord(param2); |
Reloc(RDATA) |
|IL.opGADR: |
Op2(opMOV, incr(PC), GetAnyReg()); |
EmitWord(param2); |
Reloc(RBSS) |
|IL.opLADR: |
reg1 := GetAnyReg(); |
n := LocalOffset(param2); |
Op2(opMOV, SP * 256, reg1); |
IF n # 0 THEN |
Op2(opADD, imm(n), reg1) |
END |
|IL.opLLOAD8: |
Op2(opMOV + BW, LocalSrc(param2), GetAnyReg()) |
|IL.opLLOAD16, IL.opVADR: |
Op2(opMOV, LocalSrc(param2), GetAnyReg()) |
|IL.opGLOAD8: |
Op2(opMOV + BW, src_x(param2, SR), GetAnyReg()); |
Reloc(RBSS) |
|IL.opGLOAD16: |
Op2(opMOV, src_x(param2, SR), GetAnyReg()); |
Reloc(RBSS) |
|IL.opLOAD8: |
UnOp(reg1); |
Op2(opMOV + BW, indir(reg1), reg1) |
|IL.opLOAD16: |
UnOp(reg1); |
Op2(opMOV, indir(reg1), reg1) |
|IL.opVLOAD8: |
reg1 := GetAnyReg(); |
Op2(opMOV, LocalSrc(param2), reg1); |
Op2(opMOV + BW, indir(reg1), reg1) |
|IL.opVLOAD16: |
reg1 := GetAnyReg(); |
Op2(opMOV, LocalSrc(param2), reg1); |
Op2(opMOV, indir(reg1), reg1) |
|IL.opSAVE, IL.opSAVE16: |
BinOp(reg2, reg1); |
Op2(opMOV, reg2 * 256, dst_x(0, reg1)); |
drop; |
drop |
|IL.opSAVE8: |
BinOp(reg2, reg1); |
Op2(opMOV + BW, reg2 * 256, dst_x(0, reg1)); |
drop; |
drop |
|IL.opSAVE8C: |
UnOp(reg1); |
Op2(opMOV + BW, imm(param2), dst_x(0, reg1)); |
drop |
|IL.opSAVE16C, IL.opSAVEC: |
UnOp(reg1); |
Op2(opMOV, imm(param2), dst_x(0, reg1)); |
drop |
|IL.opUMINUS: |
UnOp(reg1); |
Neg(reg1) |
|IL.opADD: |
BinOp(reg1, reg2); |
Op2(opADD, reg2 * 256, reg1); |
drop |
|IL.opADDC: |
IF param2 # 0 THEN |
UnOp(reg1); |
Op2(opADD, imm(param2), reg1) |
END |
|IL.opSUB: |
BinOp(reg1, reg2); |
Op2(opSUB, reg2 * 256, reg1); |
drop |
|IL.opSUBR, IL.opSUBL: |
UnOp(reg1); |
IF param2 # 0 THEN |
Op2(opSUB, imm(param2), reg1) |
END; |
IF opcode = IL.opSUBL THEN |
Neg(reg1) |
END |
|IL.opLADR_SAVEC: |
Op2(opMOV, imm(param2), LocalDst(param1)) |
|IL.opLADR_SAVE: |
UnOp(reg1); |
Op2(opMOV, reg1 * 256, LocalDst(param2)); |
drop |
|IL.opGADR_SAVEC: |
Op2(opMOV, imm(param2), dst_x(param1, SR)); |
Reloc(RBSS) |
|IL.opCONST_PARAM: |
PushImm(param2) |
|IL.opPARAM: |
IF param2 = 1 THEN |
UnOp(reg1); |
Push(reg1); |
drop |
ELSE |
ASSERT(R.top + 1 <= param2); |
PushAll(param2) |
END |
|IL.opEQ..IL.opGE, |
IL.opEQC..IL.opGEC: |
IF (IL.opEQ <= opcode) & (opcode <= IL.opGE) THEN |
BinOp(reg1, reg2); |
Op2(opCMP, reg2 * 256, reg1); |
drop |
ELSE |
UnOp(reg1); |
Op2(opCMP, imm(param2), reg1) |
END; |
drop; |
cc := cond(opcode); |
next := cmd.next(COMMAND); |
IF next.opcode = IL.opJNZ THEN |
jcc(cc, next.param1); |
cmd := next |
ELSIF next.opcode = IL.opJZ THEN |
jcc(ORD(BITS(cc) / {0}), next.param1); |
cmd := next |
ELSE |
setcc(cc, GetAnyReg()) |
END |
|IL.opNOP, IL.opAND, IL.opOR: |
|IL.opCODE: |
EmitWord(param2) |
|IL.opDROP: |
UnOp(reg1); |
drop |
|IL.opJNZ1: |
UnOp(reg1); |
Test(reg1); |
jcc(jne, param1) |
|IL.opJG: |
UnOp(reg1); |
Test(reg1); |
jcc(jg, param1) |
|IL.opJNZ: |
UnOp(reg1); |
Test(reg1); |
jcc(jne, param1); |
drop |
|IL.opJZ: |
UnOp(reg1); |
Test(reg1); |
jcc(je, param1); |
drop |
|IL.opNOT: |
UnOp(reg1); |
Test(reg1); |
setcc(je, reg1) |
|IL.opORD: |
UnOp(reg1); |
Test(reg1); |
setcc(jne, reg1) |
|IL.opGET: |
BinOp(reg1, reg2); |
drop; |
drop; |
Op2(opMOV + bw(param2 = 1), indir(reg1), dst_x(0, reg2)) |
|IL.opGETC: |
UnOp(reg2); |
drop; |
Op2(opMOV + bw(param2 = 1), src_x(param1, SR), dst_x(0, reg2)) |
|IL.opCHKBYTE: |
BinOp(reg1, reg2); |
Op2(opCMP, imm(256), reg1); |
jcc(jb, param1) |
|IL.opCHKIDX: |
UnOp(reg1); |
Op2(opCMP, imm(param2), reg1); |
jcc(jb, param1) |
|IL.opCHKIDX2: |
BinOp(reg1, reg2); |
IF param2 # -1 THEN |
Op2(opCMP, reg1 * 256, reg2); |
jcc(jb, param1) |
END; |
INCL(R.regs, reg1); |
DEC(R.top); |
R.stk[R.top] := reg2 |
|IL.opINCC, IL.opINCCB: |
UnOp(reg1); |
Op2(opADD + bw(opcode = IL.opINCCB), imm(param2), dst_x(0, reg1)); |
drop |
|IL.opDECCB: |
UnOp(reg1); |
Op2(opSUB + BW, imm(param2), dst_x(0, reg1)); |
drop |
|IL.opINC, IL.opINCB: |
BinOp(reg1, reg2); |
Op2(opADD + bw(opcode = IL.opINCB), reg1 * 256, dst_x(0, reg2)); |
drop; |
drop |
|IL.opDEC, IL.opDECB: |
BinOp(reg1, reg2); |
Op2(opSUB + bw(opcode = IL.opDECB), reg1 * 256, dst_x(0, reg2)); |
drop; |
drop |
|IL.opLADR_INCC, IL.opLADR_INCCB: |
Op2(opADD + bw(opcode = IL.opLADR_INCCB), imm(param2), LocalDst(param1)) |
|IL.opLADR_DECCB: |
Op2(opSUB + BW, imm(param2), LocalDst(param1)) |
|IL.opLADR_INC, IL.opLADR_INCB: |
UnOp(reg1); |
Op2(opADD + bw(opcode = IL.opLADR_INCB), reg1 * 256, LocalDst(param2)); |
drop |
|IL.opLADR_DEC, IL.opLADR_DECB: |
UnOp(reg1); |
Op2(opSUB + bw(opcode = IL.opLADR_DECB), reg1 * 256, LocalDst(param2)); |
drop |
|IL.opPUSHT: |
UnOp(reg1); |
Op2(opMOV, src_x(-2, reg1), GetAnyReg()) |
|IL.opISREC: |
PushAll(2); |
PushImm(param2); |
CallRTL(RTL._guardrec, 3); |
GetRegA |
|IL.opIS: |
PushAll(1); |
PushImm(param2); |
CallRTL(RTL._is, 2); |
GetRegA |
|IL.opTYPEGR: |
PushAll(1); |
PushImm(param2); |
CallRTL(RTL._guardrec, 2); |
GetRegA |
|IL.opTYPEGP: |
UnOp(reg1); |
PushAll(0); |
Push(reg1); |
PushImm(param2); |
CallRTL(RTL._guard, 2); |
GetRegA |
|IL.opTYPEGD: |
UnOp(reg1); |
PushAll(0); |
Op1(opPUSH, reg1, sIDX); |
IncStk; |
EmitWord(-2); |
PushImm(param2); |
CallRTL(RTL._guardrec, 2); |
GetRegA |
|IL.opMULS: |
BinOp(reg1, reg2); |
Op2(opAND, reg2 * 256, reg1); |
drop |
|IL.opMULSC: |
UnOp(reg1); |
Op2(opAND, imm(param2), reg1) |
|IL.opDIVS: |
BinOp(reg1, reg2); |
Op2(opXOR, reg2 * 256, reg1); |
drop |
|IL.opDIVSC: |
UnOp(reg1); |
Op2(opXOR, imm(param2), reg1) |
|IL.opADDS: |
BinOp(reg1, reg2); |
Op2(opBIS, reg2 * 256, reg1); |
drop |
|IL.opSUBS: |
BinOp(reg1, reg2); |
Op2(opBIC, reg2 * 256, reg1); |
drop |
|IL.opADDSC: |
UnOp(reg1); |
Op2(opBIS, imm(param2), reg1) |
|IL.opSUBSL: |
UnOp(reg1); |
Op2(opXOR, imm(-1), reg1); |
Op2(opAND, imm(param2), reg1) |
|IL.opSUBSR: |
UnOp(reg1); |
Op2(opBIC, imm(param2), reg1) |
|IL.opUMINS: |
UnOp(reg1); |
Op2(opXOR, imm(-1), reg1) |
|IL.opLENGTH: |
PushAll(2); |
CallRTL(RTL._length, 2); |
GetRegA |
|IL.opMAX,IL.opMIN: |
BinOp(reg1, reg2); |
Op2(opCMP, reg2 * 256, reg1); |
IF opcode = IL.opMIN THEN |
cc := opJL + 1 |
ELSE |
cc := opJGE + 1 |
END; |
EmitWord(cc); (* jge/jl L *) |
MovRR(reg2, reg1); |
(* L: *) |
drop |
|IL.opMAXC, IL.opMINC: |
UnOp(reg1); |
Op2(opCMP, imm(param2), reg1); |
L := NewLabel(); |
IF opcode = IL.opMINC THEN |
cc := jl |
ELSE |
cc := jge |
END; |
jcc(cc, L); |
Op2(opMOV, imm(param2), reg1); |
EmitLabel(L) |
|IL.opSWITCH: |
UnOp(reg1); |
IF param2 = 0 THEN |
reg2 := ACC |
ELSE |
reg2 := R5 |
END; |
IF reg1 # reg2 THEN |
ASSERT(REG.GetReg(R, reg2)); |
ASSERT(REG.Exchange(R, reg1, reg2)); |
drop |
END; |
drop |
|IL.opENDSW: |
|IL.opCASEL: |
Op2(opCMP, imm(param1), ACC); |
jcc(jl, param2) |
|IL.opCASER: |
Op2(opCMP, imm(param1), ACC); |
jcc(jg, param2) |
|IL.opCASELR: |
Op2(opCMP, imm(param1), ACC); |
IF param2 = cmd.param3 THEN |
jcc(jne, param2) |
ELSE |
jcc(jl, param2); |
jcc(jg, cmd.param3) |
END |
|IL.opSBOOL: |
BinOp(reg2, reg1); |
Test(reg2); |
setcc(jne, reg2); |
Op2(opMOV + BW, reg2 * 256, dst_x(0, reg1)); |
drop; |
drop |
|IL.opSBOOLC: |
UnOp(reg1); |
Op2(opMOV + BW, imm(param2), dst_x(0, reg1)); |
drop |
|IL.opEQS .. IL.opGES: |
PushAll(4); |
PushImm((opcode - IL.opEQS) * 12); |
CallRTL(RTL._strcmp, 5); |
GetRegA |
|IL.opLEN: |
UnOp(reg1); |
drop; |
EXCL(R.regs, reg1); |
WHILE param2 > 0 DO |
UnOp(reg2); |
drop; |
DEC(param2) |
END; |
INCL(R.regs, reg1); |
ASSERT(REG.GetReg(R, reg1)) |
|IL.opLSL, IL.opASR, IL.opROR, IL.opLSR: |
PushAll(2); |
CASE opcode OF |
|IL.opLSL: CallRTL(RTL._lsl, 2) |
|IL.opASR: CallRTL(RTL._asr, 2) |
|IL.opROR: CallRTL(RTL._ror, 2) |
|IL.opLSR: CallRTL(RTL._lsr, 2) |
END; |
GetRegA |
|IL.opLSL1, IL.opASR1, IL.opROR1, IL.opLSR1: |
UnOp(reg1); |
PushAll_1; |
PushImm(param2); |
Push(reg1); |
drop; |
CASE opcode OF |
|IL.opLSL1: CallRTL(RTL._lsl, 2) |
|IL.opASR1: CallRTL(RTL._asr, 2) |
|IL.opROR1: CallRTL(RTL._ror, 2) |
|IL.opLSR1: CallRTL(RTL._lsr, 2) |
END; |
GetRegA |
|IL.opASR2, IL.opROR2, IL.opLSL2, IL.opLSR2: |
param2 := param2 MOD 16; |
IF param2 # 0 THEN |
UnOp(reg1); |
Shift2(opcode, reg1, param2) |
END |
|IL.opMUL: |
PushAll(2); |
CallRTL(RTL._mul, 2); |
GetRegA |
|IL.opMULC: |
UnOp(reg1); |
a := param2; |
IF a > 1 THEN |
n := UTILS.Log2(a) |
ELSIF a < -1 THEN |
n := UTILS.Log2(-a) |
ELSE |
n := -1 |
END; |
IF a = 1 THEN |
ELSIF a = -1 THEN |
Neg(reg1) |
ELSIF a = 0 THEN |
Clear(reg1) |
ELSE |
IF n > 0 THEN |
IF a < 0 THEN |
Neg(reg1) |
END; |
Shift2(IL.opLSL2, reg1, n) |
ELSE |
PushAll(1); |
PushImm(a); |
CallRTL(RTL._mul, 2); |
GetRegA |
END |
END |
|IL.opDIV: |
PushAll(2); |
CallRTL(RTL._divmod, 2); |
GetRegA |
|IL.opDIVR: |
ASSERT(param2 > 0); |
IF param2 > 1 THEN |
n := UTILS.Log2(param2); |
IF n > 0 THEN |
UnOp(reg1); |
Shift2(IL.opASR2, reg1, n) |
ELSE |
PushAll(1); |
PushImm(param2); |
CallRTL(RTL._divmod, 2); |
GetRegA |
END |
END |
|IL.opDIVL: |
UnOp(reg1); |
PushAll_1; |
PushImm(param2); |
Push(reg1); |
drop; |
CallRTL(RTL._divmod, 2); |
GetRegA |
|IL.opMOD: |
PushAll(2); |
CallRTL(RTL._divmod, 2); |
ASSERT(REG.GetReg(R, R5)) |
|IL.opMODR: |
ASSERT(param2 > 0); |
IF param2 = 1 THEN |
UnOp(reg1); |
Clear(reg1) |
ELSE |
IF UTILS.Log2(param2) > 0 THEN |
UnOp(reg1); |
Op2(opAND, imm(param2 - 1), reg1) |
ELSE |
PushAll(1); |
PushImm(param2); |
CallRTL(RTL._divmod, 2); |
ASSERT(REG.GetReg(R, R5)) |
END |
END |
|IL.opMODL: |
UnOp(reg1); |
PushAll_1; |
PushImm(param2); |
Push(reg1); |
drop; |
CallRTL(RTL._divmod, 2); |
ASSERT(REG.GetReg(R, R5)) |
|IL.opCOPYS: |
ASSERT(R.top = 3); |
Push(R.stk[2]); |
Push(R.stk[0]); |
Op2(opCMP, R.stk[1] * 256, R.stk[3]); |
EmitWord(3801H); (* JL L1 *) |
MovRR(R.stk[1], R.stk[3]); |
(* L1: *) |
Push(R.stk[3]); |
drop; |
drop; |
drop; |
drop; |
CallRTL(RTL._move, 3) |
|IL.opCOPY: |
PushAll(2); |
PushImm(param2); |
CallRTL(RTL._move, 3) |
|IL.opMOVE: |
PushAll(3); |
CallRTL(RTL._move, 3) |
|IL.opCOPYA: |
PushAll(4); |
PushImm(param2); |
CallRTL(RTL._arrcpy, 5); |
GetRegA |
|IL.opROT: |
PushAll(0); |
MovRR(SP, ACC); |
Push(ACC); |
PushImm(param2); |
CallRTL(RTL._rot, 2) |
|IL.opSAVES: |
UnOp(reg1); |
PushAll_1; |
Op1(opPUSH, PC, sINCR); |
IncStk; |
EmitWord(param2); |
Reloc(RDATA); |
Push(reg1); |
drop; |
PushImm(param1); |
CallRTL(RTL._move, 3) |
|IL.opCASET: |
Push(R5); |
Push(R5); |
PushImm(param2); |
CallRTL(RTL._guardrec, 2); |
Pop(R5); |
Test(ACC); |
jcc(jne, param1) |
|IL.opCHR: |
UnOp(reg1); |
Op2(opAND, imm(255), reg1) |
|IL.opABS: |
UnOp(reg1); |
Test(reg1); |
L := NewLabel(); |
jcc(jge, L); |
Neg(reg1); |
EmitLabel(L) |
|IL.opEQB, IL.opNEB: |
BinOp(reg1, reg2); |
drop; |
Test(reg1); |
L := NewLabel(); |
jcc(je, L); |
Op2(opMOV, imm(1), reg1); |
EmitLabel(L); |
Test(reg2); |
L := NewLabel(); |
jcc(je, L); |
Op2(opMOV, imm(1), reg2); |
EmitLabel(L); |
Op2(opCMP, reg2 * 256, reg1); |
IF opcode = IL.opEQB THEN |
setcc(je, reg1) |
ELSE |
setcc(jne, reg1) |
END |
|IL.opSAVEP: |
UnOp(reg1); |
Op2(opMOV, incr(PC), reg1 + dIDX); |
EmitWord(param2); |
Reloc(RCODE); |
EmitWord(0); |
drop |
|IL.opPUSHP: |
Op2(opMOV, incr(PC), GetAnyReg()); |
EmitWord(param2); |
Reloc(RCODE) |
|IL.opEQP, IL.opNEP: |
UnOp(reg1); |
Op2(opCMP, incr(PC), reg1); |
EmitWord(param1); |
Reloc(RCODE); |
drop; |
reg1 := GetAnyReg(); |
IF opcode = IL.opEQP THEN |
setcc(je, reg1) |
ELSIF opcode = IL.opNEP THEN |
setcc(jne, reg1) |
END |
|IL.opVADR_PARAM: |
reg1 := GetAnyReg(); |
Op2(opMOV, LocalSrc(param2), reg1); |
Push(reg1); |
drop |
|IL.opNEW: |
PushAll(1); |
n := param2 + 2; |
ASSERT(UTILS.Align(n, 2)); |
PushImm(n); |
PushImm(param1); |
CallRTL(RTL._new, 3) |
|IL.opRSET: |
PushAll(2); |
CallRTL(RTL._set, 2); |
GetRegA |
|IL.opRSETR: |
PushAll(1); |
PushImm(param2); |
CallRTL(RTL._set, 2); |
GetRegA |
|IL.opRSETL: |
UnOp(reg1); |
PushAll_1; |
PushImm(param2); |
Push(reg1); |
drop; |
CallRTL(RTL._set, 2); |
GetRegA |
|IL.opRSET1: |
PushAll(1); |
CallRTL(RTL._set1, 1); |
GetRegA |
|IL.opINCLC: |
UnOp(reg1); |
Op2(opBIS, imm(ORD({param2})), dst_x(0, reg1)); |
drop |
|IL.opEXCLC: |
UnOp(reg1); |
Op2(opBIC, imm(ORD({param2})), dst_x(0, reg1)); |
drop |
|IL.opIN: |
PushAll(2); |
CallRTL(RTL._in, 2); |
GetRegA |
|IL.opINR: |
PushAll(1); |
PushImm(param2); |
CallRTL(RTL._in, 2); |
GetRegA |
|IL.opINL: |
PushAll(1); |
PushImm(param2); |
CallRTL(RTL._in2, 2); |
GetRegA |
|IL.opINCL: |
PushAll(2); |
CallRTL(RTL._incl, 2) |
|IL.opEXCL: |
PushAll(2); |
CallRTL(RTL._excl, 2) |
|IL.opLADR_INCL, IL.opLADR_EXCL: |
PushAll(1); |
MovRR(SP, ACC); |
n := LocalOffset(param2); |
IF n # 0 THEN |
Op2(opADD, imm(n), ACC) |
END; |
Push(ACC); |
IF opcode = IL.opLADR_INCL THEN |
CallRTL(RTL._incl, 2) |
ELSIF opcode = IL.opLADR_EXCL THEN |
CallRTL(RTL._excl, 2) |
END |
|IL.opLADR_INCLC: |
Op2(opBIS, imm(ORD({param2})), LocalDst(param1)) |
|IL.opLADR_EXCLC: |
Op2(opBIC, imm(ORD({param2})), LocalDst(param1)) |
END; |
cmd := cmd.next(COMMAND) |
END; |
ASSERT(R.pushed = 0); |
ASSERT(R.top = -1) |
END translate; |
PROCEDURE prolog; |
VAR |
i: INTEGER; |
BEGIN |
RTL.Init(EmitLabel, EmitWord, EmitCall); |
FOR i := 0 TO LEN(RTL.rtl) - 1 DO |
RTL.Set(i, NewLabel()) |
END; |
IV[LEN(IV) - 1] := NewLabel(); |
EmitLabel(IV[LEN(IV) - 1]); |
Op2(opMOV, incr(PC), SP); |
EmitWord(0); |
Op2(opMOV, incr(PC), HP); |
EmitWord(0); |
Op2(opMOV, imm(5A80H), dst_x(0120H, SR)); (* stop WDT *) |
Op2(opMOV, imm(RTL.empty_proc), dst_x(0, SP)); |
Op2(opMOV, imm(RTL.empty_proc), dst_x(2, SP)); |
END prolog; |
PROCEDURE epilog; |
VAR |
L1, i, n: INTEGER; |
BEGIN |
Op2(opBIS, imm(10H), SR); (* CPUOFF *) |
L1 := NewLabel(); |
FOR i := 0 TO LEN(IV) - 2 DO |
IV[i] := NewLabel(); |
EmitLabel(IV[i]); |
PushImm(i); |
IF i # LEN(IV) - 2 THEN |
EmitJmp(opJMP, L1) |
END |
END; |
EmitLabel(L1); |
n := 0; |
FOR i := 0 TO 15 DO |
IF i IN R.regs THEN |
Push(i); |
INC(n) |
END |
END; |
MovRR(SP, R4); |
Op2(opADD, imm(n * 2), R4); |
Push(R4); |
Op1(opPUSH, R4, sINDIR); |
Op1(opCALL, SR, sIDX); EmitWord(-RTL.VarSize); Reloc(RBSS); (* call int *) |
Op2(opADD, imm(4), SP); |
FOR i := 15 TO 0 BY -1 DO |
IF i IN R.regs THEN |
Pop(i) |
END |
END; |
Op2(opADD, imm(2), SP); |
Op1(opRETI, 0, 0); |
RTL.Gen |
END epilog; |
PROCEDURE CodeGen* (outname: ARRAY OF CHAR; target: INTEGER; options: PROG.OPTIONS); |
VAR |
i, adr, heap, stack, TextSize, TypesSize, bits, n, val: INTEGER; |
Code, Data, Bss: RECORD address, size: INTEGER END; |
ram, rom: INTEGER; |
reloc: RELOC; |
BEGIN |
IdxWords.src := NOWORD; |
IdxWords.dst := NOWORD; |
ram := options.ram; |
rom := options.rom; |
IF ODD(ram) THEN DEC(ram) END; |
IF ODD(rom) THEN DEC(rom) END; |
ram := MIN(MAX(ram, minRAM), maxRAM); |
rom := MIN(MAX(rom, minROM), maxROM); |
IF IL.codes.bss > ram - StkReserve - RTL.VarSize THEN |
ERRORS.Error(204) |
END; |
Labels := CHL.CreateIntList(); |
FOR i := 1 TO IL.codes.lcount DO |
CHL.PushInt(Labels, 0) |
END; |
CodeList := LISTS.create(NIL); |
RelList := LISTS.create(NIL); |
REG.Init(R, Push, Pop, mov, xchg, {R4, R5, R6, R7}); |
prolog; |
translate(chkSTK IN options.checking); |
epilog; |
TypesSize := CHL.Length(IL.codes.types) * 2; |
Data.size := CHL.Length(IL.codes.data); |
IF ODD(Data.size) THEN |
CHL.PushByte(IL.codes.data, 0); |
INC(Data.size) |
END; |
Code.size := Fixup(0, IntVectorSize + TypesSize + Data.size); |
Code.address := 10000H - (IntVectorSize + TypesSize + Data.size + Code.size); |
IF Code.address < 10000H - rom THEN |
ERRORS.Error(203) |
END; |
Code.size := Fixup(Code.address, IntVectorSize + TypesSize + Data.size); |
Data.address := Code.address + Code.size; |
TextSize := Code.size + Data.size; |
IF Code.address + TextSize + MAX(IL.codes.dmin - Data.size, IntVectorSize + TypesSize) > 10000H THEN |
ERRORS.Error(203) |
END; |
stack := RTL.ram + ram; |
Bss.size := IL.codes.bss + IL.codes.bss MOD 2; |
DEC(stack, Bss.size); |
Bss.address := stack; |
DEC(stack, RTL.VarSize); |
heap := RTL.ram; |
ASSERT(stack - heap >= StkReserve); |
adr := Code.address + 2; |
PutWord(stack, adr); |
adr := Code.address + 6; |
PutWord(heap, adr); |
reloc := RelList.first(RELOC); |
WHILE reloc # NIL DO |
adr := reloc.WordPtr.offset * 2; |
val := reloc.WordPtr.val; |
CASE reloc.section OF |
|RCODE: PutWord(LabelOffs(val) * 2, adr) |
|RDATA: PutWord(val + Data.address, adr) |
|RBSS: PutWord((val + Bss.address) MOD 65536, adr) |
END; |
reloc := reloc.next(RELOC) |
END; |
adr := Data.address; |
FOR i := 0 TO Data.size - 1 DO |
mem[adr] := CHL.GetByte(IL.codes.data, i); |
INC(adr) |
END; |
FOR i := TypesSize DIV 2 - 1 TO 0 BY -1 DO |
PutWord(CHL.GetInt(IL.codes.types, i), adr) |
END; |
FOR i := 0 TO 15 DO |
PutWord((33 - i) * i, adr); |
END; |
FOR n := 0 TO 15 DO |
bits := ORD({0 .. n}); |
FOR i := 0 TO 15 - n DO |
PutWord(bits, adr); |
bits := LSL(bits, 1) |
END |
END; |
PutWord(4130H, adr); (* RET *) |
PutWord(stack, adr); |
PutWord(0001H, adr); (* bsl signature (adr 0FFBEH) *) |
FOR i := 0 TO LEN(IV) - 1 DO |
PutWord(LabelOffs(IV[i]) * 2, adr) |
END; |
INC(TextSize, IntVectorSize + TypesSize + Code.address MOD 16); |
INC(Bss.size, StkReserve + RTL.VarSize); |
WR.Create(outname); |
HEX.Data(mem, Code.address - Code.address MOD 16, TextSize); |
HEX.End; |
WR.Close; |
C.Dashes; |
C.String(" rom: "); C.Int(TextSize); C.String(" of "); C.Int(rom); C.String(" ("); C.Int(TextSize * 100 DIV rom); C.StringLn("%)"); |
C.Ln; |
C.String(" ram: "); C.Int(Bss.size); C.String(" of "); C.Int(ram); C.String(" ("); C.Int(Bss.size * 100 DIV ram); C.StringLn("%)") |
END CodeGen; |
END MSP430. |
/programs/develop/oberon07/source/MSP430RTL.ob07 |
---|
0,0 → 1,671 |
(* |
BSD 2-Clause License |
Copyright (c) 2019-2021, Anton Krotov |
All rights reserved. |
*) |
MODULE MSP430RTL; |
CONST |
_mul* = 0; |
_divmod* = 1; |
_lsl* = 2; |
_asr* = 3; |
_ror* = 4; |
_lsr* = 5; |
_in* = 6; |
_in2* = 7; |
_set1* = 8; |
_incl* = 9; |
_excl* = 10; |
_move* = 11; |
_set* = 12; |
_arrcpy* = 13; |
_rot* = 14; |
_strcmp* = 15; |
_error* = 16; |
_is* = 17; |
_guard* = 18; |
_guardrec* = 19; |
_length* = 20; |
_new* = 21; |
HP* = 15; |
LenIV* = 32; |
iv = 10000H - LenIV * 2; |
bsl = iv - 2; |
sp = bsl - 2; |
empty_proc* = sp - 2; |
bits = empty_proc - 272; |
bits_offs = bits - 32; |
DataSize* = iv - bits_offs; |
types = bits_offs - 2; |
IntVectorSize* = LenIV * 2 + DataSize; |
VarSize* = 4; |
StkReserve* = 40; |
trap = 2; |
TYPE |
EMITPROC = PROCEDURE (n: INTEGER); |
VAR |
ram*: INTEGER; |
rtl*: ARRAY 22 OF |
RECORD |
label*: INTEGER; |
used: BOOLEAN |
END; |
Label, Word, Call: EMITPROC; |
PROCEDURE Gen*; |
PROCEDURE Word1 (word: INTEGER); |
BEGIN |
Word(word) |
END Word1; |
PROCEDURE Word2 (word1, word2: INTEGER); |
BEGIN |
Word1(word1); |
Word1(word2) |
END Word2; |
PROCEDURE Word3 (word1, word2, word3: INTEGER); |
BEGIN |
Word1(word1); |
Word1(word2); |
Word1(word3) |
END Word3; |
BEGIN |
(* _lsl (n, x: INTEGER): INTEGER *) |
IF rtl[_lsl].used THEN |
Label(rtl[_lsl].label); |
Word2(4115H, 2); (* MOV 2(SP), R5; R5 <- n *) |
Word2(4114H, 4); (* MOV 4(SP), R4; R4 <- x *) |
Word2(0F035H, 15); (* AND #15, R5 *) |
Word1(2400H + 3); (* JZ L1 *) |
(* L2: *) |
Word1(5404H); (* ADD R4, R4 *) |
Word1(8315H); (* SUB #1, R5 *) |
Word1(2000H + 400H - 3); (* JNZ L2 *) |
(* L1: *) |
Word1(4130H) (* RET *) |
END; |
(* _asr (n, x: INTEGER): INTEGER *) |
IF rtl[_asr].used THEN |
Label(rtl[_asr].label); |
Word2(4115H, 2); (* MOV 2(SP), R5; R5 <- n *) |
Word2(4114H, 4); (* MOV 4(SP), R4; R4 <- x *) |
Word2(0F035H, 15); (* AND #15, R5 *) |
Word1(2400H + 3); (* JZ L1 *) |
(* L2: *) |
Word1(1104H); (* RRA R4 *) |
Word1(8315H); (* SUB #1, R5 *) |
Word1(2000H + 400H - 3); (* JNZ L2 *) |
(* L1: *) |
Word1(4130H) (* RET *) |
END; |
(* _ror (n, x: INTEGER): INTEGER *) |
IF rtl[_ror].used THEN |
Label(rtl[_ror].label); |
Word2(4115H, 2); (* MOV 2(SP), R5; R5 <- n *) |
Word2(4114H, 4); (* MOV 4(SP), R4; R4 <- x *) |
Word2(0F035H, 15); (* AND #15, R5 *) |
Word1(2400H + 5); (* JZ L1 *) |
Word1(4406H); (* MOV R4, R6 *) |
(* L2: *) |
Word1(1006H); (* RRC R6 *) |
Word1(1004H); (* RRC R4 *) |
Word1(8315H); (* SUB #1, R5 *) |
Word1(2000H + 400H - 4); (* JNZ L2 *) |
(* L1: *) |
Word1(4130H) (* RET *) |
END; |
(* _lsr (n, x: INTEGER): INTEGER *) |
IF rtl[_lsr].used THEN |
Label(rtl[_lsr].label); |
Word2(4115H, 2); (* MOV 2(SP), R5; R5 <- n *) |
Word2(4114H, 4); (* MOV 4(SP), R4; R4 <- x *) |
Word2(0F035H, 15); (* AND #15, R5 *) |
Word1(2400H + 4); (* JZ L1 *) |
(* L2: *) |
Word1(0C312H); (* BIC #1, SR *) |
Word1(1004H); (* RRC R4 *) |
Word1(8315H); (* SUB #1, R5 *) |
Word1(2000H + 400H - 4); (* JNZ L2 *) |
(* L1: *) |
Word1(4130H) (* RET *) |
END; |
(* _set (b, a: INTEGER): SET *) |
IF rtl[_set].used THEN |
Label(rtl[_set].label); |
Word2(4114H, 2); (* MOV 2(SP), R4; R4 <- b *) |
Word2(4115H, 4); (* MOV 4(SP), R5; R5 <- a *) |
Word1(9504H); (* CMP R5, R4 *) |
Word1(3800H + 24); (* JL L1 *) |
Word2(9035H, 16); (* CMP #16, R5 *) |
Word1(3400H + 21); (* JGE L1 *) |
Word1(9304H); (* CMP #0, R4 *) |
Word1(3800H + 19); (* JL L1 *) |
Word2(9034H, 16); (* CMP #16, R4 *) |
Word1(3800H + 2); (* JL L2 *) |
Word2(4034H, 15); (* MOV #15, R4 *) |
(* L2: *) |
Word1(9305H); (* CMP #0, R5 *) |
Word1(3400H + 1); (* JGE L3 *) |
Word1(4305H); (* MOV #0, R5 *) |
(* L3: *) |
Word1(8504H); (* SUB R5, R4 *) |
Word1(5404H); (* ADD R4, R4 *) |
Word2(5034H, bits_offs); (* ADD bits_offs, R4 *) |
Word1(4424H); (* MOV @R4, R4 *) |
Word1(5505H); (* ADD R5, R5 *) |
Word1(5405H); (* ADD R4, R5 *) |
Word2(5035H, bits); (* ADD bits, R5 *) |
Word1(4524H); (* MOV @R5, R4 *) |
Word1(4130H); (* RET *) |
(* L1: *) |
Word1(4304H); (* MOV #0, R4 *) |
Word1(4130H) (* RET *) |
END; |
(* _set1 (a: INTEGER): SET *) |
IF rtl[_set1].used THEN |
Label(rtl[_set1].label); |
Word2(4114H, 2); (* MOV 2(SP), R4; R4 <- a *) |
Word2(0B034H, 0FFF0H); (* BIT #0FFF0H, R4 *) |
Word1(2000H + 5); (* JNZ L1 *) |
Word1(5404H); (* ADD R4, R4 *) |
Word2(5034H, bits); (* ADD bits, R4 *) |
Word1(4424H); (* MOV @R4, R4 *) |
Word1(4130H); (* RET *) |
(* L1: *) |
Word1(4304H); (* MOV #0, R4 *) |
Word1(4130H) (* RET *) |
END; |
(* _in2 (i, s: INTEGER): BOOLEAN *) |
IF rtl[_in2].used THEN |
Label(rtl[_in2].label); |
Word2(4114H, 2); (* MOV 2(SP), R4; R4 <- i *) |
Word1(5404H); (* ADD R4, R4 *) |
Word2(5034H, bits); (* ADD bits, R4 *) |
Word1(4424H); (* MOV @R4, R4 *) |
Word2(0F114H, 4); (* AND 4(SP), R4 *) |
Word1(2400H + 1); (* JZ L1 *) |
Word1(4314H); (* MOV #1, R4 *) |
(* L1: *) |
Word1(4130H) (* RET *) |
END; |
(* _in (s, i: INTEGER): BOOLEAN *) |
IF rtl[_in].used THEN |
Label(rtl[_in].label); |
Word2(4114H, 4); (* MOV 4(SP), R4; R4 <- i *) |
Word2(0B034H, 0FFF0H); (* BIT #0FFF0H, R4 *) |
Word1(2000H + 9); (* JNZ L2 *) |
Word1(5404H); (* ADD R4, R4 *) |
Word2(5034H, bits); (* ADD bits, R4 *) |
Word1(4424H); (* MOV @R4, R4 *) |
Word2(0F114H, 2); (* AND 2(SP), R4 *) |
Word1(2400H + 3); (* JZ L1 *) |
Word1(4314H); (* MOV #1, R4 *) |
Word1(4130H); (* RET *) |
(* L2: *) |
Word1(4304H); (* MOV #0, R4 *) |
(* L1: *) |
Word1(4130H) (* RET *) |
END; |
(* _incl (VAR s: SET; i: INTEGER) *) |
IF rtl[_incl].used THEN |
Label(rtl[_incl].label); |
Word2(4114H, 4); (* MOV 4(SP), R4; R4 <- i *) |
Word2(0B034H, 0FFF0H); (* BIT #0FFF0H, R4 *) |
Word1(2000H + 8); (* JNZ L1 *) |
Word1(5404H); (* ADD R4, R4 *) |
Word2(5034H, bits); (* ADD bits, R4 *) |
Word1(4424H); (* MOV @R4, R4 *) |
Word2(4115H, 2); (* MOV 2(SP), R5; R5 <- @s *) |
Word2(0D485H, 0); (* BIS R4, 0(R5) *) |
(* L1: *) |
Word1(4130H) (* RET *) |
END; |
(* _excl (VAR s: SET; i: INTEGER) *) |
IF rtl[_excl].used THEN |
Label(rtl[_excl].label); |
Word2(4114H, 4); (* MOV 4(SP), R4; R4 <- i *) |
Word2(0B034H, 0FFF0H); (* BIT #0FFF0H, R4 *) |
Word1(2000H + 8); (* JNZ L1 *) |
Word1(5404H); (* ADD R4, R4 *) |
Word2(5034H, bits); (* ADD bits, R4 *) |
Word1(4424H); (* MOV @R4, R4 *) |
Word2(4115H, 2); (* MOV 2(SP), R5; R5 <- @s *) |
Word2(0C485H, 0); (* BIC R4, 0(R5) *) |
(* L1: *) |
Word1(4130H) (* RET *) |
END; |
(* _rot (len, adr: INTEGER) *) |
IF rtl[_rot].used THEN |
Label(rtl[_rot].label); |
Word2(4114H, 2); (* MOV 2(SP), R4; R4 <- len *) |
Word2(4115H, 4); (* MOV 4(SP), R5; R5 <- adr *) |
Word1(8314H); (* SUB #1, R4 *) |
Word1(5404H); (* ADD R4, R4 *) |
Word1(1225H); (* PUSH @R5 *) |
Word1(4406H); (* MOV R4, R6 *) |
(* L1: *) |
Word3(4595H, 2, 0); (* MOV 2(R5), 0(R5) *) |
Word1(5325H); (* ADD #2, R5 *) |
Word1(8326H); (* SUB #2, R6 *) |
Word1(2000H + 400H - 6); (* JNZ L1 *) |
Word2(41B5H, 0); (* MOV @SP+, 0(R5) *) |
Word1(4130H) (* RET *) |
END; |
(* _divmod (b, a: INTEGER): INTEGER (* res -> R4, mod -> R5 *) *) |
IF rtl[_divmod].used THEN |
Label(rtl[_divmod].label); |
Word2(4115H, 4); (* MOV 4(SP), R5; R5 <- a *) |
Word1(4304H); (* MOV #0, R4 *) |
(* L1: *) |
Word2(4116H, 2); (* MOV 2(SP), R6; R6 <- b *) |
Word1(9605H); (* CMP R6, R5 *) |
Word1(3800H + 17); (* JL L3 *) |
Word1(4327H); (* MOV #2, R7 *) |
Word1(5606H); (* ADD R6, R6 *) |
(* L4: *) |
Word1(9306H); (* CMP #0, R6 *) |
Word1(2400H + 6); (* JZ L2 *) |
Word1(3800H + 5); (* JL L2 *) |
Word1(9605H); (* CMP R6, R5 *) |
Word1(3800H + 3); (* JL L2 *) |
Word1(5606H); (* ADD R6, R6 *) |
Word1(5707H); (* ADD R7, R7 *) |
Word1(3C00H + 400H - 8); (* JMP L4 *) |
(* L2: *) |
Word1(0C312H); (* BIC #1, SR *) |
Word1(1006H); (* RRC R6 *) |
Word1(0C312H); (* BIC #1, SR *) |
Word1(1007H); (* RRC R7 *) |
Word1(8605H); (* SUB R6, R5 *) |
Word1(5704H); (* ADD R7, R4 *) |
Word1(3C00H + 400H - 21); (* JMP L1 *) |
(* L3: *) |
(*----------- (a < 0) --------------*) |
(* L1: *) |
Word1(9305H); (* CMP #0, R5 *) |
Word1(3400H + 23); (* JGE L3 *) |
Word2(4116H, 2); (* MOV 2(SP), R6; R6 <- b *) |
Word1(4327H); (* MOV #2, R7 *) |
Word1(5606H); (* ADD R6, R6 *) |
Word1(0E335H); (* XOR #-1, R5 *) |
Word1(5315H); (* ADD #1, R5 *) |
(* L4: *) |
Word1(9306H); (* CMP #0, R6 *) |
Word1(2400H + 6); (* JZ L2 *) |
Word1(3800H + 5); (* JL L2 *) |
Word1(9605H); (* CMP R6, R5 *) |
Word1(3800H + 3); (* JL L2 *) |
Word1(5606H); (* ADD R6, R6 *) |
Word1(5707H); (* ADD R7, R7 *) |
Word1(3C00H + 400H - 8); (* JMP L4 *) |
(* L2: *) |
Word1(0E335H); (* XOR #-1, R5 *) |
Word1(5315H); (* ADD #1, R5 *) |
Word1(0C312H); (* BIC #1, SR *) |
Word1(1006H); (* RRC R6 *) |
Word1(0C312H); (* BIC #1, SR *) |
Word1(1007H); (* RRC R7 *) |
Word1(5605H); (* ADD R6, R5 *) |
Word1(8704H); (* SUB R7, R4 *) |
Word1(3C00H + 400H - 25); (* JMP L1 *) |
(* L3: *) |
Word1(4130H) (* RET *) |
END; |
(* _mul (a, b: INTEGER): INTEGER *) |
IF rtl[_mul].used THEN |
Label(rtl[_mul].label); |
Word2(4115H, 2); (* MOV 2(SP), R5; R5 <- a *) |
Word2(4116H, 4); (* MOV 4(SP), R6; R6 <- b *) |
Word1(4304H); (* MOV #0, R4; res := 0 *) |
Word1(9306H); (* CMP #0, R6 *) |
Word1(2400H + 7); (* JZ L1 *) |
(* L2: *) |
Word1(0B316H); (* BIT #1, R6 *) |
Word1(2400H + 1); (* JZ L3 *) |
Word1(5504H); (* ADD R5, R4 *) |
(* L3: *) |
Word1(5505H); (* ADD R5, R5 *) |
Word1(0C312H); (* BIC #1, SR *) |
Word1(1006H); (* RRC R6 *) |
Word1(2000H + 400H - 7); (* JNZ L2 *) |
(* L1: *) |
Word1(4130H) (* RET *) |
END; |
(* _error (modNum, modName, err, line: INTEGER) *) |
IF rtl[_error].used THEN |
Label(rtl[_error].label); |
Word1(5321H); (* ADD #2, SP *) |
Word1(4134H); (* POP R4; R4 <- modNum *) |
Word1(4135H); (* POP R5; R5 <- modName *) |
Word1(4136H); (* POP R6; R6 <- err *) |
Word1(4137H); (* POP R7; R7 <- line *) |
Word2(4211H, sp); (* MOV sp(SR), SP *) |
Word1(1207H); (* PUSH R7 *) |
Word1(1206H); (* PUSH R6 *) |
Word1(1205H); (* PUSH R5 *) |
Word1(1204H); (* PUSH R4 *) |
Word2(4214H, sp); (* MOV sp(SR), R4 *) |
Word2(1294H, trap); (* CALL trap(R4) *) |
Word2(04032H, 0F0H) (* MOV CPUOFF+OSCOFF+SCG0+SCG1, SR *) |
END; |
(* _new (t, size: INTEGER; VAR ptr: INTEGER) *) |
IF rtl[_new].used THEN |
Label(rtl[_new].label); |
Word1(1202H); (* PUSH SR *) |
Word1(4302H); (* MOV #0, SR *) |
Word1(4303H); (* NOP *) |
Word1(4104H); (* MOV SP, R4 *) |
Word2(8034H, StkReserve); (* SUB #StkReserve, R4 *) |
Word1(4005H + 100H * HP); (* MOV HP, R5 *) |
Word2(5115H, 6); (* ADD 6(SP), R5 *) |
Word1(9504H); (* CMP R5, R4 *) |
Word2(4114H, 8); (* MOV 8(SP), R4 *) |
Word1(3800H + 12); (* JL L1 *) |
Word3(4190H + HP, 4, 0); (* MOV 4(SP), 0(HP) *) |
Word1(5320H + HP); (* ADD #2, HP *) |
Word2(4084H + 100H * HP, 0); (* MOV HP, 0(R4) *) |
(* L3 *) |
Word2(4380H + HP, 0); (* MOV #0, 0(HP) *) |
Word1(5320H + HP); (* ADD #2, HP *) |
Word1(9500H + HP); (* CMP R5, HP *) |
Word1(3800H + 400H - 5); (* JL L3 *) |
Word1(3C00H + 2); (* JMP L2 *) |
(* L1 *) |
Word2(4384H, 0); (* MOV #0, 0(R4) *) |
(* L2 *) |
Word1(1300H) (* RETI *) |
END; |
(* _guardrec (t0, t1: INTEGER): INTEGER *) |
IF rtl[_guardrec].used THEN |
Label(rtl[_guardrec].label); |
Word2(4114H, 2); (* MOV 2(SP), R4; R4 <- t0 *) |
Word2(4115H, 4); (* MOV 4(SP), R5; R5 <- t1 *) |
Word2(4036H, types); (* MOV #types, R6 *) |
(* L3: *) |
Word1(9305H); (* CMP #0, R5 *) |
Word1(2400H + 8); (* JZ L1 *) |
Word1(9405H); (* CMP R4, R5 *) |
Word1(2400H + 10); (* JZ L2 *) |
Word1(5505H); (* ADD R5, R5 *) |
Word1(0E335H); (* XOR #-1, R5 *) |
Word1(5315H); (* ADD #1, R5 *) |
Word1(5605H); (* ADD R6, R5 *) |
Word1(4525H); (* MOV @R5, R5 *) |
Word1(3C00H + 400H - 10); (* JMP L3 *) |
(* L1: *) |
Word1(9405H); (* CMP R4, R5 *) |
Word1(2400H + 2); (* JZ L2 *) |
Word1(4304H); (* MOV #0, R4 *) |
Word1(4130H); (* RET *) |
(* L2: *) |
Word1(4314H); (* MOV #1, R4 *) |
Word1(4130H) (* RET *) |
END; |
(* _is (t, p: INTEGER): INTEGER *) |
IF rtl[_is].used THEN |
Label(rtl[_is].label); |
Word2(4114H, 4); (* MOV 4(SP), R4; R4 <- p *) |
Word2(4115H, 2); (* MOV 2(SP), R5; R5 <- t *) |
Word1(9304H); (* TST R4 *) |
Word1(2400H + 2); (* JZ L *) |
Word2(4414H, -2); (* MOV -2(R4), R4 *) |
(* L: *) |
Word1(1204H); (* PUSH R4 *) |
Word1(1205H); (* PUSH R5 *) |
Call(rtl[_guardrec].label); (* CALL _guardrec *) |
Word1(5221H); (* ADD #4, SP *) |
Word1(4130H) (* RET *) |
END; |
(* _guard (t, p: INTEGER): INTEGER *) |
IF rtl[_guard].used THEN |
Label(rtl[_guard].label); |
Word2(4115H, 4); (* MOV 4(SP), R5; R5 <- p *) |
Word1(4314H); (* MOV #1, R4 *) |
Word1(4525H); (* MOV @R5, R5 *) |
Word1(9305H); (* TST R5 *) |
Word1(2400H + 9); (* JZ L *) |
Word2(4515H, -2); (* MOV -2(R5), R5 *) |
Word2(4114H, 2); (* MOV 2(SP), R4; R4 <- t *) |
Word1(1205H); (* PUSH R5 *) |
Word1(1204H); (* PUSH R4 *) |
Call(rtl[_guardrec].label); (* CALL _guardrec *) |
Word1(5221H); (* ADD #4, SP *) |
(* L: *) |
Word1(4130H) (* RET *) |
END; |
(* _move (bytes, dest, source: INTEGER) *) |
IF rtl[_move].used THEN |
Label(rtl[_move].label); |
Word2(4116H, 2); (* MOV 2(SP), R6; R6 <- bytes *) |
Word2(4117H, 4); (* MOV 4(SP), R7; R7 <- dest *) |
Word2(4115H, 6); (* MOV 6(SP), R5; R5 <- source *) |
Word1(9306H); (* CMP #0, R6 *) |
Word1(3800H + 6); (* JL L1 *) |
Word1(2400H + 5); (* JZ L1 *) |
(* L2: *) |
Word2(45F7H, 0); (* MOV.B @R5+, 0(R7) *) |
Word1(5317H); (* ADD #1, R7 *) |
Word1(8316H); (* SUB #1, R6 *) |
Word1(2000H + 400H - 5); (* JNZ L2 *) |
(* L1: *) |
Word1(4130H) (* RET *) |
END; |
(* _arrcpy (base_size, len_dst, dst, len_src, src: INTEGER) *) |
IF rtl[_arrcpy].used THEN |
Label(rtl[_arrcpy].label); |
Word3(9191H, 8, 4); (* CMP 8(SP), 4(SP) *) |
Word1(3800H + 18); (* JL L1 *) |
Word2(1211H, 12); (* PUSH 12(SP) *) |
Word2(1211H, 10); (* PUSH 10(SP) *) |
Word2(1211H, 14); (* PUSH 14(SP) *) |
Word2(1211H, 10); (* PUSH 10(SP) *) |
Call(rtl[_mul].label); (* CALL _mul *) |
Word1(5221H); (* ADD #4, SP *) |
Word1(1204H); (* PUSH R4 *) |
Call(rtl[_move].label); (* CALL _move *) |
Word2(5031H, 6); (* ADD #6, SP *) |
Word1(4314H); (* MOV #1, R4 *) |
Word1(4130H); (* RET *) |
(* L1 *) |
Word1(4304H); (* MOV #0, R4 *) |
Word1(4130H) (* RET *) |
END; |
(* _length (len, str: INTEGER): INTEGER *) |
IF rtl[_length].used THEN |
Label(rtl[_length].label); |
Word2(4116H, 2); (* MOV 2(SP), R6; R6 <- len *) |
Word2(4117H, 4); (* MOV 4(SP), R7; R7 <- str *) |
Word1(4304H); (* MOV #0, R4; res := 0 *) |
(* L2: *) |
Word1(4775H); (* MOV.B @R7+, R5 *) |
Word1(9305H); (* CMP #0, R5 *) |
Word1(2400H + 3); (* JZ L1 *) |
Word1(5314H); (* ADD #1, R4 *) |
Word1(8316H); (* SUB #1, R6 *) |
Word1(2000H + 400H - 6); (* JNZ L2 *) |
(* L1: *) |
Word1(4130H) (* RET *) |
END; |
(* _strcmp (op, len2, str2, len1, str1: INTEGER): BOOLEAN *) |
IF rtl[_strcmp].used THEN |
Label(rtl[_strcmp].label); |
Word2(4116H, 4); (* MOV 4(SP), R6; R6 <- len2 *) |
Word2(4117H, 8); (* MOV 8(SP), R7; R7 <- len1 *) |
Word1(9607H); (* CMP R6, R7 *) |
Word1(3400H + 1); (* JGE L5 *) |
Word1(4706H); (* MOV R7, R6 *) |
(* L5: *) |
Word1(1206H); (* PUSH R6 *) |
Word2(4116H, 12); (* MOV 12(SP), R6; R6 <- str1 *) |
Word2(4117H, 8); (* MOV 8(SP), R7; R7 <- str2 *) |
(* L3: *) |
Word2(9381H, 0); (* CMP #0, 0(SP) *) |
Word1(2400H + 11); (* JZ L1 *) |
Word1(4674H); (* MOV.B @R6+, R4 *) |
Word1(4775H); (* MOV.B @R7+, R5 *) |
Word2(8391H, 0); (* SUB #1, 0(SP) *) |
Word1(9405H); (* CMP R4, R5 *) |
Word1(2400H + 2); (* JZ L2 *) |
Word1(8504H); (* SUB R5, R4 *) |
Word1(3C00H + 5); (* JMP L4 *) |
(* L2: *) |
Word1(9304H); (* CMP #0, R4 *) |
Word1(2000H + 400H - 13); (* JNZ L3 *) |
Word1(3C00H + 2); (* JMP L4 *) |
(* L1: *) |
Word2(4034H, 8000H); (* MOV #8000H, R4 *) |
(* L4: *) |
Word1(5321H); (* ADD #2, SP *) |
Word2(9034H, 8000H); (* CMP #8000H, R4 *) |
Word1(2000H + 18); (* JNZ L6 *) |
Word2(4116H, 4); (* MOV 4(SP), R6; R6 <- len2 *) |
Word2(4117H, 8); (* MOV 8(SP), R7; R7 <- len1 *) |
Word1(9607H); (* CMP R6, R7 *) |
Word1(2400H + 11); (* JZ L7 *) |
Word1(3800H + 4); (* JL L8 *) |
Word2(5116H, 10); (* ADD 10(SP), R6 *) |
Word1(4664H); (* MOV.B @R6, R4 *) |
Word1(3C00H + 7); (* JMP L6 *) |
(* L8: *) |
Word2(5117H, 6); (* ADD 6(SP), R7 *) |
Word1(4764H); (* MOV.B @R7, R4 *) |
Word1(0E334H); (* XOR #-1, R4 *) |
Word1(5314H); (* ADD #1, R4 *) |
Word1(3C00H + 1); (* JMP L6 *) |
(* L7: *) |
Word1(4304H); (* MOV #0, R4 *) |
(* L6: *) |
Word2(5110H, 2); (* ADD 2(SP), PC; PC <- PC + op *) |
Word1(9304H); (* CMP #0, R4 *) |
Word1(4314H); (* MOV #1, R4 *) |
Word1(2400H + 1); (* JZ L *) |
Word1(4304H); (* MOV #0, R4 *) |
(* L *) |
Word1(4130H); (* RET *) |
Word1(4303H); (* NOP *) |
Word1(9304H); (* CMP #0, R4 *) |
Word1(4314H); (* MOV #1, R4 *) |
Word1(2000H + 1); (* JNZ L *) |
Word1(4304H); (* MOV #0, R4 *) |
(* L *) |
Word1(4130H); (* RET *) |
Word1(4303H); (* NOP *) |
Word1(9304H); (* CMP #0, R4 *) |
Word1(4314H); (* MOV #1, R4 *) |
Word1(3800H + 1); (* JL L *) |
Word1(4304H); (* MOV #0, R4 *) |
(* L *) |
Word1(4130H); (* RET *) |
Word1(4303H); (* NOP *) |
Word1(9304H); (* CMP #0, R4 *) |
Word1(4314H); (* MOV #1, R4 *) |
Word1(3800H + 2); (* JL L *) |
Word1(2400H + 1); (* JZ L *) |
Word1(4304H); (* MOV #0, R4 *) |
(* L *) |
Word1(4130H); (* RET *) |
Word1(9304H); (* CMP #0, R4 *) |
Word1(4304H); (* MOV #0, R4 *) |
Word1(3800H + 2); (* JL L *) |
Word1(2400H + 1); (* JZ L *) |
Word1(4314H); (* MOV #1, R4 *) |
(* L *) |
Word1(4130H); (* RET *) |
Word1(9304H); (* CMP #0, R4 *) |
Word1(4314H); (* MOV #1, R4 *) |
Word1(3400H + 1); (* JGE L *) |
Word1(4304H); (* MOV #0, R4 *) |
(* L *) |
Word1(4130H) (* RET *) |
END |
END Gen; |
PROCEDURE Set* (idx, label: INTEGER); |
BEGIN |
rtl[idx].label := label; |
rtl[idx].used := FALSE |
END Set; |
PROCEDURE Used* (idx: INTEGER); |
BEGIN |
rtl[idx].used := TRUE; |
IF (idx = _guard) OR (idx = _is) THEN |
rtl[_guardrec].used := TRUE |
ELSIF idx = _arrcpy THEN |
rtl[_move].used := TRUE; |
rtl[_mul].used := TRUE |
END |
END Used; |
PROCEDURE Init* (pLabel, pWord, pCall: EMITPROC); |
BEGIN |
Label := pLabel; |
Word := pWord; |
Call := pCall; |
ram := 200H; |
END Init; |
END MSP430RTL. |
/programs/develop/oberon07/source/PARS.ob07 |
---|
0,0 → 1,1375 |
(* |
BSD 2-Clause License |
Copyright (c) 2018-2021, Anton Krotov |
All rights reserved. |
*) |
MODULE PARS; |
IMPORT PROG, SCAN, ARITH, STRINGS, ERRORS, LISTS, IL, CONSOLE, PATHS, UTILS, |
C := COLLECTIONS, TARGETS, THUMB, MSP430; |
CONST |
eCONST* = 1; eTYPE* = 2; eVAR* = 3; eEXPR* = 4; |
eVREC* = 5; ePROC* = 6; eVPAR* = 7; ePARAM* = 8; |
eSTPROC* = 9; eSTFUNC* = 10; eSYSFUNC* = 11; eSYSPROC* = 12; |
eIMP* = 13; |
TYPE |
PATH* = PATHS.PATH; |
PARSER* = POINTER TO rPARSER; |
POSITION* = RECORD (SCAN.POSITION) |
parser*: PARSER |
END; |
EXPR* = RECORD |
obj*: INTEGER; |
_type*: PROG._TYPE; |
value*: ARITH.VALUE; |
stproc*: INTEGER; |
readOnly*: BOOLEAN; |
ident*: PROG.IDENT |
END; |
STATPROC = PROCEDURE (parser: PARSER); |
EXPRPROC = PROCEDURE (parser: PARSER; VAR e: EXPR); |
RETPROC = PROCEDURE (parser: PARSER; e: EXPR; t: PROG._TYPE; pos: POSITION): BOOLEAN; |
rPARSER = RECORD (C.ITEM) |
fname*: PATH; |
path: PATH; |
lib_path: PATH; |
ext: PATH; |
modname: PATH; |
scanner: SCAN.SCANNER; |
lex*: SCAN.LEX; |
sym*: INTEGER; |
unit*: PROG.UNIT; |
constexp*: BOOLEAN; |
main*: BOOLEAN; |
open*: PROCEDURE (parser: PARSER; modname, FileExt: ARRAY OF CHAR): BOOLEAN; |
parse*: PROCEDURE (parser: PARSER); |
StatSeq*: STATPROC; |
expression*: EXPRPROC; |
designator*: EXPRPROC; |
chkreturn: RETPROC; |
create*: PROCEDURE (path, lib_path: PATH; StatSeq: STATPROC; expression, designator: EXPRPROC; chkreturn: RETPROC): PARSER |
END; |
VAR |
parsers: C.COLLECTION; |
lines*, modules: INTEGER; |
PROCEDURE destroy* (VAR parser: PARSER); |
BEGIN |
IF parser.scanner # NIL THEN |
SCAN.close(parser.scanner) |
END; |
C.push(parsers, parser); |
parser := NIL |
END destroy; |
PROCEDURE getpos (parser: PARSER; VAR pos: POSITION); |
BEGIN |
pos.line := parser.lex.pos.line; |
pos.col := parser.lex.pos.col; |
pos.parser := parser |
END getpos; |
PROCEDURE error* (pos: POSITION; errno: INTEGER); |
BEGIN |
ERRORS.ErrorMsg(pos.parser.fname, pos.line, pos.col, errno) |
END error; |
PROCEDURE check* (condition: BOOLEAN; pos: POSITION; errno: INTEGER); |
BEGIN |
IF ~condition THEN |
error(pos, errno) |
END |
END check; |
PROCEDURE check1* (condition: BOOLEAN; parser: PARSER; errno: INTEGER); |
VAR |
pos: POSITION; |
BEGIN |
IF ~condition THEN |
getpos(parser, pos); |
error(pos, errno) |
END |
END check1; |
PROCEDURE Next* (parser: PARSER); |
VAR |
errno: INTEGER; |
BEGIN |
SCAN.Next(parser.scanner, parser.lex); |
errno := parser.lex.error; |
IF errno = 0 THEN |
IF (TARGETS.RealSize = 0) & (parser.lex.sym = SCAN.lxFLOAT) THEN |
errno := -SCAN.lxERROR13 |
ELSIF (TARGETS.BitDepth = 16) & (parser.lex.sym = SCAN.lxCHAR) & (parser.lex.value.typ = ARITH.tWCHAR) THEN |
errno := -SCAN.lxERROR10 |
END |
END; |
IF errno # 0 THEN |
check1(FALSE, parser, errno) |
END; |
parser.sym := parser.lex.sym |
END Next; |
PROCEDURE NextPos (parser: PARSER; VAR pos: POSITION); |
BEGIN |
Next(parser); |
getpos(parser, pos) |
END NextPos; |
PROCEDURE checklex* (parser: PARSER; sym: INTEGER); |
VAR |
err: INTEGER; |
BEGIN |
IF parser.sym # sym THEN |
CASE sym OF |
|SCAN.lxCOMMA: err := 65 |
|SCAN.lxRROUND: err := 33 |
|SCAN.lxPOINT: err := 26 |
|SCAN.lxIDENT: err := 22 |
|SCAN.lxRSQUARE: err := 71 |
|SCAN.lxRCURLY: err := 35 |
|SCAN.lxUNDEF: err := 34 |
|SCAN.lxTHEN: err := 88 |
|SCAN.lxEND: err := 27 |
|SCAN.lxDO: err := 89 |
|SCAN.lxUNTIL: err := 90 |
|SCAN.lxCOLON: err := 53 |
|SCAN.lxOF: err := 67 |
|SCAN.lxASSIGN: err := 96 |
|SCAN.lxTO: err := 57 |
|SCAN.lxLROUND: err := 64 |
|SCAN.lxEQ: err := 32 |
|SCAN.lxSEMI: err := 24 |
|SCAN.lxRETURN: err := 38 |
|SCAN.lxMODULE: err := 21 |
END; |
check1(FALSE, parser, err) |
END |
END checklex; |
PROCEDURE ExpectSym* (parser: PARSER; sym: INTEGER); |
BEGIN |
Next(parser); |
checklex(parser, sym) |
END ExpectSym; |
PROCEDURE ImportList (parser: PARSER); |
VAR |
fname, path, ext, _name: PATH; |
name: SCAN.IDENT; |
parser2: PARSER; |
pos: POSITION; |
alias, _in: BOOLEAN; |
unit: PROG.UNIT; |
ident: PROG.IDENT; |
BEGIN |
alias := FALSE; |
REPEAT |
ExpectSym(parser, SCAN.lxIDENT); |
name := parser.lex.ident; |
getpos(parser, pos); |
IF ~alias THEN |
ident := PROG.addIdent(parser.unit, name, PROG.idMODULE); |
check(ident # NIL, pos, 30) |
END; |
Next(parser); |
path := parser.path; |
fname := ""; |
ext := UTILS.FILE_EXT; |
COPY(name.s, _name); |
_in := FALSE; |
IF parser.sym = SCAN.lxIN THEN |
_in := TRUE; |
Next(parser); |
IF parser.sym = SCAN.lxSTRING THEN |
STRINGS.trim(parser.lex.string.s, fname) |
ELSIF parser.sym = SCAN.lxCHAR THEN |
fname[0] := CHR(ARITH.Int(parser.lex.value)); |
fname[1] := 0X |
ELSE |
check1(FALSE, parser, 117) |
END; |
STRINGS.replace(fname, "/", UTILS.slash); |
STRINGS.replace(fname, "\", UTILS.slash); |
PATHS.DelSlashes(fname); |
PATHS.split(fname, path, _name, ext); |
IF PATHS.isRelative(path) THEN |
PATHS.RelPath(parser.path, path, fname); |
STRINGS.append(fname, _name); |
STRINGS.append(fname, ext); |
PATHS.split(fname, path, _name, ext) |
END; |
Next(parser) |
END; |
IF (parser.sym = SCAN.lxCOMMA) OR (parser.sym = SCAN.lxSEMI) THEN |
alias := FALSE; |
IF (fname = "") & ((_name = "SYSTEM") OR PROG.LowerCase & (_name = "system")) THEN |
unit := PROG.program.sysunit |
ELSE |
IF fname # "" THEN |
unit := PROG.getUnit(fname) |
ELSE |
fname := path; |
STRINGS.append(fname, _name); |
STRINGS.append(fname, UTILS.FILE_EXT); |
unit := PROG.getUnit(fname); |
IF unit = NIL THEN |
fname := parser.lib_path; |
STRINGS.append(fname, _name); |
STRINGS.append(fname, UTILS.FILE_EXT); |
unit := PROG.getUnit(fname) |
END |
END |
END; |
IF unit # NIL THEN |
check(unit.closed, pos, 31) |
ELSE |
parser2 := parser.create(path, parser.lib_path, |
parser.StatSeq, parser.expression, parser.designator, parser.chkreturn); |
IF ~parser2.open(parser2, _name, ext) THEN |
IF (path # parser.lib_path) & ~_in THEN |
destroy(parser2); |
parser2 := parser.create(parser.lib_path, parser.lib_path, |
parser.StatSeq, parser.expression, parser.designator, parser.chkreturn); |
check(parser2.open(parser2, _name, ext), pos, 29) |
ELSE |
error(pos, 29) |
END |
END; |
parser2.parse(parser2); |
unit := parser2.unit; |
unit.fname := parser2.fname; |
destroy(parser2) |
END; |
IF unit = PROG.program.sysunit THEN |
parser.unit.sysimport := TRUE |
END; |
ident.unit := unit |
ELSIF parser.sym = SCAN.lxASSIGN THEN |
alias := TRUE |
ELSE |
check1(FALSE, parser, 28) |
END |
UNTIL parser.sym = SCAN.lxSEMI; |
Next(parser) |
END ImportList; |
PROCEDURE QIdent (parser: PARSER; forward: BOOLEAN): PROG.IDENT; |
VAR |
ident: PROG.IDENT; |
unit: PROG.UNIT; |
BEGIN |
ASSERT(parser.sym = SCAN.lxIDENT); |
ident := PROG.getIdent(parser.unit, parser.lex.ident, FALSE); |
IF ~forward THEN |
check1(ident # NIL, parser, 48) |
END; |
IF (ident # NIL) & (ident.typ = PROG.idMODULE) THEN |
unit := ident.unit; |
ExpectSym(parser, SCAN.lxPOINT); |
ExpectSym(parser, SCAN.lxIDENT); |
ident := PROG.getIdent(unit, parser.lex.ident, FALSE); |
check1((ident # NIL) & ident.export, parser, 48) |
END |
RETURN ident |
END QIdent; |
PROCEDURE strcmp* (VAR v: ARITH.VALUE; v2: ARITH.VALUE; operator: INTEGER); |
VAR |
str: SCAN.TEXTSTR; |
string1, string2: SCAN.STRING; |
bool: BOOLEAN; |
BEGIN |
IF v.typ = ARITH.tCHAR THEN |
ASSERT(v2.typ = ARITH.tSTRING); |
ARITH.charToStr(v, str); |
string1 := SCAN.enterStr(str); |
string2 := v2.string(SCAN.STRING) |
END; |
IF v2.typ = ARITH.tCHAR THEN |
ASSERT(v.typ = ARITH.tSTRING); |
ARITH.charToStr(v2, str); |
string2 := SCAN.enterStr(str); |
string1 := v.string(SCAN.STRING) |
END; |
IF v.typ = v2.typ THEN |
string1 := v.string(SCAN.STRING); |
string2 := v2.string(SCAN.STRING) |
END; |
CASE operator OF |
|SCAN.lxEQ: bool := string1.s = string2.s |
|SCAN.lxNE: bool := string1.s # string2.s |
|SCAN.lxLT: bool := string1.s < string2.s |
|SCAN.lxGT: bool := string1.s > string2.s |
|SCAN.lxLE: bool := string1.s <= string2.s |
|SCAN.lxGE: bool := string1.s >= string2.s |
END; |
ARITH.setbool(v, bool) |
END strcmp; |
PROCEDURE ConstExpression* (parser: PARSER; VAR v: ARITH.VALUE); |
VAR |
e: EXPR; |
pos: POSITION; |
BEGIN |
getpos(parser, pos); |
parser.constexp := TRUE; |
parser.expression(parser, e); |
parser.constexp := FALSE; |
check(e.obj = eCONST, pos, 62); |
v := e.value |
END ConstExpression; |
PROCEDURE FieldList (parser: PARSER; rec: PROG._TYPE); |
VAR |
name: SCAN.IDENT; |
export: BOOLEAN; |
pos: POSITION; |
BEGIN |
ASSERT(parser.sym = SCAN.lxIDENT); |
WHILE parser.sym = SCAN.lxIDENT DO |
getpos(parser, pos); |
name := parser.lex.ident; |
Next(parser); |
export := parser.sym = SCAN.lxMUL; |
IF export THEN |
check1(parser.unit.scopeLvl = 0, parser, 61); |
Next(parser) |
END; |
check(PROG.addField(rec, name, export), pos, 30); |
IF parser.sym = SCAN.lxCOMMA THEN |
ExpectSym(parser, SCAN.lxIDENT) |
ELSE |
checklex(parser, SCAN.lxCOLON) |
END |
END |
END FieldList; |
PROCEDURE FormalParameters (parser: PARSER; _type: PROG._TYPE); |
VAR |
ident: PROG.IDENT; |
PROCEDURE FPSection (parser: PARSER; _type: PROG._TYPE); |
VAR |
ident: PROG.IDENT; |
exit: BOOLEAN; |
vPar: BOOLEAN; |
dim: INTEGER; |
t0, t1: PROG._TYPE; |
BEGIN |
vPar := parser.sym = SCAN.lxVAR; |
IF vPar THEN |
Next(parser) |
END; |
checklex(parser, SCAN.lxIDENT); |
exit := FALSE; |
WHILE (parser.sym = SCAN.lxIDENT) & ~exit DO |
check1(PROG.addParam(_type, parser.lex.ident, vPar), parser, 30); |
Next(parser); |
IF parser.sym = SCAN.lxCOMMA THEN |
ExpectSym(parser, SCAN.lxIDENT) |
ELSIF parser.sym = SCAN.lxCOLON THEN |
Next(parser); |
dim := 0; |
WHILE parser.sym = SCAN.lxARRAY DO |
INC(dim); |
check1(dim <= PROG.MAXARRDIM, parser, 84); |
ExpectSym(parser, SCAN.lxOF); |
Next(parser) |
END; |
checklex(parser, SCAN.lxIDENT); |
ident := QIdent(parser, FALSE); |
check1(ident.typ = PROG.idTYPE, parser, 68); |
t0 := ident._type; |
t1 := t0; |
WHILE dim > 0 DO |
t1 := PROG.enterType(PROG.tARRAY, -1, 0, parser.unit); |
t1.base := t0; |
t0 := t1; |
DEC(dim) |
END; |
PROG.setParams(_type, t1); |
Next(parser); |
exit := TRUE |
ELSE |
checklex(parser, SCAN.lxCOLON) |
END |
END |
END FPSection; |
BEGIN |
IF parser.sym = SCAN.lxLROUND THEN |
Next(parser); |
IF (parser.sym = SCAN.lxVAR) OR (parser.sym = SCAN.lxIDENT) THEN |
FPSection(parser, _type); |
WHILE parser.sym = SCAN.lxSEMI DO |
Next(parser); |
FPSection(parser, _type) |
END |
END; |
checklex(parser, SCAN.lxRROUND); |
Next(parser); |
IF parser.sym = SCAN.lxCOLON THEN |
ExpectSym(parser, SCAN.lxIDENT); |
ident := QIdent(parser, FALSE); |
check1(ident.typ = PROG.idTYPE, parser, 68); |
check1(~(ident._type.typ IN {PROG.tRECORD, PROG.tARRAY}), parser, 69); |
check1( ~(ODD(_type.call) & (ident._type.typ = PROG.tREAL)), parser, 113); |
_type.base := ident._type; |
Next(parser) |
ELSE |
_type.base := NIL |
END |
END |
END FormalParameters; |
PROCEDURE sysflag (parser: PARSER; proc: BOOLEAN): INTEGER; |
VAR |
res, sf: INTEGER; |
BEGIN |
checklex(parser, SCAN.lxIDENT); |
IF parser.lex.ident.s = "stdcall" THEN |
sf := PROG.sf_stdcall |
ELSIF parser.lex.ident.s = "cdecl" THEN |
sf := PROG.sf_cdecl |
ELSIF parser.lex.ident.s = "ccall" THEN |
sf := PROG.sf_ccall |
ELSIF parser.lex.ident.s = "win64" THEN |
sf := PROG.sf_win64 |
ELSIF parser.lex.ident.s = "systemv" THEN |
sf := PROG.sf_systemv |
ELSIF parser.lex.ident.s = "windows" THEN |
sf := PROG.sf_windows |
ELSIF parser.lex.ident.s = "linux" THEN |
sf := PROG.sf_linux |
ELSIF parser.lex.ident.s = "code" THEN |
sf := PROG.sf_code |
ELSIF parser.lex.ident.s = "oberon" THEN |
sf := PROG.sf_oberon |
ELSIF parser.lex.ident.s = "noalign" THEN |
sf := PROG.sf_noalign |
ELSE |
check1(FALSE, parser, 124) |
END; |
check1(sf IN PROG.program.sysflags, parser, 125); |
IF proc THEN |
check1(sf IN PROG.proc_flags, parser, 123) |
ELSE |
check1(sf IN PROG.rec_flags, parser, 123) |
END; |
CASE sf OF |
|PROG.sf_stdcall: |
res := PROG.stdcall |
|PROG.sf_cdecl: |
res := PROG.cdecl |
|PROG.sf_ccall: |
IF TARGETS.OS IN {TARGETS.osWIN32, TARGETS.osLINUX32, TARGETS.osKOS} THEN |
res := PROG.ccall |
ELSIF TARGETS.OS = TARGETS.osWIN64 THEN |
res := PROG.win64 |
ELSIF TARGETS.OS = TARGETS.osLINUX64 THEN |
res := PROG.systemv |
END |
|PROG.sf_win64: |
res := PROG.win64 |
|PROG.sf_systemv: |
res := PROG.systemv |
|PROG.sf_code: |
res := PROG.code |
|PROG.sf_oberon: |
IF TARGETS.OS IN {TARGETS.osWIN32, TARGETS.osLINUX32, TARGETS.osKOS} THEN |
res := PROG.default32 |
ELSIF TARGETS.OS IN {TARGETS.osWIN64, TARGETS.osLINUX64} THEN |
res := PROG.default64 |
END |
|PROG.sf_windows: |
IF TARGETS.OS = TARGETS.osWIN32 THEN |
res := PROG.stdcall |
ELSIF TARGETS.OS = TARGETS.osWIN64 THEN |
res := PROG.win64 |
END |
|PROG.sf_linux: |
IF TARGETS.OS = TARGETS.osLINUX32 THEN |
res := PROG.ccall |
ELSIF TARGETS.OS = TARGETS.osLINUX64 THEN |
res := PROG.systemv |
END |
|PROG.sf_noalign: |
res := PROG.noalign |
END |
RETURN res |
END sysflag; |
PROCEDURE procflag (parser: PARSER; VAR _import: IL.IMPORT_PROC; isProc: BOOLEAN): INTEGER; |
VAR |
call: INTEGER; |
dll, proc: SCAN.TEXTSTR; |
pos: POSITION; |
PROCEDURE getStr (parser: PARSER; VAR name: SCAN.TEXTSTR); |
VAR |
pos: POSITION; |
str: ARITH.VALUE; |
BEGIN |
getpos(parser, pos); |
ConstExpression(parser, str); |
IF str.typ = ARITH.tSTRING THEN |
name := str.string(SCAN.STRING).s |
ELSIF str.typ = ARITH.tCHAR THEN |
ARITH.charToStr(str, name) |
ELSE |
check(FALSE, pos, 117) |
END |
END getStr; |
BEGIN |
_import := NIL; |
IF parser.sym = SCAN.lxLSQUARE THEN |
getpos(parser, pos); |
check1(parser.unit.sysimport, parser, 54); |
Next(parser); |
call := sysflag(parser, TRUE); |
Next(parser); |
IF parser.sym = SCAN.lxMINUS THEN |
Next(parser); |
INC(call) |
END; |
IF isProc & (parser.sym = SCAN.lxCOMMA) THEN |
Next(parser); |
getStr(parser, dll); |
STRINGS.UpCase(dll); |
checklex(parser, SCAN.lxCOMMA); |
Next(parser); |
getStr(parser, proc); |
_import := IL.AddImp(dll, proc) |
END; |
checklex(parser, SCAN.lxRSQUARE); |
Next(parser) |
ELSE |
CASE TARGETS.BitDepth OF |
|16: call := PROG.default16 |
|32: IF TARGETS.CPU = TARGETS.cpuX86 THEN |
call := PROG.default32 |
ELSE |
call := PROG.cdecl |
END |
|64: IF TARGETS.CPU = TARGETS.cpuAMD64 THEN |
call := PROG.default64 |
ELSE |
call := PROG.cdecl |
END |
END |
END; |
IF _import # NIL THEN |
check(TARGETS.Import, pos, 70) |
END |
RETURN call |
END procflag; |
PROCEDURE _type (parser: PARSER; VAR t: PROG._TYPE; flags: SET); |
CONST |
comma = 0; |
closed = 1; |
forward = 2; |
VAR |
arrLen: ARITH.VALUE; |
typeSize: ARITH.VALUE; |
ident: PROG.IDENT; |
unit: PROG.UNIT; |
pos, pos2: POSITION; |
fieldType: PROG._TYPE; |
baseIdent: SCAN.IDENT; |
a, b: INTEGER; |
RecFlag: INTEGER; |
_import: IL.IMPORT_PROC; |
BEGIN |
unit := parser.unit; |
t := NIL; |
IF parser.sym = SCAN.lxIDENT THEN |
ident := QIdent(parser, forward IN flags); |
IF ident # NIL THEN |
check1(ident.typ = PROG.idTYPE, parser, 49); |
t := ident._type; |
check1(t # NIL, parser, 50); |
IF closed IN flags THEN |
check1(t.closed, parser, 50) |
END |
END; |
Next(parser) |
ELSIF (parser.sym = SCAN.lxARRAY) OR ((parser.sym = SCAN.lxCOMMA) & (comma IN flags)) THEN |
IF parser.sym = SCAN.lxARRAY THEN |
getpos(parser, pos2) |
END; |
NextPos(parser, pos); |
ConstExpression(parser, arrLen); |
check(arrLen.typ = ARITH.tINTEGER, pos, 43); |
check(ARITH.check(arrLen), pos, 39); |
check(ARITH.getInt(arrLen) > 0, pos, 51); |
t := PROG.enterType(PROG.tARRAY, -1, ARITH.getInt(arrLen), unit); |
IF parser.sym = SCAN.lxCOMMA THEN |
_type(parser, t.base, {comma, closed}) |
ELSIF parser.sym = SCAN.lxOF THEN |
Next(parser); |
_type(parser, t.base, {closed}) |
ELSE |
check1(FALSE, parser, 47) |
END; |
t.align := t.base.align; |
a := t.length; |
b := t.base.size; |
check(ARITH.mulInt(a, b), pos2, 104); |
check(ARITH.setInt(typeSize, a), pos2, 104); |
t.size := a; |
t.closed := TRUE |
ELSIF parser.sym = SCAN.lxRECORD THEN |
getpos(parser, pos2); |
Next(parser); |
t := PROG.enterType(PROG.tRECORD, 0, 0, unit); |
t.align := 1; |
IF parser.sym = SCAN.lxLSQUARE THEN |
check1(parser.unit.sysimport, parser, 54); |
Next(parser); |
RecFlag := sysflag(parser, FALSE); |
t.noalign := RecFlag = PROG.noalign; |
ExpectSym(parser, SCAN.lxRSQUARE); |
Next(parser) |
END; |
IF parser.sym = SCAN.lxLROUND THEN |
check1(~t.noalign, parser, 111); |
ExpectSym(parser, SCAN.lxIDENT); |
getpos(parser, pos); |
_type(parser, t.base, {closed}); |
check(t.base.typ IN {PROG.tRECORD, PROG.tPOINTER}, pos, 52); |
IF t.base.typ = PROG.tPOINTER THEN |
t.base := t.base.base; |
check(t.base # NIL, pos, 55) |
END; |
check(~t.base.noalign, pos, 112); |
checklex(parser, SCAN.lxRROUND); |
Next(parser); |
t.size := t.base.size; |
IF t.base.align > t.align THEN |
t.align := t.base.align |
END |
ELSE |
t.base := PROG.program.stTypes.tANYREC |
END; |
WHILE parser.sym = SCAN.lxIDENT DO |
FieldList(parser, t); |
ASSERT(parser.sym = SCAN.lxCOLON); |
Next(parser); |
_type(parser, fieldType, {closed}); |
check(PROG.setFields(t, fieldType), pos2, 104); |
IF (fieldType.align > t.align) & ~t.noalign THEN |
t.align := fieldType.align |
END; |
IF parser.sym = SCAN.lxSEMI THEN |
ExpectSym(parser, SCAN.lxIDENT) |
ELSE |
checklex(parser, SCAN.lxEND) |
END |
END; |
t.closed := TRUE; |
IL.AddRec(t.base.num); |
IF ~t.noalign THEN |
check(UTILS.Align(t.size, t.align), pos2, 104); |
check(ARITH.setInt(typeSize, t.size), pos2, 104) |
END; |
checklex(parser, SCAN.lxEND); |
Next(parser) |
ELSIF parser.sym = SCAN.lxPOINTER THEN |
ExpectSym(parser, SCAN.lxTO); |
Next(parser); |
t := PROG.enterType(PROG.tPOINTER, TARGETS.AdrSize, 0, unit); |
t.align := TARGETS.AdrSize; |
getpos(parser, pos); |
IF parser.sym = SCAN.lxIDENT THEN |
baseIdent := parser.lex.ident |
END; |
_type(parser, t.base, {forward}); |
IF t.base # NIL THEN |
check(t.base.typ = PROG.tRECORD, pos, 58) |
ELSE |
PROG.frwPtr(unit, t, baseIdent, pos) |
END |
ELSIF parser.sym = SCAN.lxPROCEDURE THEN |
NextPos(parser, pos); |
t := PROG.enterType(PROG.tPROCEDURE, TARGETS.AdrSize, 0, unit); |
t.align := TARGETS.AdrSize; |
t.call := procflag(parser, _import, FALSE); |
FormalParameters(parser, t) |
ELSE |
check1(FALSE, parser, 49) |
END |
END _type; |
PROCEDURE IdentDef (parser: PARSER; typ: INTEGER; VAR name: SCAN.IDENT): PROG.IDENT; |
VAR |
ident: PROG.IDENT; |
pos: POSITION; |
BEGIN |
ASSERT(parser.sym = SCAN.lxIDENT); |
name := parser.lex.ident; |
getpos(parser, pos); |
ident := PROG.addIdent(parser.unit, name, typ); |
check(ident # NIL, pos, 30); |
ident.pos := pos; |
Next(parser); |
IF parser.sym = SCAN.lxMUL THEN |
check1(ident.global, parser, 61); |
ident.export := TRUE; |
Next(parser) |
END |
RETURN ident |
END IdentDef; |
PROCEDURE ConstTypeDeclaration (parser: PARSER; _const: BOOLEAN); |
VAR |
ident: PROG.IDENT; |
name: SCAN.IDENT; |
pos: POSITION; |
BEGIN |
IF _const THEN |
ident := IdentDef(parser, PROG.idNONE, name) |
ELSE |
ident := IdentDef(parser, PROG.idTYPE, name) |
END; |
checklex(parser, SCAN.lxEQ); |
NextPos(parser, pos); |
IF _const THEN |
ConstExpression(parser, ident.value); |
IF ident.value.typ = ARITH.tINTEGER THEN |
check(ARITH.check(ident.value), pos, 39) |
ELSIF ident.value.typ = ARITH.tREAL THEN |
check(ARITH.check(ident.value), pos, 40) |
END; |
ident.typ := PROG.idCONST; |
ident._type := PROG.getType(ident.value.typ) |
ELSE |
_type(parser, ident._type, {}) |
END; |
checklex(parser, SCAN.lxSEMI); |
Next(parser) |
END ConstTypeDeclaration; |
PROCEDURE VarDeclaration (parser: PARSER); |
VAR |
ident: PROG.IDENT; |
name: SCAN.IDENT; |
t: PROG._TYPE; |
BEGIN |
REPEAT |
ident := IdentDef(parser, PROG.idVAR, name); |
IF parser.sym = SCAN.lxCOMMA THEN |
ExpectSym(parser, SCAN.lxIDENT) |
ELSIF parser.sym = SCAN.lxCOLON THEN |
Next(parser); |
_type(parser, t, {}); |
PROG.setVarsType(parser.unit, t); |
checklex(parser, SCAN.lxSEMI); |
Next(parser) |
ELSE |
checklex(parser, SCAN.lxCOLON) |
END |
UNTIL parser.sym # SCAN.lxIDENT |
END VarDeclaration; |
PROCEDURE DeclarationSequence (parser: PARSER): BOOLEAN; |
VAR |
ptr: PROG.FRWPTR; |
endmod: BOOLEAN; |
pos: POSITION; |
PROCEDURE ProcDeclaration (parser: PARSER): BOOLEAN; |
VAR |
proc: PROG.IDENT; |
endname, |
name: SCAN.IDENT; |
param: PROG.PARAM; |
unit: PROG.UNIT; |
ident: PROG.IDENT; |
e: EXPR; |
pos, pos1, |
pos2: POSITION; |
label: INTEGER; |
enter: IL.COMMAND; |
call: INTEGER; |
t: PROG._TYPE; |
_import: IL.IMPORT_PROC; |
endmod, b: BOOLEAN; |
fparams: SET; |
int, flt: INTEGER; |
comma: BOOLEAN; |
code, iv: ARITH.VALUE; |
codeProc, |
handler: BOOLEAN; |
line: INTEGER; |
BEGIN |
endmod := FALSE; |
handler := FALSE; |
unit := parser.unit; |
call := procflag(parser, _import, TRUE); |
getpos(parser, pos); |
pos1 := pos; |
checklex(parser, SCAN.lxIDENT); |
line := pos.line; |
IF _import # NIL THEN |
proc := IdentDef(parser, PROG.idIMP, name); |
proc._import := _import; |
IF _import.name = "" THEN |
COPY(name.s, _import.name) |
END; |
PROG.program.procs.last(PROG.PROC)._import := _import |
ELSE |
proc := IdentDef(parser, PROG.idPROC, name) |
END; |
check(PROG.openScope(unit, proc.proc), pos, 116); |
proc._type := PROG.enterType(PROG.tPROCEDURE, TARGETS.AdrSize, 0, unit); |
t := proc._type; |
t.align := TARGETS.AdrSize; |
t.call := call; |
FormalParameters(parser, t); |
IF parser.sym = SCAN.lxLSQUARE THEN |
getpos(parser, pos2); |
check((TARGETS.CPU = TARGETS.cpuTHUMB) & (TARGETS.OS = TARGETS.osNONE), pos2, 24); |
Next(parser); |
getpos(parser, pos2); |
ConstExpression(parser, iv); |
check(iv.typ = ARITH.tINTEGER, pos2, 43); |
check((0 <= ARITH.Int(iv)) & (ARITH.Int(iv) <= THUMB.maxIVT), pos2, 46); |
check(THUMB.SetIV(ARITH.Int(iv)), pos2, 121); |
checklex(parser, SCAN.lxRSQUARE); |
Next(parser); |
handler := TRUE |
END; |
codeProc := call IN {PROG.code, PROG._code}; |
IF call IN {PROG.systemv, PROG._systemv} THEN |
check(t.parSize <= PROG.MAXSYSVPARAM, pos, 120) |
END; |
param := t.params.first(PROG.PARAM); |
WHILE param # NIL DO |
ident := PROG.addIdent(unit, param.name, PROG.idPARAM); |
ASSERT(ident # NIL); |
ident._type := param._type; |
ident.offset := param.offset; |
IF param.vPar THEN |
ident.typ := PROG.idVPAR |
END; |
param := param.next(PROG.PARAM) |
END; |
IF _import = NIL THEN |
label := IL.NewLabel(); |
proc.proc.label := label; |
proc.proc.used := handler; |
IF handler THEN |
IL.AddCmd2(IL.opHANDLER, label, ARITH.Int(iv)) |
END |
END; |
IF codeProc THEN |
enter := IL.EnterC(label); |
comma := FALSE; |
WHILE (parser.sym # SCAN.lxSEMI) OR comma DO |
getpos(parser, pos2); |
ConstExpression(parser, code); |
check(code.typ = ARITH.tINTEGER, pos2, 43); |
IF TARGETS.WordSize > TARGETS.InstrSize THEN |
CASE TARGETS.InstrSize OF |
|1: check(ARITH.range(code, 0, 255), pos, 42) |
|2: check(ARITH.range(code, 0, 65535), pos, 110) |
END |
END; |
IL.AddCmd(IL.opCODE, ARITH.getInt(code)); |
comma := parser.sym = SCAN.lxCOMMA; |
IF comma THEN |
Next(parser) |
ELSE |
checklex(parser, SCAN.lxSEMI) |
END |
END |
END; |
checklex(parser, SCAN.lxSEMI); |
Next(parser); |
IF _import = NIL THEN |
IF parser.main & proc.export & TARGETS.Dll THEN |
IF TARGETS.target = TARGETS.KolibriOSDLL THEN |
check((proc.name.s # "lib_init") & (proc.name.s # "version"), pos, 114) |
END; |
IL.AddExp(label, proc.name.s); |
proc.proc.used := TRUE |
END; |
IF ~codeProc THEN |
b := DeclarationSequence(parser) |
END; |
PROG.ResetLocSize; |
IF call IN {PROG._win64, PROG.win64} THEN |
fparams := PROG.getFloatParamsPos(proc._type, 3, int, flt); |
enter := IL.Enter(label, LSL(ORD(fparams), 5) + MIN(proc._type.parSize, 4)) |
ELSIF call IN {PROG._systemv, PROG.systemv} THEN |
fparams := PROG.getFloatParamsPos(proc._type, PROG.MAXSYSVPARAM - 1, int, flt); |
enter := IL.Enter(label, -(LSL(ORD(fparams), 5) + proc._type.parSize)) |
ELSIF codeProc THEN |
ELSE |
enter := IL.Enter(label, 0) |
END; |
proc.proc.enter := enter; |
IF ~codeProc & (parser.sym = SCAN.lxBEGIN) THEN |
Next(parser); |
parser.StatSeq(parser) |
END; |
IF ~codeProc & (t.base # NIL) THEN |
checklex(parser, SCAN.lxRETURN); |
NextPos(parser, pos); |
parser.expression(parser, e); |
check(parser.chkreturn(parser, e, t.base, pos), pos, 87) |
END; |
IF ~codeProc THEN |
proc.proc.leave := IL.Leave(t.base # NIL, (t.base # NIL) & (t.base.typ = PROG.tREAL), PROG.program.locsize, |
t.parSize * ORD((t.call IN PROG.callee_clean_up) OR (t.call IN {PROG.systemv, PROG._systemv}))); |
enter.param2 := PROG.program.locsize; |
checklex(parser, SCAN.lxEND) |
ELSE |
proc.proc.leave := IL.LeaveC() |
END; |
IF (TARGETS.CPU = TARGETS.cpuMSP430) & ~codeProc THEN |
check(MSP430.CheckProcDataSize(enter.param2 + proc._type.parSize, PROG.program.options.ram), pos1, 63); |
enter.param2 := enter.param2 * 65536 + line; |
enter.param3 := IL.codes.errlabels[10] |
END |
END; |
IF parser.sym = SCAN.lxEND THEN |
Next(parser); |
IF parser.sym = SCAN.lxIDENT THEN |
getpos(parser, pos); |
endname := parser.lex.ident; |
IF ~codeProc & (_import = NIL) THEN |
check(PROG.IdEq(endname, name), pos, 60); |
ExpectSym(parser, SCAN.lxSEMI); |
Next(parser) |
ELSE |
IF PROG.IdEq(endname, parser.unit.name) THEN |
ExpectSym(parser, SCAN.lxPOINT); |
Next(parser); |
endmod := TRUE |
ELSIF PROG.IdEq(endname, name) THEN |
ExpectSym(parser, SCAN.lxSEMI); |
Next(parser) |
ELSE |
error(pos, 60) |
END |
END |
ELSIF parser.sym = SCAN.lxSEMI THEN |
Next(parser) |
ELSE |
checklex(parser, SCAN.lxIDENT) |
END |
END; |
PROG.closeScope(unit); |
RETURN endmod |
END ProcDeclaration; |
BEGIN |
IF parser.sym = SCAN.lxCONST THEN |
Next(parser); |
WHILE parser.sym = SCAN.lxIDENT DO |
ConstTypeDeclaration(parser, TRUE) |
END |
END; |
IF parser.sym = SCAN.lxTYPE THEN |
Next(parser); |
WHILE parser.sym = SCAN.lxIDENT DO |
ConstTypeDeclaration(parser, FALSE) |
END |
END; |
ptr := PROG.linkPtr(parser.unit); |
IF ptr # NIL THEN |
pos.line := ptr.pos.line; |
pos.col := ptr.pos.col; |
pos.parser := parser; |
IF ptr.notRecord THEN |
error(pos, 58) |
ELSE |
error(pos, 48) |
END |
END; |
IF parser.sym = SCAN.lxVAR THEN |
Next(parser); |
IF parser.sym = SCAN.lxIDENT THEN |
VarDeclaration(parser) |
END |
END; |
endmod := FALSE; |
WHILE ~endmod & (parser.sym = SCAN.lxPROCEDURE) DO |
Next(parser); |
endmod := ProcDeclaration(parser) |
END |
RETURN endmod |
END DeclarationSequence; |
PROCEDURE parse (parser: PARSER); |
VAR |
unit: PROG.UNIT; |
label: INTEGER; |
name: INTEGER; |
endmod: BOOLEAN; |
errlabel: INTEGER; |
errno: INTEGER; |
BEGIN |
ASSERT(parser # NIL); |
ASSERT(parser.scanner # NIL); |
ExpectSym(parser, SCAN.lxMODULE); |
ExpectSym(parser, SCAN.lxIDENT); |
IF ~parser.main THEN |
check1(parser.lex.ident.s = parser.modname, parser, 23) |
END; |
unit := PROG.newUnit(parser.lex.ident); |
unit.fname := parser.fname; |
parser.unit := unit; |
ExpectSym(parser, SCAN.lxSEMI); |
Next(parser); |
IF parser.sym = SCAN.lxIMPORT THEN |
ImportList(parser) |
END; |
INC(modules); |
CONSOLE.String("compiling "); |
CONSOLE.String("("); CONSOLE.Int(modules); CONSOLE.String(") "); |
CONSOLE.String(unit.name.s); |
IF parser.unit.sysimport THEN |
CONSOLE.String(" (SYSTEM)") |
END; |
CONSOLE.Ln; |
IF TARGETS.CPU IN {TARGETS.cpuX86, TARGETS.cpuAMD64} THEN |
IL.fname(parser.fname) |
END; |
label := IL.NewLabel(); |
IL.Jmp(IL.opJMP, label); |
name := IL.putstr(unit.name.s); |
errlabel := IL.NewLabel(); |
IL.SetLabel(errlabel); |
IL.StrAdr(name); |
IL.Param1; |
IL.AddCmd(IL.opPUSHC, modules); |
IL.AddCmd0(IL.opERR); |
FOR errno := 1 TO LEN(IL.codes.errlabels) - 1 DO |
IL.SetErrLabel(errno); |
IL.AddCmd(IL.opPUSHC, errno); |
IL.Jmp(IL.opJMP, errlabel) |
END; |
endmod := DeclarationSequence(parser); |
IL.SetLabel(label); |
IF ~endmod THEN |
IF parser.sym = SCAN.lxBEGIN THEN |
Next(parser); |
parser.StatSeq(parser) |
END; |
checklex(parser, SCAN.lxEND); |
ExpectSym(parser, SCAN.lxIDENT); |
check1(parser.lex.ident.s = unit.name.s, parser, 25); |
ExpectSym(parser, SCAN.lxPOINT) |
END; |
INC(lines, parser.lex.pos.line); |
PROG.closeUnit(unit) |
END parse; |
PROCEDURE open (parser: PARSER; modname, FileExt: ARRAY OF CHAR): BOOLEAN; |
BEGIN |
ASSERT(parser # NIL); |
STRINGS.append(parser.fname, modname); |
STRINGS.append(parser.fname, FileExt); |
STRINGS.append(parser.modname, modname); |
parser.scanner := SCAN.open(parser.fname) |
RETURN parser.scanner # NIL |
END open; |
PROCEDURE NewParser (): PARSER; |
VAR |
pars: PARSER; |
citem: C.ITEM; |
BEGIN |
citem := C.pop(parsers); |
IF citem = NIL THEN |
NEW(pars) |
ELSE |
pars := citem(PARSER) |
END |
RETURN pars |
END NewParser; |
PROCEDURE create* (path, lib_path: PATH; StatSeq: STATPROC; expression, designator: EXPRPROC; chkreturn: RETPROC): PARSER; |
VAR |
parser: PARSER; |
BEGIN |
parser := NewParser(); |
parser.path := path; |
parser.lib_path := lib_path; |
parser.ext := UTILS.FILE_EXT; |
parser.fname := path; |
parser.modname := ""; |
parser.scanner := NIL; |
parser.unit := NIL; |
parser.constexp := FALSE; |
parser.main := FALSE; |
parser.open := open; |
parser.parse := parse; |
parser.StatSeq := StatSeq; |
parser.expression := expression; |
parser.designator := designator; |
parser.chkreturn := chkreturn; |
parser.create := create |
RETURN parser |
END create; |
PROCEDURE init* (options: PROG.OPTIONS); |
BEGIN |
PROG.create(options); |
parsers := C.create(); |
lines := 0; |
modules := 0 |
END init; |
END PARS. |
/programs/develop/oberon07/source/PATHS.ob07 |
---|
0,0 → 1,151 |
(* |
BSD 2-Clause License |
Copyright (c) 2018-2021, Anton Krotov |
All rights reserved. |
*) |
MODULE PATHS; |
IMPORT STRINGS, UTILS; |
CONST |
slash = UTILS.slash; |
PATHLEN = 2048; |
TYPE |
PATH* = ARRAY PATHLEN OF CHAR; |
PROCEDURE split* (fname: ARRAY OF CHAR; VAR path, name, ext: ARRAY OF CHAR); |
VAR |
pos1, pos2, len: INTEGER; |
BEGIN |
len := LENGTH(fname); |
pos1 := len - 1; |
pos2 := pos1; |
STRINGS.search(fname, pos1, slash, FALSE); |
STRINGS.search(fname, pos2, ".", FALSE); |
path := fname; |
path[pos1 + 1] := 0X; |
IF (pos2 = -1) OR (pos2 < pos1) THEN |
pos2 := len |
END; |
INC(pos1); |
STRINGS.copy(fname, name, pos1, 0, pos2 - pos1); |
name[pos2 - pos1] := 0X; |
STRINGS.copy(fname, ext, pos2, 0, len - pos2); |
ext[len - pos2] := 0X |
END split; |
PROCEDURE RelPath* (absolute, relative: ARRAY OF CHAR; VAR res: ARRAY OF CHAR); |
VAR |
i, j: INTEGER; |
error: BOOLEAN; |
BEGIN |
COPY(absolute, res); |
i := LENGTH(res) - 1; |
WHILE (i >= 0) & (res[i] # slash) DO |
DEC(i) |
END; |
INC(i); |
res[i] := 0X; |
error := FALSE; |
j := 0; |
WHILE (relative[j] = ".") & (relative[j + 1] = slash) DO |
INC(j, 2) |
ELSIF relative[j] = slash DO |
INC(j) |
END; |
WHILE ~error & (relative[j] # 0X) DO |
IF (relative[j] = ".") & (relative[j + 1] = ".") & (relative[j + 2] = slash) & (i > 0) & (res[i - 1] = slash) THEN |
DEC(i, 2); |
WHILE (i >= 0) & (res[i] # slash) DO |
DEC(i) |
END; |
IF i < 0 THEN |
error := TRUE |
ELSE |
INC(i); |
INC(j, 3) |
END |
ELSE |
res[i] := relative[j]; |
INC(i); |
INC(j) |
END |
END; |
IF error THEN |
COPY(relative, res) |
ELSE |
res[i] := 0X |
END |
END RelPath; |
PROCEDURE DelSlashes* (VAR path: ARRAY OF CHAR); |
VAR |
i, j, k: INTEGER; |
c: CHAR; |
BEGIN |
i := 0; |
j := 0; |
k := 0; |
REPEAT |
c := path[j]; |
INC(j); |
IF c = slash THEN |
INC(k) |
ELSE |
k := 0 |
END; |
IF k <= 1 THEN |
path[i] := c; |
INC(i) |
END |
UNTIL c = 0X; |
i := 0; |
j := 0; |
REPEAT |
c := path[j]; |
INC(j); |
path[i] := c; |
INC(i); |
IF (c = slash) & (path[j] = ".") & (path[j + 1] = slash) THEN |
INC(j, 2) |
END |
UNTIL c = 0X |
END DelSlashes; |
PROCEDURE isRelative* (path: ARRAY OF CHAR): BOOLEAN; |
RETURN UTILS.isRelative(path) |
END isRelative; |
PROCEDURE GetCurrentDirectory* (VAR path: ARRAY OF CHAR); |
BEGIN |
UTILS.GetCurrentDirectory(path) |
END GetCurrentDirectory; |
END PATHS. |
/programs/develop/oberon07/source/PROG.ob07 |
---|
0,0 → 1,1271 |
(* |
BSD 2-Clause License |
Copyright (c) 2018-2021, Anton Krotov |
All rights reserved. |
*) |
MODULE PROG; |
IMPORT SCAN, LISTS, ARITH, ERRORS, C := COLLECTIONS, IL, UTILS, TARGETS, STRINGS, PATHS; |
CONST |
MAXARRDIM* = 5; |
MAXSCOPE = 16; |
MAXSYSVPARAM* = 26; |
idNONE* = 0; idGUARD = 1; idMODULE* = 2; idCONST* = 3; |
idTYPE* = 4; idSTFUNC* = 5; idSTPROC* = 6; idVAR* = 7; |
idPROC* = 8; idVPAR* = 9; idPARAM* = 10; idSYSFUNC* = 11; |
idSYSPROC* = 12; idIMP* = 13; |
tINTEGER* = 1; tBYTE* = 2; tCHAR* = 3; tSET* = 4; |
tBOOLEAN* = 5; tREAL* = 6; tARRAY* = 7; tRECORD* = 8; |
tPOINTER* = 9; tPROCEDURE* = 10; tSTRING* = 11; tNIL* = 12; |
tCARD32* = 13; tANYREC* = 14; tWCHAR* = 15; tNONE* = 16; |
BASICTYPES* = {tINTEGER, tBYTE, tCHAR, tSET, tBOOLEAN, tREAL, tCARD32, tWCHAR}; |
stABS* = 1; stASR* = 2; stCHR* = 3; stFLOOR* = 4; |
stFLT* = 5; stLEN* = 6; stLSL* = 7; stODD* = 8; |
stORD* = 9; stROR* = 10; stASSERT* = 11; stDEC* = 12; |
stEXCL* = 13; stINC* = 14; stINCL* = 15; stNEW* = 16; |
stPACK* = 17; stUNPK* = 18; sysADR* = 19; sysSIZE* = 20; |
sysGET* = 21; sysPUT* = 22; |
stDISPOSE* = 23; stLSR* = 24; stBITS* = 25; sysCODE* = 26; |
sysMOVE* = 27; stLENGTH* = 28; stMIN* = 29; stMAX* = 30; |
sysSADR* = 31; sysTYPEID* = 32; sysCOPY* = 33; sysINF* = 34; |
sysPUT8* = 35; sysPUT16* = 36; stCOPY* = 37; stWCHR* = 38; |
sysWSADR* = 39; sysPUT32* = 40; (*sysNOP* = 41; sysEINT* = 42; |
sysDINT* = 43;*)sysGET8* = 44; sysGET16* = 45; sysGET32* = 46; |
default32* = 2; _default32* = default32 + 1; |
stdcall* = 4; _stdcall* = stdcall + 1; |
cdecl* = 6; _cdecl* = cdecl + 1; |
ccall* = 8; _ccall* = ccall + 1; |
win64* = 10; _win64* = win64 + 1; |
default64* = 12; _default64* = default64 + 1; |
systemv* = 14; _systemv* = systemv + 1; |
default16* = 16; _default16* = default16 + 1; |
code* = 18; _code* = code + 1; |
noalign* = 22; |
callee_clean_up* = {default32, _default32, stdcall, _stdcall, default64, _default64}; |
sf_stdcall* = 0; sf_oberon* = 1; sf_cdecl* = 2; sf_ccall* = 3; |
sf_win64* = 4; sf_systemv* = 5; sf_windows* = 6; sf_linux* = 7; |
sf_code* = 8; |
sf_noalign* = 9; |
proc_flags* = {sf_stdcall, sf_cdecl, sf_ccall, sf_win64, sf_systemv, sf_windows, sf_linux, sf_code, sf_oberon}; |
rec_flags* = {sf_noalign}; |
STACK_FRAME = 2; |
TYPE |
OPTIONS* = RECORD |
version*, stack*, ram*, rom*: INTEGER; |
pic*, lower*: BOOLEAN; |
checking*: SET |
END; |
IDENT* = POINTER TO rIDENT; |
UNIT* = POINTER TO rUNIT; |
_TYPE* = POINTER TO rTYPE; |
FRWPTR* = POINTER TO RECORD (LISTS.ITEM) |
_type: _TYPE; |
baseIdent: SCAN.IDENT; |
linked: BOOLEAN; |
pos*: SCAN.POSITION; |
notRecord*: BOOLEAN |
END; |
PROC* = POINTER TO RECORD (LISTS.ITEM) |
label*: INTEGER; |
used*: BOOLEAN; |
processed*: BOOLEAN; |
_import*: LISTS.ITEM; |
using*: LISTS.LIST; |
enter*, |
leave*: LISTS.ITEM |
END; |
USED_PROC = POINTER TO RECORD (LISTS.ITEM) |
proc: PROC |
END; |
rUNIT = RECORD (LISTS.ITEM) |
fname*: PATHS.PATH; |
name*: SCAN.IDENT; |
idents*: LISTS.LIST; |
frwPointers: LISTS.LIST; |
gscope: IDENT; |
closed*: BOOLEAN; |
scopeLvl*: INTEGER; |
sysimport*: BOOLEAN; |
scopes*: ARRAY MAXSCOPE OF PROC |
END; |
FIELD* = POINTER TO rFIELD; |
PARAM* = POINTER TO rPARAM; |
rTYPE = RECORD (LISTS.ITEM) |
typ*: INTEGER; |
size*: INTEGER; |
parSize*: INTEGER; |
length*: INTEGER; |
align*: INTEGER; |
base*: _TYPE; |
fields*: LISTS.LIST; |
params*: LISTS.LIST; |
unit*: UNIT; |
closed*: BOOLEAN; |
num*: INTEGER; |
call*: INTEGER; |
_import*: BOOLEAN; |
noalign*: BOOLEAN |
END; |
rFIELD = RECORD (LISTS.ITEM) |
_type*: _TYPE; |
name*: SCAN.IDENT; |
export*: BOOLEAN; |
offset*: INTEGER |
END; |
rPARAM = RECORD (LISTS.ITEM) |
name*: SCAN.IDENT; |
_type*: _TYPE; |
vPar*: BOOLEAN; |
offset*: INTEGER |
END; |
rIDENT = RECORD (LISTS.ITEM) |
name*: SCAN.IDENT; |
typ*: INTEGER; |
export*: BOOLEAN; |
_import*: LISTS.ITEM; |
unit*: UNIT; |
value*: ARITH.VALUE; |
_type*: _TYPE; |
stproc*: INTEGER; |
global*: BOOLEAN; |
scopeLvl*: INTEGER; |
offset*: INTEGER; |
proc*: PROC; |
pos*: SCAN.POSITION |
END; |
PROGRAM = RECORD |
recCount: INTEGER; |
units*: LISTS.LIST; |
types*: LISTS.LIST; |
sysunit*: UNIT; |
rtl*: UNIT; |
bss*: INTEGER; |
locsize*: INTEGER; |
procs*: LISTS.LIST; |
sysflags*: SET; |
options*: OPTIONS; |
stTypes*: RECORD |
tINTEGER*, tBYTE*, tCHAR*, tWCHAR*, tSET*, tBOOLEAN*, tREAL*, |
tSTRING*, tNIL*, tCARD32*, tANYREC*, tNONE*: _TYPE |
END |
END; |
DELIMPORT = PROCEDURE (_import: LISTS.ITEM); |
VAR |
LowerCase*: BOOLEAN; |
idents: C.COLLECTION; |
program*: PROGRAM; |
PROCEDURE NewIdent (): IDENT; |
VAR |
ident: IDENT; |
citem: C.ITEM; |
BEGIN |
citem := C.pop(idents); |
IF citem = NIL THEN |
NEW(ident) |
ELSE |
ident := citem(IDENT) |
END |
RETURN ident |
END NewIdent; |
PROCEDURE getOffset* (varIdent: IDENT): INTEGER; |
VAR |
size: INTEGER; |
BEGIN |
IF varIdent.offset = -1 THEN |
size := varIdent._type.size; |
IF varIdent.global THEN |
IF UTILS.Align(program.bss, varIdent._type.align) THEN |
IF UTILS.maxint - program.bss >= size THEN |
varIdent.offset := program.bss; |
INC(program.bss, size) |
END |
END |
ELSE |
IF UTILS.Align(size, TARGETS.WordSize) THEN |
size := size DIV TARGETS.WordSize; |
IF UTILS.maxint - program.locsize >= size THEN |
INC(program.locsize, size); |
varIdent.offset := program.locsize |
END |
END |
END; |
IF varIdent.offset = -1 THEN |
ERRORS.Error(204) |
END |
END |
RETURN varIdent.offset |
END getOffset; |
PROCEDURE closeUnit* (unit: UNIT); |
VAR |
ident, prev: IDENT; |
offset: INTEGER; |
BEGIN |
ident := unit.idents.last(IDENT); |
WHILE (ident # NIL) & (ident.typ # idGUARD) DO |
IF (ident.typ = idVAR) & (ident.offset = -1) THEN |
ERRORS.HintMsg(ident.name.s, ident.pos.line, ident.pos.col, 0); |
IF ident.export THEN |
offset := getOffset(ident) |
END |
END; |
ident := ident.prev(IDENT) |
END; |
ident := unit.idents.last(IDENT); |
WHILE ident # NIL DO |
prev := ident.prev(IDENT); |
IF ~ident.export THEN |
LISTS.delete(unit.idents, ident); |
C.push(idents, ident) |
END; |
ident := prev |
END; |
unit.closed := TRUE |
END closeUnit; |
PROCEDURE IdEq* (a, b: SCAN.IDENT): BOOLEAN; |
RETURN (a.hash = b.hash) & (a.s = b.s) |
END IdEq; |
PROCEDURE unique (unit: UNIT; ident: SCAN.IDENT): BOOLEAN; |
VAR |
item: IDENT; |
BEGIN |
item := unit.idents.last(IDENT); |
WHILE (item.typ # idGUARD) & ~IdEq(item.name, ident) DO |
item := item.prev(IDENT) |
END |
RETURN item.typ = idGUARD |
END unique; |
PROCEDURE addIdent* (unit: UNIT; ident: SCAN.IDENT; typ: INTEGER): IDENT; |
VAR |
item: IDENT; |
res: BOOLEAN; |
proc: PROC; |
BEGIN |
ASSERT(unit # NIL); |
res := unique(unit, ident); |
IF res THEN |
item := NewIdent(); |
item.name := ident; |
item.typ := typ; |
item.unit := NIL; |
item.export := FALSE; |
item._import := NIL; |
item._type := NIL; |
item.value.typ := 0; |
item.stproc := 0; |
item.global := unit.scopeLvl = 0; |
item.scopeLvl := unit.scopeLvl; |
item.offset := -1; |
IF item.typ IN {idPROC, idIMP} THEN |
NEW(proc); |
proc._import := NIL; |
proc.label := 0; |
proc.used := FALSE; |
proc.processed := FALSE; |
proc.using := LISTS.create(NIL); |
LISTS.push(program.procs, proc); |
item.proc := proc |
END; |
LISTS.push(unit.idents, item) |
ELSE |
item := NIL |
END |
RETURN item |
END addIdent; |
PROCEDURE UseProc* (unit: UNIT; call_proc: PROC); |
VAR |
procs: LISTS.LIST; |
cur: LISTS.ITEM; |
proc: USED_PROC; |
BEGIN |
IF unit.scopeLvl = 0 THEN |
call_proc.used := TRUE |
ELSE |
procs := unit.scopes[unit.scopeLvl].using; |
cur := procs.first; |
WHILE (cur # NIL) & (cur(USED_PROC).proc # call_proc) DO |
cur := cur.next |
END; |
IF cur = NIL THEN |
NEW(proc); |
proc.proc := call_proc; |
LISTS.push(procs, proc) |
END |
END |
END UseProc; |
PROCEDURE setVarsType* (unit: UNIT; _type: _TYPE); |
VAR |
item: IDENT; |
BEGIN |
ASSERT(_type # NIL); |
item := unit.idents.last(IDENT); |
WHILE (item # NIL) & (item.typ = idVAR) & (item._type = NIL) DO |
item._type := _type; |
item := item.prev(IDENT) |
END |
END setVarsType; |
PROCEDURE getIdent* (unit: UNIT; ident: SCAN.IDENT; currentScope: BOOLEAN): IDENT; |
VAR |
item: IDENT; |
BEGIN |
item := unit.idents.last(IDENT); |
IF item # NIL THEN |
IF currentScope THEN |
WHILE (item.typ # idGUARD) & ~IdEq(item.name, ident) DO |
item := item.prev(IDENT) |
END; |
IF item.typ = idGUARD THEN |
item := NIL |
END |
ELSE |
WHILE (item # NIL) & ~IdEq(item.name, ident) DO |
item := item.prev(IDENT) |
END |
END |
END |
RETURN item |
END getIdent; |
PROCEDURE openScope* (unit: UNIT; proc: PROC): BOOLEAN; |
VAR |
item: IDENT; |
res: BOOLEAN; |
BEGIN |
INC(unit.scopeLvl); |
res := unit.scopeLvl < MAXSCOPE; |
IF res THEN |
unit.scopes[unit.scopeLvl] := proc; |
NEW(item); |
item := NewIdent(); |
item.name.s := ""; |
item.name.hash := 0; |
item.typ := idGUARD; |
LISTS.push(unit.idents, item) |
END |
RETURN res |
END openScope; |
PROCEDURE closeScope* (unit: UNIT); |
VAR |
item: IDENT; |
del: IDENT; |
BEGIN |
item := unit.idents.last(IDENT); |
WHILE (item # NIL) & (item.typ # idGUARD) DO |
del := item; |
item := item.prev(IDENT); |
IF (del.typ = idVAR) & (del.offset = -1) THEN |
ERRORS.HintMsg(del.name.s, del.pos.line, del.pos.col, 0) |
END; |
LISTS.delete(unit.idents, del); |
C.push(idents, del) |
END; |
IF (item # NIL) & (item.typ = idGUARD) THEN |
LISTS.delete(unit.idents, item); |
C.push(idents, item) |
END; |
DEC(unit.scopeLvl) |
END closeScope; |
PROCEDURE frwPtr* (unit: UNIT; _type: _TYPE; baseIdent: SCAN.IDENT; pos: SCAN.POSITION); |
VAR |
newptr: FRWPTR; |
BEGIN |
ASSERT(unit # NIL); |
ASSERT(_type # NIL); |
NEW(newptr); |
newptr._type := _type; |
newptr.baseIdent := baseIdent; |
newptr.pos := pos; |
newptr.linked := FALSE; |
newptr.notRecord := FALSE; |
LISTS.push(unit.frwPointers, newptr) |
END frwPtr; |
PROCEDURE linkPtr* (unit: UNIT): FRWPTR; |
VAR |
item: FRWPTR; |
ident: IDENT; |
res: FRWPTR; |
BEGIN |
res := NIL; |
item := unit.frwPointers.last(FRWPTR); |
WHILE (item # NIL) & ~item.linked & (res = NIL) DO |
ident := getIdent(unit, item.baseIdent, TRUE); |
IF (ident # NIL) THEN |
IF (ident.typ = idTYPE) & (ident._type.typ = tRECORD) THEN |
item._type.base := ident._type; |
item.linked := TRUE |
ELSE |
item.notRecord := TRUE; |
res := item |
END |
ELSE |
item.notRecord := FALSE; |
res := item |
END; |
item := item.prev(FRWPTR) |
END |
RETURN res |
END linkPtr; |
PROCEDURE isTypeEq* (t1, t2: _TYPE): BOOLEAN; |
VAR |
res: BOOLEAN; |
param1, param2: LISTS.ITEM; |
BEGIN |
IF t1 = t2 THEN |
res := TRUE |
ELSIF (t1 = NIL) OR (t2 = NIL) THEN |
res := FALSE |
ELSIF (t1.typ = tPROCEDURE) & (t2.typ = tPROCEDURE) THEN |
param1 := t1.params.first; |
param2 := t2.params.first; |
res := ((t1.call = t2.call) OR (t1.call IN {code, _code}) OR (t2.call IN {code, _code})) & ((param1 # NIL) = (param2 # NIL)); |
WHILE res & (param1 # NIL) & (param2 # NIL) DO |
res := (param1(PARAM).vPar = param2(PARAM).vPar) & isTypeEq(param1(PARAM)._type, param2(PARAM)._type); |
param1 := param1.next; |
param2 := param2.next; |
res := res & ((param1 # NIL) = (param2 # NIL)) |
END; |
res := res & isTypeEq(t1.base, t2.base) |
ELSIF (t1.typ = tARRAY) & (t2.typ = tARRAY) THEN |
res := (t1.length = 0) & (t2.length = 0) & isTypeEq(t1.base, t2.base) |
ELSE |
res := FALSE |
END |
RETURN res |
END isTypeEq; |
PROCEDURE isBaseOf* (t0, t1: _TYPE): BOOLEAN; |
VAR |
res: BOOLEAN; |
BEGIN |
res := (t0.typ = t1.typ) & (t0.typ IN {tPOINTER, tRECORD}); |
IF res & (t0.typ = tPOINTER) THEN |
t0 := t0.base; |
t1 := t1.base |
END; |
IF res THEN |
WHILE (t1 # NIL) & (t1 # t0) DO |
t1 := t1.base |
END; |
res := t1 # NIL |
END |
RETURN res |
END isBaseOf; |
PROCEDURE isOpenArray* (t: _TYPE): BOOLEAN; |
RETURN (t.typ = tARRAY) & (t.length = 0) |
END isOpenArray; |
PROCEDURE arrcomp* (src, dst: _TYPE): BOOLEAN; |
RETURN (dst.typ = tARRAY) & isOpenArray(src) & |
~isOpenArray(src.base) & ~isOpenArray(dst.base) & |
isTypeEq(src.base, dst.base) |
END arrcomp; |
PROCEDURE getUnit* (name: PATHS.PATH): UNIT; |
VAR |
item: UNIT; |
BEGIN |
item := program.units.first(UNIT); |
WHILE (item # NIL) & (item.fname # name) DO |
item := item.next(UNIT) |
END; |
IF (item = NIL) & ((name = "SYSTEM") OR LowerCase & (name = "system")) THEN |
item := program.sysunit |
END |
RETURN item |
END getUnit; |
PROCEDURE enterStTypes (unit: UNIT); |
PROCEDURE enter (unit: UNIT; nameStr: SCAN.IDSTR; _type: _TYPE); |
VAR |
ident: IDENT; |
upper: SCAN.IDSTR; |
name: SCAN.IDENT; |
BEGIN |
IF LowerCase THEN |
SCAN.setIdent(name, nameStr); |
ident := addIdent(unit, name, idTYPE); |
ident._type := _type |
END; |
upper := nameStr; |
STRINGS.UpCase(upper); |
SCAN.setIdent(name, upper); |
ident := addIdent(unit, name, idTYPE); |
ident._type := _type |
END enter; |
BEGIN |
enter(unit, "integer", program.stTypes.tINTEGER); |
enter(unit, "byte", program.stTypes.tBYTE); |
enter(unit, "char", program.stTypes.tCHAR); |
enter(unit, "set", program.stTypes.tSET); |
enter(unit, "boolean", program.stTypes.tBOOLEAN); |
IF TARGETS.RealSize # 0 THEN |
enter(unit, "real", program.stTypes.tREAL) |
END; |
IF TARGETS.BitDepth >= 32 THEN |
enter(unit, "wchar", program.stTypes.tWCHAR) |
END |
END enterStTypes; |
PROCEDURE enterStProcs (unit: UNIT); |
PROCEDURE Enter (unit: UNIT; nameStr: SCAN.IDSTR; nfunc, tfunc: INTEGER); |
VAR |
ident: IDENT; |
upper: SCAN.IDSTR; |
name: SCAN.IDENT; |
BEGIN |
IF LowerCase THEN |
SCAN.setIdent(name, nameStr); |
ident := addIdent(unit, name, tfunc); |
ident.stproc := nfunc; |
ident._type := program.stTypes.tNONE |
END; |
upper := nameStr; |
STRINGS.UpCase(upper); |
SCAN.setIdent(name, upper); |
ident := addIdent(unit, name, tfunc); |
ident.stproc := nfunc; |
ident._type := program.stTypes.tNONE |
END Enter; |
BEGIN |
Enter(unit, "assert", stASSERT, idSTPROC); |
Enter(unit, "dec", stDEC, idSTPROC); |
Enter(unit, "excl", stEXCL, idSTPROC); |
Enter(unit, "inc", stINC, idSTPROC); |
Enter(unit, "incl", stINCL, idSTPROC); |
Enter(unit, "new", stNEW, idSTPROC); |
Enter(unit, "copy", stCOPY, idSTPROC); |
Enter(unit, "abs", stABS, idSTFUNC); |
Enter(unit, "asr", stASR, idSTFUNC); |
Enter(unit, "chr", stCHR, idSTFUNC); |
Enter(unit, "len", stLEN, idSTFUNC); |
Enter(unit, "lsl", stLSL, idSTFUNC); |
Enter(unit, "odd", stODD, idSTFUNC); |
Enter(unit, "ord", stORD, idSTFUNC); |
Enter(unit, "ror", stROR, idSTFUNC); |
Enter(unit, "bits", stBITS, idSTFUNC); |
Enter(unit, "lsr", stLSR, idSTFUNC); |
Enter(unit, "length", stLENGTH, idSTFUNC); |
Enter(unit, "min", stMIN, idSTFUNC); |
Enter(unit, "max", stMAX, idSTFUNC); |
IF TARGETS.RealSize # 0 THEN |
Enter(unit, "pack", stPACK, idSTPROC); |
Enter(unit, "unpk", stUNPK, idSTPROC); |
Enter(unit, "floor", stFLOOR, idSTFUNC); |
Enter(unit, "flt", stFLT, idSTFUNC) |
END; |
IF TARGETS.BitDepth >= 32 THEN |
Enter(unit, "wchr", stWCHR, idSTFUNC) |
END; |
IF TARGETS.Dispose THEN |
Enter(unit, "dispose", stDISPOSE, idSTPROC) |
END |
END enterStProcs; |
PROCEDURE newUnit* (name: SCAN.IDENT): UNIT; |
VAR |
unit: UNIT; |
BEGIN |
NEW(unit); |
unit.name := name; |
unit.closed := FALSE; |
unit.idents := LISTS.create(NIL); |
unit.frwPointers := LISTS.create(NIL); |
ASSERT(openScope(unit, NIL)); |
enterStTypes(unit); |
enterStProcs(unit); |
ASSERT(openScope(unit, NIL)); |
unit.gscope := unit.idents.last(IDENT); |
LISTS.push(program.units, unit); |
unit.scopeLvl := 0; |
unit.scopes[0] := NIL; |
unit.sysimport := FALSE; |
IF unit.name.s = UTILS.RTL_NAME THEN |
program.rtl := unit |
END |
RETURN unit |
END newUnit; |
PROCEDURE getField* (self: _TYPE; name: SCAN.IDENT; unit: UNIT): FIELD; |
VAR |
field: FIELD; |
BEGIN |
ASSERT(self # NIL); |
ASSERT(unit # NIL); |
field := NIL; |
WHILE (self # NIL) & (field = NIL) DO |
field := self.fields.first(FIELD); |
WHILE (field # NIL) & ~IdEq(field.name, name) DO |
field := field.next(FIELD) |
END; |
IF field = NIL THEN |
self := self.base |
END |
END; |
IF (field # NIL) & (self.unit # unit) & ~field.export THEN |
field := NIL |
END |
RETURN field |
END getField; |
PROCEDURE addField* (self: _TYPE; name: SCAN.IDENT; export: BOOLEAN): BOOLEAN; |
VAR |
field: FIELD; |
res: BOOLEAN; |
BEGIN |
res := getField(self, name, self.unit) = NIL; |
IF res THEN |
NEW(field); |
field.name := name; |
field.export := export; |
field._type := NIL; |
field.offset := self.size; |
LISTS.push(self.fields, field) |
END |
RETURN res |
END addField; |
PROCEDURE setFields* (self: _TYPE; _type: _TYPE): BOOLEAN; |
VAR |
item: FIELD; |
res: BOOLEAN; |
BEGIN |
ASSERT(_type # NIL); |
item := self.fields.first(FIELD); |
WHILE (item # NIL) & (item._type # NIL) DO |
item := item.next(FIELD) |
END; |
res := TRUE; |
WHILE res & (item # NIL) & (item._type = NIL) DO |
item._type := _type; |
IF ~self.noalign THEN |
res := UTILS.Align(self.size, _type.align) |
ELSE |
res := TRUE |
END; |
item.offset := self.size; |
res := res & (UTILS.maxint - self.size >= _type.size); |
IF res THEN |
INC(self.size, _type.size) |
END; |
item := item.next(FIELD) |
END |
RETURN res |
END setFields; |
PROCEDURE getParam* (self: _TYPE; name: SCAN.IDENT): PARAM; |
VAR |
item: PARAM; |
BEGIN |
item := self.params.first(PARAM); |
WHILE (item # NIL) & ~IdEq(item.name, name) DO |
item := item.next(PARAM) |
END |
RETURN item |
END getParam; |
PROCEDURE addParam* (self: _TYPE; name: SCAN.IDENT; vPar: BOOLEAN): BOOLEAN; |
VAR |
param: PARAM; |
res: BOOLEAN; |
BEGIN |
res := getParam(self, name) = NIL; |
IF res THEN |
NEW(param); |
param.name := name; |
param._type := NIL; |
param.vPar := vPar; |
LISTS.push(self.params, param) |
END |
RETURN res |
END addParam; |
PROCEDURE Dim* (t: _TYPE): INTEGER; |
VAR |
res: INTEGER; |
BEGIN |
res := 0; |
WHILE isOpenArray(t) DO |
t := t.base; |
INC(res) |
END |
RETURN res |
END Dim; |
PROCEDURE OpenBase* (t: _TYPE): _TYPE; |
BEGIN |
WHILE isOpenArray(t) DO t := t.base END |
RETURN t |
END OpenBase; |
PROCEDURE getFloatParamsPos* (self: _TYPE; maxoffs: INTEGER; VAR int, flt: INTEGER): SET; |
VAR |
res: SET; |
param: PARAM; |
BEGIN |
res := {}; |
int := 0; |
flt := 0; |
param := self.params.first(PARAM); |
WHILE (param # NIL) & (param.offset <= maxoffs + STACK_FRAME) DO |
IF ~param.vPar & (param._type.typ = tREAL) THEN |
INCL(res, param.offset - STACK_FRAME); |
INC(flt) |
END; |
param := param.next(PARAM) |
END; |
int := self.parSize - flt |
RETURN res |
END getFloatParamsPos; |
PROCEDURE setParams* (self: _TYPE; _type: _TYPE); |
VAR |
item: LISTS.ITEM; |
param: PARAM; |
word, size: INTEGER; |
BEGIN |
ASSERT(_type # NIL); |
word := UTILS.target.bit_depth DIV 8; |
item := self.params.first; |
WHILE (item # NIL) & (item(PARAM)._type # NIL) DO |
item := item.next |
END; |
WHILE (item # NIL) & (item(PARAM)._type = NIL) DO |
param := item(PARAM); |
param._type := _type; |
IF param.vPar THEN |
IF _type.typ = tRECORD THEN |
size := 2 |
ELSIF isOpenArray(_type) THEN |
size := Dim(_type) + 1 |
ELSE |
size := 1 |
END; |
param.offset := self.parSize + ORD(_type.typ = tRECORD) + Dim(_type) + STACK_FRAME; |
INC(self.parSize, size) |
ELSE |
IF _type.typ IN {tRECORD, tARRAY} THEN |
IF isOpenArray(_type) THEN |
size := Dim(_type) + 1 |
ELSE |
size := 1 |
END |
ELSE |
size := _type.size; |
ASSERT(UTILS.Align(size, word)); |
size := size DIV word |
END; |
param.offset := self.parSize + Dim(_type) + STACK_FRAME; |
INC(self.parSize, size) |
END; |
item := item.next |
END |
END setParams; |
PROCEDURE enterType* (typ, size, length: INTEGER; unit: UNIT): _TYPE; |
VAR |
t: _TYPE; |
BEGIN |
NEW(t); |
t.typ := typ; |
t.size := size; |
t.length := length; |
t.align := 0; |
t.base := NIL; |
t.fields := LISTS.create(NIL); |
t.params := LISTS.create(NIL); |
t.unit := unit; |
t.num := 0; |
CASE TARGETS.BitDepth OF |
|16: t.call := default16 |
|32: t.call := default32 |
|64: t.call := default64 |
END; |
t._import := FALSE; |
t.noalign := FALSE; |
t.parSize := 0; |
IF typ IN {tARRAY, tRECORD} THEN |
t.closed := FALSE; |
IF typ = tRECORD THEN |
INC(program.recCount); |
t.num := program.recCount |
END |
ELSE |
t.closed := TRUE |
END; |
LISTS.push(program.types, t) |
RETURN t |
END enterType; |
PROCEDURE getType* (typ: INTEGER): _TYPE; |
VAR |
res: _TYPE; |
BEGIN |
CASE typ OF |
|ARITH.tINTEGER: res := program.stTypes.tINTEGER |
|ARITH.tREAL: res := program.stTypes.tREAL |
|ARITH.tSET: res := program.stTypes.tSET |
|ARITH.tBOOLEAN: res := program.stTypes.tBOOLEAN |
|ARITH.tCHAR: res := program.stTypes.tCHAR |
|ARITH.tWCHAR: res := program.stTypes.tWCHAR |
|ARITH.tSTRING: res := program.stTypes.tSTRING |
END |
RETURN res |
END getType; |
PROCEDURE createSysUnit; |
VAR |
ident: IDENT; |
unit: UNIT; |
name: SCAN.IDENT; |
PROCEDURE EnterProc (sys: UNIT; nameStr: SCAN.IDSTR; idtyp, proc: INTEGER); |
VAR |
ident: IDENT; |
upper: SCAN.IDSTR; |
name: SCAN.IDENT; |
BEGIN |
IF LowerCase THEN |
SCAN.setIdent(name, nameStr); |
ident := addIdent(sys, name, idtyp); |
ident.stproc := proc; |
ident._type := program.stTypes.tNONE; |
ident.export := TRUE |
END; |
upper := nameStr; |
STRINGS.UpCase(upper); |
SCAN.setIdent(name, upper); |
ident := addIdent(sys, name, idtyp); |
ident.stproc := proc; |
ident._type := program.stTypes.tNONE; |
ident.export := TRUE |
END EnterProc; |
BEGIN |
SCAN.setIdent(name, "$SYSTEM"); |
unit := newUnit(name); |
unit.fname := "SYSTEM"; |
EnterProc(unit, "adr", idSYSFUNC, sysADR); |
EnterProc(unit, "size", idSYSFUNC, sysSIZE); |
EnterProc(unit, "sadr", idSYSFUNC, sysSADR); |
EnterProc(unit, "typeid", idSYSFUNC, sysTYPEID); |
EnterProc(unit, "get", idSYSPROC, sysGET); |
EnterProc(unit, "get8", idSYSPROC, sysGET8); |
EnterProc(unit, "put", idSYSPROC, sysPUT); |
EnterProc(unit, "put8", idSYSPROC, sysPUT8); |
EnterProc(unit, "code", idSYSPROC, sysCODE); |
EnterProc(unit, "move", idSYSPROC, sysMOVE); |
(* |
IF program.target.sys = mConst.Target_iMSP430 THEN |
EnterProc(unit, "nop", idSYSPROC, sysNOP); |
EnterProc(unit, "eint", idSYSPROC, sysEINT); |
EnterProc(unit, "dint", idSYSPROC, sysDINT) |
END; |
*) |
IF TARGETS.RealSize # 0 THEN |
EnterProc(unit, "inf", idSYSFUNC, sysINF); |
END; |
IF TARGETS.CPU IN {TARGETS.cpuX86, TARGETS.cpuAMD64} THEN |
EnterProc(unit, "copy", idSYSPROC, sysCOPY) |
END; |
IF TARGETS.BitDepth >= 32 THEN |
EnterProc(unit, "wsadr", idSYSFUNC, sysWSADR); |
EnterProc(unit, "put16", idSYSPROC, sysPUT16); |
EnterProc(unit, "put32", idSYSPROC, sysPUT32); |
EnterProc(unit, "get16", idSYSPROC, sysGET16); |
EnterProc(unit, "get32", idSYSPROC, sysGET32); |
IF LowerCase THEN |
SCAN.setIdent(name, "card32"); |
ident := addIdent(unit, name, idTYPE); |
ident._type := program.stTypes.tCARD32; |
ident.export := TRUE |
END; |
SCAN.setIdent(name, "CARD32"); |
ident := addIdent(unit, name, idTYPE); |
ident._type := program.stTypes.tCARD32; |
ident.export := TRUE; |
END; |
closeUnit(unit); |
program.sysunit := unit |
END createSysUnit; |
PROCEDURE DelUnused* (DelImport: DELIMPORT); |
VAR |
proc: PROC; |
flag: BOOLEAN; |
PROCEDURE process (proc: PROC); |
VAR |
used_proc: LISTS.ITEM; |
BEGIN |
proc.processed := TRUE; |
used_proc := proc.using.first; |
WHILE used_proc # NIL DO |
used_proc(USED_PROC).proc.used := TRUE; |
used_proc := used_proc.next |
END |
END process; |
BEGIN |
REPEAT |
flag := FALSE; |
proc := program.procs.first(PROC); |
WHILE proc # NIL DO |
IF proc.used & ~proc.processed THEN |
process(proc); |
flag := TRUE |
END; |
proc := proc.next(PROC) |
END |
UNTIL ~flag; |
proc := program.procs.first(PROC); |
WHILE proc # NIL DO |
IF ~proc.used THEN |
IF proc._import = NIL THEN |
IL.delete2(proc.enter, proc.leave) |
ELSE |
DelImport(proc._import) |
END |
END; |
proc := proc.next(PROC) |
END |
END DelUnused; |
PROCEDURE ResetLocSize*; |
BEGIN |
program.locsize := 0 |
END ResetLocSize; |
PROCEDURE create* (options: OPTIONS); |
BEGIN |
LowerCase := options.lower; |
SCAN.init(options.lower); |
idents := C.create(); |
UTILS.SetBitDepth(TARGETS.BitDepth, TARGETS.RealSize = 8); |
program.options := options; |
CASE TARGETS.OS OF |
|TARGETS.osWIN32: program.sysflags := {sf_oberon, sf_windows, sf_stdcall, sf_cdecl, sf_ccall, sf_noalign} |
|TARGETS.osLINUX32: program.sysflags := {sf_oberon, sf_linux, sf_stdcall, sf_cdecl, sf_ccall, sf_noalign} |
|TARGETS.osKOS: program.sysflags := {sf_oberon, sf_stdcall, sf_cdecl, sf_ccall, sf_noalign} |
|TARGETS.osWIN64: program.sysflags := {sf_oberon, sf_windows, sf_win64, sf_systemv, sf_ccall, sf_noalign} |
|TARGETS.osLINUX64: program.sysflags := {sf_oberon, sf_linux, sf_win64, sf_systemv, sf_ccall, sf_noalign} |
|TARGETS.osNONE: program.sysflags := {sf_code} |
END; |
program.recCount := -1; |
program.bss := 0; |
program.units := LISTS.create(NIL); |
program.types := LISTS.create(NIL); |
program.procs := LISTS.create(NIL); |
program.stTypes.tINTEGER := enterType(tINTEGER, TARGETS.WordSize, 0, NIL); |
program.stTypes.tBYTE := enterType(tBYTE, 1, 0, NIL); |
program.stTypes.tCHAR := enterType(tCHAR, 1, 0, NIL); |
program.stTypes.tSET := enterType(tSET, TARGETS.WordSize, 0, NIL); |
program.stTypes.tBOOLEAN := enterType(tBOOLEAN, 1, 0, NIL); |
program.stTypes.tINTEGER.align := TARGETS.WordSize; |
program.stTypes.tBYTE.align := 1; |
program.stTypes.tCHAR.align := 1; |
program.stTypes.tSET.align := TARGETS.WordSize; |
program.stTypes.tBOOLEAN.align := 1; |
IF TARGETS.BitDepth >= 32 THEN |
program.stTypes.tWCHAR := enterType(tWCHAR, 2, 0, NIL); |
program.stTypes.tCARD32 := enterType(tCARD32, 4, 0, NIL); |
program.stTypes.tWCHAR.align := 2; |
program.stTypes.tCARD32.align := 4 |
END; |
IF TARGETS.RealSize # 0 THEN |
program.stTypes.tREAL := enterType(tREAL, TARGETS.RealSize, 0, NIL); |
program.stTypes.tREAL.align := TARGETS.RealSize |
END; |
program.stTypes.tSTRING := enterType(tSTRING, TARGETS.WordSize, 0, NIL); |
program.stTypes.tNIL := enterType(tNIL, TARGETS.WordSize, 0, NIL); |
program.stTypes.tNONE := enterType(tNONE, 0, 0, NIL); |
program.stTypes.tANYREC := enterType(tRECORD, 0, 0, NIL); |
program.stTypes.tANYREC.closed := TRUE; |
createSysUnit |
END create; |
END PROG. |
/programs/develop/oberon07/source/REG.ob07 |
---|
0,0 → 1,286 |
(* |
BSD 2-Clause License |
Copyright (c) 2018-2021, Anton Krotov |
All rights reserved. |
*) |
MODULE REG; |
CONST |
N = 16; |
R0* = 0; R1* = 1; R2* = 2; R3* = 3; |
R4* = 4; R5* = 5; R6* = 6; R7* = 7; |
R8* = 8; R9* = 9; R10* = 10; R11* = 11; |
R12* = 12; R13* = 13; R14* = 14; R15* = 15; |
TYPE |
OP1 = PROCEDURE (arg: INTEGER); |
OP2 = PROCEDURE (arg1, arg2: INTEGER); |
REGS* = RECORD |
regs*: SET; |
stk*: ARRAY N OF INTEGER; |
top*: INTEGER; |
pushed*: INTEGER; |
push, pop: OP1; |
mov, xch: OP2 |
END; |
PROCEDURE push (VAR R: REGS); |
VAR |
i, reg: INTEGER; |
BEGIN |
reg := R.stk[0]; |
INCL(R.regs, reg); |
R.push(reg); |
FOR i := 0 TO R.top - 1 DO |
R.stk[i] := R.stk[i + 1] |
END; |
DEC(R.top); |
INC(R.pushed) |
END push; |
PROCEDURE pop (VAR R: REGS; reg: INTEGER); |
VAR |
i: INTEGER; |
BEGIN |
FOR i := R.top + 1 TO 1 BY -1 DO |
R.stk[i] := R.stk[i - 1] |
END; |
R.stk[0] := reg; |
EXCL(R.regs, reg); |
R.pop(reg); |
INC(R.top); |
DEC(R.pushed) |
END pop; |
PROCEDURE InStk (R: REGS; reg: INTEGER): INTEGER; |
VAR |
i: INTEGER; |
BEGIN |
i := R.top; |
WHILE (i >= 0) & (R.stk[i] # reg) DO |
DEC(i) |
END |
RETURN i |
END InStk; |
PROCEDURE GetFreeReg (R: REGS): INTEGER; |
VAR |
i: INTEGER; |
BEGIN |
i := 0; |
WHILE (i < N) & ~(i IN R.regs) DO |
INC(i) |
END; |
IF i = N THEN |
i := -1 |
END |
RETURN i |
END GetFreeReg; |
PROCEDURE Put (VAR R: REGS; reg: INTEGER); |
BEGIN |
EXCL(R.regs, reg); |
INC(R.top); |
R.stk[R.top] := reg |
END Put; |
PROCEDURE PopAnyReg (VAR R: REGS): INTEGER; |
VAR |
reg: INTEGER; |
BEGIN |
reg := GetFreeReg(R); |
ASSERT(reg # -1); |
ASSERT(R.top < LEN(R.stk) - 1); |
ASSERT(R.pushed > 0); |
pop(R, reg) |
RETURN reg |
END PopAnyReg; |
PROCEDURE GetAnyReg* (VAR R: REGS): INTEGER; |
VAR |
reg: INTEGER; |
BEGIN |
reg := GetFreeReg(R); |
IF reg = -1 THEN |
ASSERT(R.top >= 0); |
reg := R.stk[0]; |
push(R) |
END; |
Put(R, reg) |
RETURN reg |
END GetAnyReg; |
PROCEDURE GetReg* (VAR R: REGS; reg: INTEGER): BOOLEAN; |
VAR |
free: INTEGER; |
res: BOOLEAN; |
PROCEDURE exch (VAR R: REGS; reg1, reg2: INTEGER); |
VAR |
n1, n2: INTEGER; |
BEGIN |
n1 := InStk(R, reg1); |
n2 := InStk(R, reg2); |
R.stk[n1] := reg2; |
R.stk[n2] := reg1; |
R.xch(reg1, reg2) |
END exch; |
BEGIN |
IF reg IN R.regs THEN |
Put(R, reg); |
res := TRUE |
ELSE |
res := InStk(R, reg) # -1; |
IF res THEN |
free := GetFreeReg(R); |
IF free # -1 THEN |
Put(R, free); |
exch(R, reg, free) |
ELSE |
push(R); |
free := GetFreeReg(R); |
ASSERT(free # -1); |
Put(R, free); |
IF free # reg THEN |
exch(R, reg, free) |
END |
END |
END |
END |
RETURN res |
END GetReg; |
PROCEDURE Exchange* (VAR R: REGS; reg1, reg2: INTEGER): BOOLEAN; |
VAR |
n1, n2: INTEGER; |
res: BOOLEAN; |
BEGIN |
res := TRUE; |
IF reg1 # reg2 THEN |
n1 := InStk(R, reg1); |
n2 := InStk(R, reg2); |
IF (n1 # -1) & (n2 # -1) THEN |
R.stk[n1] := reg2; |
R.stk[n2] := reg1; |
R.xch(reg2, reg1) |
ELSIF (n1 # -1) & (reg2 IN R.regs) THEN |
R.stk[n1] := reg2; |
INCL(R.regs, reg1); |
EXCL(R.regs, reg2); |
R.mov(reg2, reg1) |
ELSIF (n2 # -1) & (reg1 IN R.regs) THEN |
R.stk[n2] := reg1; |
EXCL(R.regs, reg1); |
INCL(R.regs, reg2); |
R.mov(reg1, reg2) |
ELSE |
res := FALSE |
END |
END |
RETURN res |
END Exchange; |
PROCEDURE Drop* (VAR R: REGS); |
BEGIN |
INCL(R.regs, R.stk[R.top]); |
DEC(R.top) |
END Drop; |
PROCEDURE BinOp* (VAR R: REGS; VAR reg1, reg2: INTEGER); |
BEGIN |
IF R.top > 0 THEN |
reg1 := R.stk[R.top - 1]; |
reg2 := R.stk[R.top] |
ELSIF R.top = 0 THEN |
reg1 := PopAnyReg(R); |
reg2 := R.stk[1] |
ELSE (* R.top = -1 *) |
reg2 := PopAnyReg(R); |
reg1 := PopAnyReg(R) |
END |
END BinOp; |
PROCEDURE UnOp* (VAR R: REGS; VAR reg: INTEGER); |
BEGIN |
IF R.top >= 0 THEN |
reg := R.stk[R.top] |
ELSE |
reg := PopAnyReg(R) |
END |
END UnOp; |
PROCEDURE PushAll* (VAR R: REGS); |
BEGIN |
WHILE R.top >= 0 DO |
push(R) |
END |
END PushAll; |
PROCEDURE PushAll_1* (VAR R: REGS); |
BEGIN |
WHILE R.top >= 1 DO |
push(R) |
END |
END PushAll_1; |
PROCEDURE Init* (VAR R: REGS; push, pop: OP1; mov, xch: OP2; regs: SET); |
BEGIN |
R.regs := regs; |
R.pushed := 0; |
R.top := -1; |
R.push := push; |
R.pop := pop; |
R.mov := mov; |
R.xch := xch; |
END Init; |
END REG. |
/programs/develop/oberon07/source/RVMxI.ob07 |
---|
0,0 → 1,1428 |
(* |
BSD 2-Clause License |
Copyright (c) 2020-2021, Anton Krotov |
All rights reserved. |
*) |
MODULE RVMxI; |
IMPORT |
PROG, WR := WRITER, IL, CHL := CHUNKLISTS, REG, UTILS, STRINGS, ERRORS, TARGETS; |
CONST |
LTypes = 0; |
LStrings = 1; |
LGlobal = 2; |
LHeap = 3; |
LStack = 4; |
numGPRs = 3; |
R0 = 0; R1 = 1; |
BP = 3; SP = 4; |
ACC = R0; |
GPRs = {0 .. 2} + {5 .. numGPRs + 1}; |
opSTOP = 0; opRET = 1; opENTER = 2; opNEG = 3; opNOT = 4; opNOP = 5; |
opXCHG = 6; opLDB = 7; opLDH = 8; opLDW = 9; opPUSH = 10; opPUSHC = 11; |
opPOP = 12; opLABEL = 13; opLEA = 14; opLLA = 15; |
opLDD = 16; (* 17, 18 *) |
opJMP = 19; opCALL = 20; opCALLI = 21; |
opMOV = 22; opMUL = 24; opADD = 26; opSUB = 28; opDIV = 30; opMOD = 32; |
opSTB = 34; opSTH = 36; opSTW = 38; opSTD = 40; (* 42, 44 *) |
opAND = 46; opOR = 48; opXOR = 50; opASR = 52; opLSR = 54; |
opLSL = 56; opROR = 58; (* 60, 62 *) opCMP = 64; |
opMOVC = 23; opMULC = 25; opADDC = 27; opSUBC = 29; opDIVC = 31; opMODC = 33; |
opSTBC = 35; opSTHC = 37; opSTWC = 39; opSTDC = 41; (* 43, 45 *) |
opANDC = 47; opORC = 49; opXORC = 51; opASRC = 53; opLSRC = 55; |
opLSLC = 57; opRORC = 59; (* 61, 63 *) opCMPC = 65; |
opBIT = 66; opSYSCALL = 67; opJBT = 68; opADDRC = 69; |
opJEQ = 70; opJNE = 71; opJLT = 72; opJGE = 73; opJGT = 74; opJLE = 75; |
opSEQ = 76; opSNE = 77; opSLT = 78; opSGE = 79; opSGT = 80; opSLE = 81; |
VAR |
R: REG.REGS; count, szWord: INTEGER; |
ldr, str: PROCEDURE (r1, r2: INTEGER); |
PROCEDURE OutByte (n: BYTE); |
BEGIN |
WR.WriteByte(n); |
INC(count) |
END OutByte; |
PROCEDURE OutInt (n: INTEGER); |
BEGIN |
IF szWord = 8 THEN |
WR.Write64LE(n); |
INC(count, 8) |
ELSE (* szWord = 4 *) |
WR.Write32LE(n); |
INC(count, 4) |
END |
END OutInt; |
PROCEDURE Emit (op, par1, par2: INTEGER); |
BEGIN |
OutInt(op); |
OutInt(par1); |
OutInt(par2) |
END Emit; |
PROCEDURE drop; |
BEGIN |
REG.Drop(R) |
END drop; |
PROCEDURE GetAnyReg (): INTEGER; |
RETURN REG.GetAnyReg(R) |
END GetAnyReg; |
PROCEDURE GetAcc; |
BEGIN |
ASSERT(REG.GetReg(R, ACC)) |
END GetAcc; |
PROCEDURE UnOp (VAR r: INTEGER); |
BEGIN |
REG.UnOp(R, r) |
END UnOp; |
PROCEDURE BinOp (VAR r1, r2: INTEGER); |
BEGIN |
REG.BinOp(R, r1, r2) |
END BinOp; |
PROCEDURE PushAll (NumberOfParameters: INTEGER); |
BEGIN |
REG.PushAll(R); |
DEC(R.pushed, NumberOfParameters) |
END PushAll; |
PROCEDURE push (r: INTEGER); |
BEGIN |
Emit(opPUSH, r, 0) |
END push; |
PROCEDURE pop (r: INTEGER); |
BEGIN |
Emit(opPOP, r, 0) |
END pop; |
PROCEDURE mov (r1, r2: INTEGER); |
BEGIN |
Emit(opMOV, r1, r2) |
END mov; |
PROCEDURE xchg (r1, r2: INTEGER); |
BEGIN |
Emit(opXCHG, r1, r2) |
END xchg; |
PROCEDURE addrc (r, c: INTEGER); |
BEGIN |
Emit(opADDC, r, c) |
END addrc; |
PROCEDURE subrc (r, c: INTEGER); |
BEGIN |
Emit(opSUBC, r, c) |
END subrc; |
PROCEDURE movrc (r, c: INTEGER); |
BEGIN |
Emit(opMOVC, r, c) |
END movrc; |
PROCEDURE pushc (c: INTEGER); |
BEGIN |
Emit(opPUSHC, c, 0) |
END pushc; |
PROCEDURE add (r1, r2: INTEGER); |
BEGIN |
Emit(opADD, r1, r2) |
END add; |
PROCEDURE sub (r1, r2: INTEGER); |
BEGIN |
Emit(opSUB, r1, r2) |
END sub; |
PROCEDURE ldr64 (r1, r2: INTEGER); |
BEGIN |
Emit(opLDD, r2 * 256 + r1, 0) |
END ldr64; |
PROCEDURE ldr32 (r1, r2: INTEGER); |
BEGIN |
Emit(opLDW, r2 * 256 + r1, 0) |
END ldr32; |
PROCEDURE ldr16 (r1, r2: INTEGER); |
BEGIN |
Emit(opLDH, r2 * 256 + r1, 0) |
END ldr16; |
PROCEDURE ldr8 (r1, r2: INTEGER); |
BEGIN |
Emit(opLDB, r2 * 256 + r1, 0) |
END ldr8; |
PROCEDURE str64 (r1, r2: INTEGER); |
BEGIN |
Emit(opSTD, r1 * 256 + r2, 0) |
END str64; |
PROCEDURE str32 (r1, r2: INTEGER); |
BEGIN |
Emit(opSTW, r1 * 256 + r2, 0) |
END str32; |
PROCEDURE str16 (r1, r2: INTEGER); |
BEGIN |
Emit(opSTH, r1 * 256 + r2, 0) |
END str16; |
PROCEDURE str8 (r1, r2: INTEGER); |
BEGIN |
Emit(opSTB, r1 * 256 + r2, 0) |
END str8; |
PROCEDURE GlobalAdr (r, offset: INTEGER); |
BEGIN |
Emit(opLEA, r + 256 * LGlobal, offset) |
END GlobalAdr; |
PROCEDURE StrAdr (r, offset: INTEGER); |
BEGIN |
Emit(opLEA, r + 256 * LStrings, offset) |
END StrAdr; |
PROCEDURE ProcAdr (r, label: INTEGER); |
BEGIN |
Emit(opLLA, r, label) |
END ProcAdr; |
PROCEDURE jnz (r, label: INTEGER); |
BEGIN |
Emit(opCMPC, r, 0); |
Emit(opJNE, label, 0) |
END jnz; |
PROCEDURE CallRTL (proc, par: INTEGER); |
BEGIN |
Emit(opCALL, IL.codes.rtl[proc], 0); |
addrc(SP, par * szWord) |
END CallRTL; |
PROCEDURE jcc (cc: INTEGER): INTEGER; |
BEGIN |
CASE cc OF |
|IL.opEQ, IL.opEQC: cc := opJEQ |
|IL.opNE, IL.opNEC: cc := opJNE |
|IL.opLT, IL.opLTC: cc := opJLT |
|IL.opLE, IL.opLEC: cc := opJLE |
|IL.opGT, IL.opGTC: cc := opJGT |
|IL.opGE, IL.opGEC: cc := opJGE |
END |
RETURN cc |
END jcc; |
PROCEDURE shift1 (op, param: INTEGER); |
VAR |
r1, r2: INTEGER; |
BEGIN |
r2 := GetAnyReg(); |
Emit(opMOVC, r2, param); |
BinOp(r1, r2); |
Emit(op, r2, r1); |
mov(r1, r2); |
drop |
END shift1; |
PROCEDURE shift (op: INTEGER); |
VAR |
r1, r2: INTEGER; |
BEGIN |
BinOp(r1, r2); |
Emit(op, r1, r2); |
drop |
END shift; |
PROCEDURE translate (szWord: INTEGER); |
VAR |
cmd, next: IL.COMMAND; |
opcode, param1, param2, r1, r2, r3, |
a, b, label, opLD, opST, opSTC: INTEGER; |
BEGIN |
IF szWord = 8 THEN |
opLD := opLDD; |
opST := opSTD; |
opSTC := opSTDC |
ELSE |
opLD := opLDW; |
opST := opSTW; |
opSTC := opSTWC |
END; |
cmd := IL.codes.commands.first(IL.COMMAND); |
WHILE cmd # NIL DO |
param1 := cmd.param1; |
param2 := cmd.param2; |
opcode := cmd.opcode; |
CASE opcode OF |
|IL.opJMP: |
Emit(opJMP, param1, 0) |
|IL.opLABEL: |
Emit(opLABEL, param1, 0) |
|IL.opCALL: |
Emit(opCALL, param1, 0) |
|IL.opCALLP: |
UnOp(r1); |
Emit(opCALLI, r1, 0); |
drop; |
ASSERT(R.top = -1) |
|IL.opPUSHC: |
pushc(param2) |
|IL.opCLEANUP: |
IF param2 # 0 THEN |
addrc(SP, param2 * szWord) |
END |
|IL.opNOP, IL.opAND, IL.opOR: |
|IL.opSADR: |
StrAdr(GetAnyReg(), param2) |
|IL.opGADR: |
GlobalAdr(GetAnyReg(), param2) |
|IL.opLADR: |
param2 := param2 * szWord; |
next := cmd.next(IL.COMMAND); |
IF ((next.opcode = IL.opSAVE) OR (next.opcode = IL.opSAVEF)) & (szWord = 8) OR (next.opcode = IL.opSAVE64) THEN |
UnOp(r1); |
Emit(opSTD, BP * 256 + r1, param2); |
drop; |
cmd := next |
ELSIF ((next.opcode = IL.opSAVE) OR (next.opcode = IL.opSAVEF)) & (szWord = 4) OR (next.opcode = IL.opSAVE32) THEN |
UnOp(r1); |
Emit(opSTW, BP * 256 + r1, param2); |
drop; |
cmd := next |
ELSIF next.opcode = IL.opSAVE16 THEN |
UnOp(r1); |
Emit(opSTH, BP * 256 + r1, param2); |
drop; |
cmd := next |
ELSIF next.opcode = IL.opSAVE8 THEN |
UnOp(r1); |
Emit(opSTB, BP * 256 + r1, param2); |
drop; |
cmd := next |
ELSE |
Emit(opADDRC, BP * 256 + GetAnyReg(), param2) |
END |
|IL.opPARAM: |
IF param2 = 1 THEN |
UnOp(r1); |
push(r1); |
drop |
ELSE |
ASSERT(R.top + 1 <= param2); |
PushAll(param2) |
END |
|IL.opONERR: |
pushc(param2); |
Emit(opJMP, param1, 0) |
|IL.opPRECALL: |
PushAll(0) |
|IL.opRES, IL.opRESF: |
ASSERT(R.top = -1); |
GetAcc |
|IL.opENTER: |
ASSERT(R.top = -1); |
Emit(opLABEL, param1, 0); |
Emit(opENTER, param2, 0) |
|IL.opLEAVE, IL.opLEAVER, IL.opLEAVEF: |
IF opcode # IL.opLEAVE THEN |
UnOp(r1); |
IF r1 # ACC THEN |
mov(ACC, r1) |
END; |
drop |
END; |
ASSERT(R.top = -1); |
IF param1 > 0 THEN |
mov(SP, BP) |
END; |
pop(BP); |
Emit(opRET, 0, 0) |
|IL.opLEAVEC: |
Emit(opRET, 0, 0) |
|IL.opCONST: |
next := cmd.next(IL.COMMAND); |
IF (next.opcode = IL.opPARAM) & (next.param2 = 1) THEN |
pushc(param2); |
cmd := next |
ELSE |
movrc(GetAnyReg(), param2) |
END |
|IL.opDROP: |
UnOp(r1); |
drop |
|IL.opSAVEC: |
UnOp(r1); |
Emit(opSTC, r1, param2); |
drop |
|IL.opSAVE8C: |
UnOp(r1); |
Emit(opSTBC, r1, param2 MOD 256); |
drop |
|IL.opSAVE16C: |
UnOp(r1); |
Emit(opSTHC, r1, param2 MOD 65536); |
drop |
|IL.opSAVE, IL.opSAVEF: |
BinOp(r2, r1); |
str(r1, r2); |
drop; |
drop |
|IL.opSAVE32: |
BinOp(r2, r1); |
str32(r1, r2); |
drop; |
drop |
|IL.opSAVE64: |
BinOp(r2, r1); |
str64(r1, r2); |
drop; |
drop |
|IL.opSAVEFI: |
BinOp(r2, r1); |
str(r2, r1); |
drop; |
drop |
|IL.opSAVE8: |
BinOp(r2, r1); |
str8(r1, r2); |
drop; |
drop |
|IL.opSAVE16: |
BinOp(r2, r1); |
str16(r1, r2); |
drop; |
drop |
|IL.opGLOAD32: |
r1 := GetAnyReg(); |
GlobalAdr(r1, param2); |
ldr32(r1, r1) |
|IL.opGLOAD64: |
r1 := GetAnyReg(); |
GlobalAdr(r1, param2); |
ldr64(r1, r1) |
|IL.opVADR: |
Emit(opLD, BP * 256 + GetAnyReg(), param2 * szWord) |
|IL.opLLOAD32: |
Emit(opLDW, BP * 256 + GetAnyReg(), param2 * szWord) |
|IL.opLLOAD64: |
Emit(opLDD, BP * 256 + GetAnyReg(), param2 * szWord) |
|IL.opVLOAD32: |
r1 := GetAnyReg(); |
Emit(opLD, BP * 256 + r1, param2 * szWord); |
ldr32(r1, r1) |
|IL.opVLOAD64: |
r1 := GetAnyReg(); |
Emit(opLDD, BP * 256 + r1, param2 * szWord); |
ldr64(r1, r1) |
|IL.opGLOAD16: |
r1 := GetAnyReg(); |
GlobalAdr(r1, param2); |
ldr16(r1, r1) |
|IL.opLLOAD16: |
Emit(opLDH, BP * 256 + GetAnyReg(), param2 * szWord) |
|IL.opVLOAD16: |
r1 := GetAnyReg(); |
Emit(opLD, BP * 256 + r1, param2 * szWord); |
ldr16(r1, r1) |
|IL.opGLOAD8: |
r1 := GetAnyReg(); |
GlobalAdr(r1, param2); |
ldr8(r1, r1) |
|IL.opLLOAD8: |
Emit(opLDB, BP * 256 + GetAnyReg(), param2 * szWord) |
|IL.opVLOAD8: |
r1 := GetAnyReg(); |
Emit(opLD, BP * 256 + r1, param2 * szWord); |
ldr8(r1, r1) |
|IL.opLOAD8: |
UnOp(r1); |
ldr8(r1, r1) |
|IL.opLOAD16: |
UnOp(r1); |
ldr16(r1, r1) |
|IL.opLOAD32: |
UnOp(r1); |
ldr32(r1, r1) |
|IL.opLOAD64: |
UnOp(r1); |
ldr64(r1, r1) |
|IL.opLOADF: |
UnOp(r1); |
ldr(r1, r1) |
|IL.opUMINUS: |
UnOp(r1); |
Emit(opNEG, r1, 0) |
|IL.opADD: |
BinOp(r1, r2); |
add(r1, r2); |
drop |
|IL.opSUB: |
BinOp(r1, r2); |
sub(r1, r2); |
drop |
|IL.opADDC: |
UnOp(r1); |
next := cmd.next(IL.COMMAND); |
CASE next.opcode OF |
|IL.opLOADF: |
Emit(opLD, r1 * 256 + r1, param2); |
cmd := next |
|IL.opLOAD64: |
Emit(opLDD, r1 * 256 + r1, param2); |
cmd := next |
|IL.opLOAD32: |
Emit(opLDW, r1 * 256 + r1, param2); |
cmd := next |
|IL.opLOAD16: |
Emit(opLDH, r1 * 256 + r1, param2); |
cmd := next |
|IL.opLOAD8: |
Emit(opLDB, r1 * 256 + r1, param2); |
cmd := next |
ELSE |
addrc(r1, param2) |
END |
|IL.opSUBR: |
UnOp(r1); |
subrc(r1, param2) |
|IL.opSUBL: |
UnOp(r1); |
subrc(r1, param2); |
Emit(opNEG, r1, 0) |
|IL.opMULC: |
UnOp(r1); |
Emit(opMULC, r1, param2) |
|IL.opMUL: |
BinOp(r1, r2); |
Emit(opMUL, r1, r2); |
drop |
|IL.opDIV: |
BinOp(r1, r2); |
Emit(opDIV, r1, r2); |
drop |
|IL.opMOD: |
BinOp(r1, r2); |
Emit(opMOD, r1, r2); |
drop |
|IL.opDIVR: |
UnOp(r1); |
Emit(opDIVC, r1, param2) |
|IL.opMODR: |
UnOp(r1); |
Emit(opMODC, r1, param2) |
|IL.opDIVL: |
UnOp(r1); |
r2 := GetAnyReg(); |
movrc(r2, param2); |
Emit(opDIV, r2, r1); |
mov(r1, r2); |
drop |
|IL.opMODL: |
UnOp(r1); |
r2 := GetAnyReg(); |
movrc(r2, param2); |
Emit(opMOD, r2, r1); |
mov(r1, r2); |
drop |
|IL.opEQ .. IL.opGE, IL.opEQC .. IL.opGEC: |
IF (IL.opEQ <= opcode) & (opcode <= IL.opGE) THEN |
BinOp(r1, r2); |
Emit(opCMP, r1, r2); |
drop |
ELSE |
UnOp(r1); |
Emit(opCMPC, r1, param2) |
END; |
next := cmd.next(IL.COMMAND); |
IF next.opcode = IL.opJZ THEN |
Emit(ORD(BITS(jcc(opcode)) / {0}), next.param1, 0); |
cmd := next; |
drop |
ELSIF next.opcode = IL.opJNZ THEN |
Emit(jcc(opcode), next.param1, 0); |
cmd := next; |
drop |
ELSE |
Emit(jcc(opcode) + 6, r1, 0) |
END |
|IL.opJNZ1: |
UnOp(r1); |
jnz(r1, param1) |
|IL.opJG: |
UnOp(r1); |
Emit(opCMPC, r1, 0); |
Emit(opJGT, param1, 0) |
|IL.opJNZ: |
UnOp(r1); |
jnz(r1, param1); |
drop |
|IL.opJZ: |
UnOp(r1); |
Emit(opCMPC, r1, 0); |
Emit(opJEQ, param1, 0); |
drop |
|IL.opMULS: |
BinOp(r1, r2); |
Emit(opAND, r1, r2); |
drop |
|IL.opMULSC: |
UnOp(r1); |
Emit(opANDC, r1, param2) |
|IL.opDIVS: |
BinOp(r1, r2); |
Emit(opXOR, r1, r2); |
drop |
|IL.opDIVSC: |
UnOp(r1); |
Emit(opXORC, r1, param2) |
|IL.opADDS: |
BinOp(r1, r2); |
Emit(opOR, r1, r2); |
drop |
|IL.opSUBS: |
BinOp(r1, r2); |
Emit(opNOT, r2, 0); |
Emit(opAND, r1, r2); |
drop |
|IL.opADDSC: |
UnOp(r1); |
Emit(opORC, r1, param2) |
|IL.opSUBSL: |
UnOp(r1); |
Emit(opNOT, r1, 0); |
Emit(opANDC, r1, param2) |
|IL.opSUBSR: |
UnOp(r1); |
Emit(opANDC, r1, ORD(-BITS(param2))) |
|IL.opUMINS: |
UnOp(r1); |
Emit(opNOT, r1, 0) |
|IL.opASR: |
shift(opASR) |
|IL.opLSL: |
shift(opLSL) |
|IL.opROR: |
shift(opROR) |
|IL.opLSR: |
shift(opLSR) |
|IL.opASR1: |
shift1(opASR, param2) |
|IL.opLSL1: |
shift1(opLSL, param2) |
|IL.opROR1: |
shift1(opROR, param2) |
|IL.opLSR1: |
shift1(opLSR, param2) |
|IL.opASR2: |
UnOp(r1); |
Emit(opASRC, r1, param2 MOD (szWord * 8)) |
|IL.opLSL2: |
UnOp(r1); |
Emit(opLSLC, r1, param2 MOD (szWord * 8)) |
|IL.opROR2: |
UnOp(r1); |
Emit(opRORC, r1, param2 MOD (szWord * 8)) |
|IL.opLSR2: |
UnOp(r1); |
Emit(opLSRC, r1, param2 MOD (szWord * 8)) |
|IL.opCHR: |
UnOp(r1); |
Emit(opANDC, r1, 255) |
|IL.opWCHR: |
UnOp(r1); |
Emit(opANDC, r1, 65535) |
|IL.opABS: |
UnOp(r1); |
Emit(opCMPC, r1, 0); |
label := IL.NewLabel(); |
Emit(opJGE, label, 0); |
Emit(opNEG, r1, 0); |
Emit(opLABEL, label, 0) |
|IL.opLEN: |
UnOp(r1); |
drop; |
EXCL(R.regs, r1); |
WHILE param2 > 0 DO |
UnOp(r2); |
drop; |
DEC(param2) |
END; |
INCL(R.regs, r1); |
ASSERT(REG.GetReg(R, r1)) |
|IL.opSWITCH: |
UnOp(r1); |
IF param2 = 0 THEN |
r2 := ACC |
ELSE |
r2 := R1 |
END; |
IF r1 # r2 THEN |
ASSERT(REG.GetReg(R, r2)); |
ASSERT(REG.Exchange(R, r1, r2)); |
drop |
END; |
drop |
|IL.opENDSW: |
|IL.opCASEL: |
Emit(opCMPC, ACC, param1); |
Emit(opJLT, param2, 0) |
|IL.opCASER: |
Emit(opCMPC, ACC, param1); |
Emit(opJGT, param2, 0) |
|IL.opCASELR: |
Emit(opCMPC, ACC, param1); |
IF param2 = cmd.param3 THEN |
Emit(opJNE, param2, 0) |
ELSE |
Emit(opJLT, param2, 0); |
Emit(opJGT, cmd.param3, 0) |
END |
|IL.opSBOOL: |
BinOp(r2, r1); |
Emit(opCMPC, r2, 0); |
Emit(opSNE, r2, 0); |
str8(r1, r2); |
drop; |
drop |
|IL.opSBOOLC: |
UnOp(r1); |
Emit(opSTBC, r1, ORD(param2 # 0)); |
drop |
|IL.opINCC: |
UnOp(r1); |
r2 := GetAnyReg(); |
ldr(r2, r1); |
addrc(r2, param2); |
str(r1, r2); |
drop; |
drop |
|IL.opINCCB, IL.opDECCB: |
IF opcode = IL.opDECCB THEN |
param2 := -param2 |
END; |
UnOp(r1); |
r2 := GetAnyReg(); |
ldr8(r2, r1); |
addrc(r2, param2); |
str8(r1, r2); |
drop; |
drop |
|IL.opINCB, IL.opDECB: |
BinOp(r2, r1); |
r3 := GetAnyReg(); |
ldr8(r3, r1); |
IF opcode = IL.opINCB THEN |
add(r3, r2) |
ELSE |
sub(r3, r2) |
END; |
str8(r1, r3); |
drop; |
drop; |
drop |
|IL.opINC, IL.opDEC: |
BinOp(r2, r1); |
r3 := GetAnyReg(); |
ldr(r3, r1); |
IF opcode = IL.opINC THEN |
add(r3, r2) |
ELSE |
sub(r3, r2) |
END; |
str(r1, r3); |
drop; |
drop; |
drop |
|IL.opINCL, IL.opEXCL: |
BinOp(r2, r1); |
Emit(opBIT, r2, r2); |
r3 := GetAnyReg(); |
ldr(r3, r1); |
IF opcode = IL.opINCL THEN |
Emit(opOR, r3, r2) |
ELSE |
Emit(opNOT, r2, 0); |
Emit(opAND, r3, r2) |
END; |
str(r1, r3); |
drop; |
drop; |
drop |
|IL.opINCLC, IL.opEXCLC: |
UnOp(r1); |
r2 := GetAnyReg(); |
ldr(r2, r1); |
IF opcode = IL.opINCLC THEN |
Emit(opORC, r2, ORD({param2})) |
ELSE |
Emit(opANDC, r2, ORD(-{param2})) |
END; |
str(r1, r2); |
drop; |
drop |
|IL.opEQB, IL.opNEB: |
BinOp(r1, r2); |
Emit(opCMPC, r1, 0); |
Emit(opSNE, r1, 0); |
Emit(opCMPC, r2, 0); |
Emit(opSNE, r2, 0); |
Emit(opCMP, r1, r2); |
IF opcode = IL.opEQB THEN |
Emit(opSEQ, r1, 0) |
ELSE |
Emit(opSNE, r1, 0) |
END; |
drop |
|IL.opCHKBYTE: |
BinOp(r1, r2); |
Emit(opCMPC, r1, 256); |
Emit(opJBT, param1, 0) |
|IL.opCHKIDX: |
UnOp(r1); |
Emit(opCMPC, r1, param2); |
Emit(opJBT, param1, 0) |
|IL.opCHKIDX2: |
BinOp(r1, r2); |
IF param2 # -1 THEN |
Emit(opCMP, r2, r1); |
Emit(opJBT, param1, 0) |
END; |
INCL(R.regs, r1); |
DEC(R.top); |
R.stk[R.top] := r2 |
|IL.opEQP, IL.opNEP: |
ProcAdr(GetAnyReg(), param1); |
BinOp(r1, r2); |
Emit(opCMP, r1, r2); |
IF opcode = IL.opEQP THEN |
Emit(opSEQ, r1, 0) |
ELSE |
Emit(opSNE, r1, 0) |
END; |
drop |
|IL.opSAVEP: |
UnOp(r1); |
r2 := GetAnyReg(); |
ProcAdr(r2, param2); |
str(r1, r2); |
drop; |
drop |
|IL.opPUSHP: |
ProcAdr(GetAnyReg(), param2) |
|IL.opPUSHT: |
UnOp(r1); |
Emit(opLD, r1 * 256 + GetAnyReg(), -szWord) |
|IL.opGET, IL.opGETC: |
IF opcode = IL.opGET THEN |
BinOp(r1, r2) |
ELSIF opcode = IL.opGETC THEN |
UnOp(r2); |
r1 := GetAnyReg(); |
movrc(r1, param1) |
END; |
drop; |
drop; |
CASE param2 OF |
|1: ldr8(r1, r1); str8(r2, r1) |
|2: ldr16(r1, r1); str16(r2, r1) |
|4: ldr32(r1, r1); str32(r2, r1) |
|8: ldr64(r1, r1); str64(r2, r1) |
END |
|IL.opNOT: |
UnOp(r1); |
Emit(opCMPC, r1, 0); |
Emit(opSEQ, r1, 0) |
|IL.opORD: |
UnOp(r1); |
Emit(opCMPC, r1, 0); |
Emit(opSNE, r1, 0) |
|IL.opMIN, IL.opMAX: |
BinOp(r1, r2); |
Emit(opCMP, r1, r2); |
label := IL.NewLabel(); |
IF opcode = IL.opMIN THEN |
Emit(opJLE, label, 0) |
ELSE |
Emit(opJGE, label, 0) |
END; |
Emit(opMOV, r1, r2); |
Emit(opLABEL, label, 0); |
drop |
|IL.opMINC, IL.opMAXC: |
UnOp(r1); |
Emit(opCMPC, r1, param2); |
label := IL.NewLabel(); |
IF opcode = IL.opMINC THEN |
Emit(opJLE, label, 0) |
ELSE |
Emit(opJGE, label, 0) |
END; |
Emit(opMOVC, r1, param2); |
Emit(opLABEL, label, 0) |
|IL.opIN: |
BinOp(r1, r2); |
Emit(opBIT, r1, r1); |
Emit(opAND, r1, r2); |
Emit(opCMPC, r1, 0); |
Emit(opSNE, r1, 0); |
drop |
|IL.opINL: |
UnOp(r1); |
Emit(opANDC, r1, ORD({param2})); |
Emit(opCMPC, r1, 0); |
Emit(opSNE, r1, 0) |
|IL.opINR: |
UnOp(r1); |
Emit(opBIT, r1, r1); |
Emit(opANDC, r1, param2); |
Emit(opCMPC, r1, 0); |
Emit(opSNE, r1, 0) |
|IL.opERR: |
CallRTL(IL._error, 4) |
|IL.opEQS .. IL.opGES: |
PushAll(4); |
pushc(opcode - IL.opEQS); |
CallRTL(IL._strcmp, 5); |
GetAcc |
|IL.opEQSW .. IL.opGESW: |
PushAll(4); |
pushc(opcode - IL.opEQSW); |
CallRTL(IL._strcmpw, 5); |
GetAcc |
|IL.opCOPY: |
PushAll(2); |
pushc(param2); |
CallRTL(IL._move, 3) |
|IL.opMOVE: |
PushAll(3); |
CallRTL(IL._move, 3) |
|IL.opCOPYA: |
PushAll(4); |
pushc(param2); |
CallRTL(IL._arrcpy, 5); |
GetAcc |
|IL.opCOPYS: |
PushAll(4); |
pushc(param2); |
CallRTL(IL._strcpy, 5) |
|IL.opROT: |
PushAll(0); |
mov(ACC, SP); |
push(ACC); |
pushc(param2); |
CallRTL(IL._rot, 2) |
|IL.opLENGTH: |
PushAll(2); |
CallRTL(IL._length, 2); |
GetAcc |
|IL.opLENGTHW: |
PushAll(2); |
CallRTL(IL._lengthw, 2); |
GetAcc |
|IL.opSAVES: |
UnOp(r2); |
REG.PushAll_1(R); |
r1 := GetAnyReg(); |
StrAdr(r1, param2); |
push(r1); |
drop; |
push(r2); |
drop; |
pushc(param1); |
CallRTL(IL._move, 3) |
|IL.opRSET: |
PushAll(2); |
CallRTL(IL._set, 2); |
GetAcc |
|IL.opRSETR: |
PushAll(1); |
pushc(param2); |
CallRTL(IL._set, 2); |
GetAcc |
|IL.opRSETL: |
UnOp(r1); |
REG.PushAll_1(R); |
pushc(param2); |
push(r1); |
drop; |
CallRTL(IL._set, 2); |
GetAcc |
|IL.opRSET1: |
PushAll(1); |
CallRTL(IL._set1, 1); |
GetAcc |
|IL.opNEW: |
PushAll(1); |
INC(param2, szWord); |
ASSERT(UTILS.Align(param2, szWord)); |
pushc(param2); |
pushc(param1); |
CallRTL(IL._new, 3) |
|IL.opTYPEGP: |
UnOp(r1); |
PushAll(0); |
push(r1); |
pushc(param2); |
CallRTL(IL._guard, 2); |
GetAcc |
|IL.opIS: |
PushAll(1); |
pushc(param2); |
CallRTL(IL._is, 2); |
GetAcc |
|IL.opISREC: |
PushAll(2); |
pushc(param2); |
CallRTL(IL._guardrec, 3); |
GetAcc |
|IL.opTYPEGR: |
PushAll(1); |
pushc(param2); |
CallRTL(IL._guardrec, 2); |
GetAcc |
|IL.opTYPEGD: |
UnOp(r1); |
PushAll(0); |
subrc(r1, szWord); |
ldr(r1, r1); |
push(r1); |
pushc(param2); |
CallRTL(IL._guardrec, 2); |
GetAcc |
|IL.opCASET: |
push(R1); |
push(R1); |
pushc(param2); |
CallRTL(IL._guardrec, 2); |
pop(R1); |
jnz(ACC, param1) |
|IL.opCONSTF: |
IF szWord = 8 THEN |
movrc(GetAnyReg(), UTILS.splitf(cmd.float, a, b)) |
ELSE (* szWord = 4 *) |
movrc(GetAnyReg(), UTILS.d2s(cmd.float)) |
END |
|IL.opMULF: |
PushAll(2); |
CallRTL(IL._fmul, 2); |
GetAcc |
|IL.opDIVF: |
PushAll(2); |
CallRTL(IL._fdiv, 2); |
GetAcc |
|IL.opDIVFI: |
PushAll(2); |
CallRTL(IL._fdivi, 2); |
GetAcc |
|IL.opADDF: |
PushAll(2); |
CallRTL(IL._fadd, 2); |
GetAcc |
|IL.opSUBFI: |
PushAll(2); |
CallRTL(IL._fsubi, 2); |
GetAcc |
|IL.opSUBF: |
PushAll(2); |
CallRTL(IL._fsub, 2); |
GetAcc |
|IL.opEQF..IL.opGEF: |
PushAll(2); |
pushc(opcode - IL.opEQF); |
CallRTL(IL._fcmp, 3); |
GetAcc |
|IL.opFLOOR: |
PushAll(1); |
CallRTL(IL._floor, 1); |
GetAcc |
|IL.opFLT: |
PushAll(1); |
CallRTL(IL._flt, 1); |
GetAcc |
|IL.opUMINF: |
UnOp(r1); |
Emit(opRORC, r1, -1); |
Emit(opXORC, r1, 1); |
Emit(opRORC, r1, 1) |
|IL.opFABS: |
UnOp(r1); |
Emit(opLSLC, r1, 1); |
Emit(opLSRC, r1, 1) |
|IL.opINF: |
r1 := GetAnyReg(); |
Emit(opMOVC, r1, 1); |
Emit(opRORC, r1, 1); |
Emit(opASRC, r1, 7 + 3 * ORD(szWord = 8)); |
Emit(opLSRC, r1, 1) |
|IL.opPUSHF: |
UnOp(r1); |
push(r1); |
drop |
|IL.opPACK: |
PushAll(2); |
CallRTL(IL._pack, 2) |
|IL.opPACKC: |
PushAll(1); |
pushc(param2); |
CallRTL(IL._pack, 2) |
|IL.opUNPK: |
PushAll(2); |
CallRTL(IL._unpk, 2) |
|IL.opCODE: |
OutInt(param2) |
|IL.opLADR_SAVE: |
UnOp(r1); |
Emit(opST, BP * 256 + r1, param2 * szWord); |
drop |
|IL.opLADR_INCC: |
r1 := GetAnyReg(); |
Emit(opLD, BP * 256 + r1, param1 * szWord); |
Emit(opADDC, r1, param2); |
Emit(opST, BP * 256 + r1, param1 * szWord); |
drop |
END; |
cmd := cmd.next(IL.COMMAND) |
END; |
ASSERT(R.pushed = 0); |
ASSERT(R.top = -1) |
END translate; |
PROCEDURE prolog; |
BEGIN |
Emit(opLEA, SP + LStack * 256, 0); |
Emit(opLEA, ACC + LTypes * 256, 0); |
push(ACC); |
Emit(opLEA, ACC + LHeap * 256, 0); |
push(ACC); |
pushc(CHL.Length(IL.codes.types)); |
CallRTL(IL._init, 3) |
END prolog; |
PROCEDURE epilog (ram, szWord: INTEGER); |
VAR |
tcount, dcount, i, offTypes, offStrings, |
szData, szGlobal, szHeapStack: INTEGER; |
BEGIN |
Emit(opSTOP, 0, 0); |
offTypes := count; |
tcount := CHL.Length(IL.codes.types); |
FOR i := 0 TO tcount - 1 DO |
OutInt(CHL.GetInt(IL.codes.types, i)) |
END; |
offStrings := count; |
dcount := CHL.Length(IL.codes.data); |
FOR i := 0 TO dcount - 1 DO |
OutByte(CHL.GetByte(IL.codes.data, i)) |
END; |
IF dcount MOD szWord # 0 THEN |
i := szWord - dcount MOD szWord; |
WHILE i > 0 DO |
OutByte(0); |
DEC(i) |
END |
END; |
szData := count - offTypes; |
szGlobal := (IL.codes.bss DIV szWord + 1) * szWord; |
szHeapStack := ram - szData - szGlobal; |
OutInt(offTypes); |
OutInt(offStrings); |
OutInt(szGlobal DIV szWord); |
OutInt(szHeapStack DIV szWord); |
FOR i := 1 TO 8 DO |
OutInt(0) |
END |
END epilog; |
PROCEDURE CodeGen* (outname: ARRAY OF CHAR; target: INTEGER; options: PROG.OPTIONS); |
CONST |
minRAM = 32*1024; |
maxRAM = 256*1024; |
VAR |
szData, szRAM: INTEGER; |
BEGIN |
szWord := TARGETS.WordSize; |
IF szWord = 8 THEN |
ldr := ldr64; |
str := str64 |
ELSE |
ldr := ldr32; |
str := str32 |
END; |
szData := (CHL.Length(IL.codes.types) + CHL.Length(IL.codes.data) DIV szWord + IL.codes.bss DIV szWord + 2) * szWord; |
szRAM := MIN(MAX(options.ram, minRAM), maxRAM) * 1024; |
IF szRAM - szData < 1024*1024 THEN |
ERRORS.Error(208) |
END; |
count := 0; |
WR.Create(outname); |
REG.Init(R, push, pop, mov, xchg, GPRs); |
prolog; |
translate(szWord); |
epilog(szRAM, szWord); |
WR.Close |
END CodeGen; |
END RVMxI. |
/programs/develop/oberon07/source/SCAN.ob07 |
---|
0,0 → 1,783 |
(* |
BSD 2-Clause License |
Copyright (c) 2018-2021, Anton Krotov |
All rights reserved. |
*) |
MODULE SCAN; |
IMPORT TXT := TEXTDRV, ARITH, S := STRINGS, ERRORS, LISTS; |
CONST |
NUMLEN = 256; |
IDLEN = 256; |
TEXTLEN = 512; |
lxUNDEF* = 0; lxIDENT* = 1; lxINTEGER* = 2; lxHEX* = 3; |
lxCHAR* = 4; lxFLOAT* = 5; lxSTRING* = 6; lxCOMMENT* = 7; |
lxEOF* = 8; |
lxPLUS* = 21; lxMINUS* = 22; lxMUL* = 23; lxSLASH* = 24; |
lxNOT* = 25; lxAND* = 26; lxPOINT* = 27; lxCOMMA* = 28; |
lxSEMI* = 29; lxBAR* = 30; lxLROUND* = 31; lxLSQUARE* = 32; |
lxLCURLY* = 33; lxCARET* = 34; lxEQ* = 35; lxNE* = 36; |
lxLT* = 37; lxGT* = 38; lxCOLON* = 39; lxRROUND* = 40; |
lxRSQUARE* = 41; lxRCURLY* = 42; lxLE* = 43; lxGE* = 44; |
lxASSIGN* = 45; lxRANGE* = 46; |
lxKW = 51; |
lxARRAY* = 51; lxBEGIN* = 52; lxBY* = 53; lxCASE* = 54; |
lxCONST* = 55; lxDIV* = 56; lxDO* = 57; lxELSE* = 58; |
lxELSIF* = 59; lxEND* = 60; lxFALSE* = 61; lxFOR* = 62; |
lxIF* = 63; lxIMPORT* = 64; lxIN* = 65; lxIS* = 66; |
lxMOD* = 67; lxMODULE* = 68; lxNIL* = 69; lxOF* = 70; |
lxOR* = 71; lxPOINTER* = 72; lxPROCEDURE* = 73; lxRECORD* = 74; |
lxREPEAT* = 75; lxRETURN* = 76; lxTHEN* = 77; lxTO* = 78; |
lxTRUE* = 79; lxTYPE* = 80; lxUNTIL* = 81; lxVAR* = 82; |
lxWHILE* = 83; |
lxERROR01* = -1; lxERROR02* = -2; lxERROR03* = -3; lxERROR04* = -4; |
lxERROR05* = -5; (*lxERROR06* = -6;*) lxERROR07* = -7; lxERROR08* = -8; |
lxERROR09* = -9; lxERROR10* = -10; lxERROR11* = -11; lxERROR12* = -12; |
lxERROR13* = -13; |
TYPE |
TEXTSTR* = ARRAY TEXTLEN OF CHAR; |
IDSTR* = ARRAY IDLEN OF CHAR; |
DEF = POINTER TO RECORD (LISTS.ITEM) |
ident: IDSTR |
END; |
STRING* = POINTER TO RECORD (LISTS.ITEM) |
s*: TEXTSTR; |
offset*, offsetW*, hash: INTEGER |
END; |
IDENT* = RECORD |
s*: IDSTR; |
hash*: INTEGER |
END; |
POSITION* = RECORD |
line*, col*: INTEGER |
END; |
LEX* = RECORD |
sym*: INTEGER; |
pos*: POSITION; |
ident*: IDENT; |
string*: STRING; |
value*: ARITH.VALUE; |
error*: INTEGER |
END; |
SCANNER* = TXT.TEXT; |
KEYWORD = ARRAY 10 OF CHAR; |
VAR |
delimiters: ARRAY 256 OF BOOLEAN; |
upto, LowerCase, _if: BOOLEAN; |
strings, def: LISTS.LIST; |
KW: ARRAY 33 OF RECORD upper, lower: KEYWORD; uhash, lhash: INTEGER END; |
PROCEDURE enterKW (s: KEYWORD; idx: INTEGER); |
BEGIN |
KW[idx].lower := s; |
KW[idx].upper := s; |
S.UpCase(KW[idx].upper); |
KW[idx].uhash := S.HashStr(KW[idx].upper); |
KW[idx].lhash := S.HashStr(KW[idx].lower); |
END enterKW; |
PROCEDURE checkKW (ident: IDENT): INTEGER; |
VAR |
i, res: INTEGER; |
BEGIN |
res := lxIDENT; |
i := 0; |
WHILE i < LEN(KW) DO |
IF (KW[i].uhash = ident.hash) & (KW[i].upper = ident.s) |
OR LowerCase & (KW[i].lhash = ident.hash) & (KW[i].lower = ident.s) THEN |
res := i + lxKW; |
i := LEN(KW) |
END; |
INC(i) |
END |
RETURN res |
END checkKW; |
PROCEDURE enterStr* (s: TEXTSTR): STRING; |
VAR |
str, res: STRING; |
hash: INTEGER; |
BEGIN |
hash := S.HashStr(s); |
str := strings.first(STRING); |
res := NIL; |
WHILE str # NIL DO |
IF (str.hash = hash) & (str.s = s) THEN |
res := str; |
str := NIL |
ELSE |
str := str.next(STRING) |
END |
END; |
IF res = NIL THEN |
NEW(res); |
res.s := s; |
res.offset := -1; |
res.offsetW := -1; |
res.hash := hash; |
LISTS.push(strings, res) |
END |
RETURN res |
END enterStr; |
PROCEDURE nextc (text: TXT.TEXT): CHAR; |
BEGIN |
TXT.next(text) |
RETURN text.peak |
END nextc; |
PROCEDURE setIdent* (VAR ident: IDENT; s: IDSTR); |
BEGIN |
ident.s := s; |
ident.hash := S.HashStr(s) |
END setIdent; |
PROCEDURE ident (text: TXT.TEXT; VAR lex: LEX); |
VAR |
c: CHAR; |
i: INTEGER; |
BEGIN |
c := text.peak; |
ASSERT(S.letter(c)); |
i := 0; |
WHILE (i < IDLEN - 1) & (S.letter(c) OR S.digit(c)) DO |
lex.ident.s[i] := c; |
INC(i); |
c := nextc(text) |
END; |
lex.ident.s[i] := 0X; |
lex.ident.hash := S.HashStr(lex.ident.s); |
lex.sym := checkKW(lex.ident); |
IF S.letter(c) OR S.digit(c) THEN |
ERRORS.WarningMsg(lex.pos.line, lex.pos.col, 2); |
WHILE S.letter(c) OR S.digit(c) DO |
c := nextc(text) |
END |
END |
END ident; |
PROCEDURE number (text: TXT.TEXT; VAR lex: LEX); |
TYPE |
NUMSTR = ARRAY NUMLEN OF CHAR; |
VAR |
c: CHAR; |
hex: BOOLEAN; |
error, sym, i: INTEGER; |
num: NUMSTR; |
PROCEDURE push (VAR num: NUMSTR; VAR i: INTEGER; c: CHAR); |
BEGIN |
IF i < NUMLEN - 1 THEN |
num[i] := c; |
INC(i) |
END |
END push; |
BEGIN |
c := text.peak; |
ASSERT(S.digit(c)); |
i := 0; |
error := 0; |
sym := lxINTEGER; |
hex := FALSE; |
WHILE S.digit(c) DO |
push(num, i, c); |
c := nextc(text) |
END; |
WHILE S.hexdigit(c) OR LowerCase & ("a" <= c) & (c <= "f") DO |
S.cap(c); |
push(num, i, c); |
c := nextc(text); |
hex := TRUE |
END; |
IF (c = "H") OR LowerCase & (c = "h") THEN |
push(num, i, c); |
TXT.next(text); |
sym := lxHEX |
ELSIF (c = "X") OR LowerCase & (c = "x") THEN |
push(num, i, c); |
TXT.next(text); |
sym := lxCHAR |
ELSIF c = "." THEN |
IF hex THEN |
sym := lxERROR01 |
ELSE |
c := nextc(text); |
IF c # "." THEN |
push(num, i, "."); |
sym := lxFLOAT |
ELSE |
sym := lxINTEGER; |
text.peak := 7FX; |
upto := TRUE |
END; |
WHILE S.digit(c) DO |
push(num, i, c); |
c := nextc(text) |
END; |
IF (c = "E") OR LowerCase & (c = "e") THEN |
push(num, i, c); |
c := nextc(text); |
IF (c = "+") OR (c = "-") THEN |
push(num, i, c); |
c := nextc(text) |
END; |
IF S.digit(c) THEN |
WHILE S.digit(c) DO |
push(num, i, c); |
c := nextc(text) |
END |
ELSE |
sym := lxERROR02 |
END |
END |
END |
ELSIF hex THEN |
sym := lxERROR01 |
END; |
IF (i = NUMLEN - 1) & (sym >= 0) THEN |
sym := lxERROR07 |
END; |
num[i] := 0X; |
IF sym = lxINTEGER THEN |
ARITH.iconv(num, lex.value, error) |
ELSIF (sym = lxHEX) OR (sym = lxCHAR) THEN |
ARITH.hconv(num, lex.value, error) |
ELSIF sym = lxFLOAT THEN |
ARITH.fconv(num, lex.value, error) |
END; |
CASE error OF |
|0: |
|1: sym := lxERROR08 |
|2: sym := lxERROR09 |
|3: sym := lxERROR10 |
|4: sym := lxERROR11 |
|5: sym := lxERROR12 |
END; |
lex.sym := sym |
END number; |
PROCEDURE string (text: TXT.TEXT; VAR lex: LEX; quot: CHAR); |
VAR |
c: CHAR; |
i: INTEGER; |
str: TEXTSTR; |
BEGIN |
c := nextc(text); |
i := 0; |
WHILE (i < LEN(str) - 1) & (c # quot) & (c # 0X) & ~text.eol & ~text.eof DO |
str[i] := c; |
c := nextc(text); |
INC(i) |
END; |
str[i] := 0X; |
IF (i = LEN(str) - 1) & (c # quot) & (c # 0X) & ~text.eol & ~text.eof THEN |
lex.sym := lxERROR05 |
END; |
IF c = quot THEN |
TXT.next(text); |
IF i # 1 THEN |
lex.sym := lxSTRING |
ELSE |
lex.sym := lxCHAR; |
ARITH.setChar(lex.value, ORD(str[0])) |
END |
ELSIF lex.sym # lxERROR05 THEN |
lex.sym := lxERROR03 |
END; |
IF lex.sym = lxSTRING THEN |
lex.string := enterStr(str); |
lex.value.typ := ARITH.tSTRING; |
lex.value.string := lex.string |
END |
END string; |
PROCEDURE comment (text: TXT.TEXT); |
VAR |
c: CHAR; |
cond, depth: INTEGER; |
BEGIN |
cond := 0; |
depth := 1; |
REPEAT |
c := text.peak; |
TXT.next(text); |
IF c = "*" THEN |
IF cond = 1 THEN |
cond := 0; |
INC(depth) |
ELSE |
cond := 2 |
END |
ELSIF c = ")" THEN |
IF cond = 2 THEN |
DEC(depth) |
END; |
cond := 0 |
ELSIF c = "(" THEN |
cond := 1 |
ELSE |
cond := 0 |
END |
UNTIL (depth = 0) OR text.eof |
END comment; |
PROCEDURE delimiter (text: TXT.TEXT; c: CHAR): INTEGER; |
VAR |
sym: INTEGER; |
c0: CHAR; |
BEGIN |
c0 := c; |
c := nextc(text); |
CASE c0 OF |
|"+": |
sym := lxPLUS |
|"-": |
sym := lxMINUS |
|"*": |
sym := lxMUL |
|"/": |
sym := lxSLASH; |
IF c = "/" THEN |
sym := lxCOMMENT; |
REPEAT |
TXT.next(text) |
UNTIL text.eol OR text.eof |
END |
|"~": |
sym := lxNOT |
|"&": |
sym := lxAND |
|".": |
sym := lxPOINT; |
IF c = "." THEN |
sym := lxRANGE; |
TXT.next(text) |
END |
|",": |
sym := lxCOMMA |
|";": |
sym := lxSEMI |
|"|": |
sym := lxBAR |
|"(": |
sym := lxLROUND; |
IF c = "*" THEN |
sym := lxCOMMENT; |
TXT.next(text); |
comment(text) |
END |
|"[": |
sym := lxLSQUARE |
|"{": |
sym := lxLCURLY |
|"^": |
sym := lxCARET |
|"=": |
sym := lxEQ |
|"#": |
sym := lxNE |
|"<": |
sym := lxLT; |
IF c = "=" THEN |
sym := lxLE; |
TXT.next(text) |
END |
|">": |
sym := lxGT; |
IF c = "=" THEN |
sym := lxGE; |
TXT.next(text) |
END |
|":": |
sym := lxCOLON; |
IF c = "=" THEN |
sym := lxASSIGN; |
TXT.next(text) |
END |
|")": |
sym := lxRROUND |
|"]": |
sym := lxRSQUARE |
|"}": |
sym := lxRCURLY |
END |
RETURN sym |
END delimiter; |
PROCEDURE Next* (text: SCANNER; VAR lex: LEX); |
VAR |
c: CHAR; |
PROCEDURE check (cond: BOOLEAN; text: SCANNER; lex: LEX; errno: INTEGER); |
BEGIN |
IF ~cond THEN |
ERRORS.ErrorMsg(text.fname, lex.pos.line, lex.pos.col, errno) |
END |
END check; |
PROCEDURE IsDef (str: ARRAY OF CHAR): BOOLEAN; |
VAR |
cur: DEF; |
BEGIN |
cur := def.first(DEF); |
WHILE (cur # NIL) & (cur.ident # str) DO |
cur := cur.next(DEF) |
END |
RETURN cur # NIL |
END IsDef; |
PROCEDURE Skip (text: SCANNER); |
VAR |
i: INTEGER; |
BEGIN |
i := 0; |
WHILE (i <= text.ifc) & ~text._skip[i] DO |
INC(i) |
END; |
text.skip := i <= text.ifc |
END Skip; |
PROCEDURE prep_if (text: SCANNER; VAR lex: LEX); |
VAR |
skip: BOOLEAN; |
BEGIN |
INC(text.ifc); |
text._elsif[text.ifc] := lex.sym = lxELSIF; |
IF lex.sym = lxIF THEN |
INC(text.elsec); |
text._else[text.elsec] := FALSE |
END; |
_if := TRUE; |
skip := TRUE; |
text.skip := FALSE; |
Next(text, lex); |
check(lex.sym = lxLROUND, text, lex, 64); |
Next(text, lex); |
check(lex.sym = lxIDENT, text, lex, 22); |
REPEAT |
IF IsDef(lex.ident.s) THEN |
skip := FALSE |
END; |
Next(text, lex); |
IF lex.sym = lxBAR THEN |
Next(text, lex); |
check(lex.sym = lxIDENT, text, lex, 22) |
ELSE |
check(lex.sym = lxRROUND, text, lex, 33) |
END |
UNTIL lex.sym = lxRROUND; |
_if := FALSE; |
text._skip[text.ifc] := skip; |
Skip(text); |
Next(text, lex) |
END prep_if; |
PROCEDURE prep_end (text: SCANNER; VAR lex: LEX); |
BEGIN |
check(text.ifc > 0, text, lex, 118); |
IF lex.sym = lxEND THEN |
WHILE text._elsif[text.ifc] DO |
DEC(text.ifc) |
END; |
DEC(text.ifc); |
DEC(text.elsec) |
ELSIF (lex.sym = lxELSE) OR (lex.sym = lxELSIF) THEN |
check(~text._else[text.elsec], text, lex, 118); |
text._skip[text.ifc] := ~text._skip[text.ifc]; |
text._else[text.elsec] := lex.sym = lxELSE |
END; |
Skip(text); |
IF lex.sym = lxELSIF THEN |
prep_if(text, lex) |
ELSE |
Next(text, lex) |
END |
END prep_end; |
BEGIN |
REPEAT |
c := text.peak; |
WHILE S.space(c) DO |
c := nextc(text) |
END; |
lex.pos.line := text.line; |
lex.pos.col := text.col; |
IF S.letter(c) THEN |
ident(text, lex) |
ELSIF S.digit(c) THEN |
number(text, lex) |
ELSIF (c = '"') OR (c = "'") THEN |
string(text, lex, c) |
ELSIF delimiters[ORD(c)] THEN |
lex.sym := delimiter(text, c) |
ELSIF c = "$" THEN |
IF S.letter(nextc(text)) THEN |
ident(text, lex); |
IF lex.sym = lxIF THEN |
IF ~_if THEN |
prep_if(text, lex) |
END |
ELSIF (lex.sym = lxEND) OR (lex.sym = lxELSE) OR (lex.sym = lxELSIF) THEN |
IF ~_if THEN |
prep_end(text, lex) |
END |
ELSE |
check(FALSE, text, lex, 119) |
END |
ELSE |
check(FALSE, text, lex, 119) |
END |
ELSIF c = 0X THEN |
lex.sym := lxEOF; |
text.skip := FALSE; |
IF text.eof THEN |
INC(lex.pos.col) |
END |
ELSIF (c = 7FX) & upto THEN |
upto := FALSE; |
lex.sym := lxRANGE; |
DEC(lex.pos.col); |
TXT.next(text) |
ELSE |
TXT.next(text); |
lex.sym := lxERROR04 |
END; |
IF lex.sym < 0 THEN |
lex.error := -lex.sym |
ELSE |
lex.error := 0 |
END |
UNTIL (lex.sym # lxCOMMENT) & ~text.skip |
END Next; |
PROCEDURE open* (name: ARRAY OF CHAR): SCANNER; |
RETURN TXT.open(name) |
END open; |
PROCEDURE close* (VAR scanner: SCANNER); |
BEGIN |
TXT.close(scanner) |
END close; |
PROCEDURE init* (lower: BOOLEAN); |
VAR |
i: INTEGER; |
delim: ARRAY 23 OF CHAR; |
BEGIN |
upto := FALSE; |
LowerCase := lower; |
FOR i := 0 TO 255 DO |
delimiters[i] := FALSE |
END; |
delim := "+-*/~&.,;|([{^=#<>:)]}"; |
FOR i := 0 TO LEN(delim) - 2 DO |
delimiters[ORD(delim[i])] := TRUE |
END; |
enterKW("array", 0); |
enterKW("begin", 1); |
enterKW("by", 2); |
enterKW("case", 3); |
enterKW("const", 4); |
enterKW("div", 5); |
enterKW("do", 6); |
enterKW("else", 7); |
enterKW("elsif", 8); |
enterKW("end", 9); |
enterKW("false", 10); |
enterKW("for", 11); |
enterKW("if", 12); |
enterKW("import", 13); |
enterKW("in", 14); |
enterKW("is", 15); |
enterKW("mod", 16); |
enterKW("module", 17); |
enterKW("nil", 18); |
enterKW("of", 19); |
enterKW("or", 20); |
enterKW("pointer", 21); |
enterKW("procedure", 22); |
enterKW("record", 23); |
enterKW("repeat", 24); |
enterKW("return", 25); |
enterKW("then", 26); |
enterKW("to", 27); |
enterKW("true", 28); |
enterKW("type", 29); |
enterKW("until", 30); |
enterKW("var", 31); |
enterKW("while", 32) |
END init; |
PROCEDURE NewDef* (str: ARRAY OF CHAR); |
VAR |
item: DEF; |
BEGIN |
NEW(item); |
COPY(str, item.ident); |
LISTS.push(def, item) |
END NewDef; |
BEGIN |
def := LISTS.create(NIL); |
strings := LISTS.create(NIL) |
END SCAN. |
/programs/develop/oberon07/source/STATEMENTS.ob07 |
---|
0,0 → 1,3406 |
(* |
BSD 2-Clause License |
Copyright (c) 2018-2021, Anton Krotov |
All rights reserved. |
*) |
MODULE STATEMENTS; |
IMPORT |
PARS, PROG, SCAN, ARITH, STRINGS, LISTS, IL, X86, AMD64, MSP430, THUMB, RVMxI, |
ERRORS, UTILS, AVL := AVLTREES, CONSOLE, C := COLLECTIONS, TARGETS; |
CONST |
eCONST = PARS.eCONST; eTYPE = PARS.eTYPE; eVAR = PARS.eVAR; |
eEXPR = PARS.eEXPR; eVREC = PARS.eVREC; ePROC = PARS.ePROC; |
eVPAR = PARS.eVPAR; ePARAM = PARS.ePARAM; eSTPROC = PARS.eSTPROC; |
eSTFUNC = PARS.eSTFUNC; eSYSFUNC = PARS.eSYSFUNC; eSYSPROC = PARS.eSYSPROC; |
eIMP = PARS.eIMP; |
errASSERT = 1; errPTR = 2; errDIV = 3; errPROC = 4; |
errGUARD = 5; errIDX = 6; errCASE = 7; errCOPY = 8; |
errCHR = 9; errWCHR = 10; errBYTE = 11; |
chkIDX* = 0; chkGUARD* = 1; chkPTR* = 2; chkCHR* = 3; chkWCHR* = 4; chkBYTE* = 5; |
chkSTK* = MSP430.chkSTK; (* 6 *) |
chkALL* = {chkIDX, chkGUARD, chkPTR, chkCHR, chkWCHR, chkBYTE, chkSTK}; |
TYPE |
isXXX = PROCEDURE (e: PARS.EXPR): BOOLEAN; |
RANGE = RECORD |
a, b: INTEGER |
END; |
CASE_LABEL = POINTER TO rCASE_LABEL; |
rCASE_LABEL = RECORD (AVL.DATA) |
range: RANGE; |
variant, self: INTEGER; |
_type: PROG._TYPE; |
prev: CASE_LABEL |
END; |
CASE_VARIANT = POINTER TO RECORD (LISTS.ITEM) |
label: INTEGER; |
cmd: IL.COMMAND; |
processed: BOOLEAN |
END; |
VAR |
Options: PROG.OPTIONS; |
begcall, endcall: IL.COMMAND; |
CaseLabels, CaseVar: C.COLLECTION; |
CaseVariants: LISTS.LIST; |
CPU: INTEGER; |
tINTEGER, tBYTE, tCHAR, tWCHAR, tSET, tBOOLEAN, tREAL: PROG._TYPE; |
PROCEDURE isExpr (e: PARS.EXPR): BOOLEAN; |
RETURN e.obj IN {eCONST, eVAR, eEXPR, eVPAR, ePARAM, eVREC} |
END isExpr; |
PROCEDURE isVar (e: PARS.EXPR): BOOLEAN; |
RETURN e.obj IN {eVAR, eVPAR, ePARAM, eVREC} |
END isVar; |
PROCEDURE isBoolean (e: PARS.EXPR): BOOLEAN; |
RETURN isExpr(e) & (e._type = tBOOLEAN) |
END isBoolean; |
PROCEDURE isInteger (e: PARS.EXPR): BOOLEAN; |
RETURN isExpr(e) & (e._type = tINTEGER) |
END isInteger; |
PROCEDURE isByte (e: PARS.EXPR): BOOLEAN; |
RETURN isExpr(e) & (e._type = tBYTE) |
END isByte; |
PROCEDURE isInt (e: PARS.EXPR): BOOLEAN; |
RETURN isByte(e) OR isInteger(e) |
END isInt; |
PROCEDURE isReal (e: PARS.EXPR): BOOLEAN; |
RETURN isExpr(e) & (e._type = tREAL) |
END isReal; |
PROCEDURE isSet (e: PARS.EXPR): BOOLEAN; |
RETURN isExpr(e) & (e._type = tSET) |
END isSet; |
PROCEDURE isString (e: PARS.EXPR): BOOLEAN; |
RETURN (e.obj = eCONST) & (e._type.typ IN {PROG.tSTRING, PROG.tCHAR}) |
END isString; |
PROCEDURE isStringW (e: PARS.EXPR): BOOLEAN; |
RETURN (e.obj = eCONST) & (e._type.typ IN {PROG.tSTRING, PROG.tCHAR, PROG.tWCHAR}) |
END isStringW; |
PROCEDURE isChar (e: PARS.EXPR): BOOLEAN; |
RETURN isExpr(e) & (e._type = tCHAR) |
END isChar; |
PROCEDURE isCharW (e: PARS.EXPR): BOOLEAN; |
RETURN isExpr(e) & (e._type = tWCHAR) |
END isCharW; |
PROCEDURE isPtr (e: PARS.EXPR): BOOLEAN; |
RETURN isExpr(e) & (e._type.typ = PROG.tPOINTER) |
END isPtr; |
PROCEDURE isRec (e: PARS.EXPR): BOOLEAN; |
RETURN isExpr(e) & (e._type.typ = PROG.tRECORD) |
END isRec; |
PROCEDURE isRecPtr (e: PARS.EXPR): BOOLEAN; |
RETURN isRec(e) OR isPtr(e) |
END isRecPtr; |
PROCEDURE isArr (e: PARS.EXPR): BOOLEAN; |
RETURN isExpr(e) & (e._type.typ = PROG.tARRAY) |
END isArr; |
PROCEDURE isProc (e: PARS.EXPR): BOOLEAN; |
RETURN isExpr(e) & (e._type.typ = PROG.tPROCEDURE) OR (e.obj IN {ePROC, eIMP}) |
END isProc; |
PROCEDURE isNil (e: PARS.EXPR): BOOLEAN; |
RETURN e._type.typ = PROG.tNIL |
END isNil; |
PROCEDURE isCharArray (e: PARS.EXPR): BOOLEAN; |
RETURN isArr(e) & (e._type.base = tCHAR) |
END isCharArray; |
PROCEDURE isCharArrayW (e: PARS.EXPR): BOOLEAN; |
RETURN isArr(e) & (e._type.base = tWCHAR) |
END isCharArrayW; |
PROCEDURE isCharArrayX (e: PARS.EXPR): BOOLEAN; |
RETURN isCharArray(e) OR isCharArrayW(e) |
END isCharArrayX; |
PROCEDURE getpos (parser: PARS.PARSER; VAR pos: PARS.POSITION); |
BEGIN |
pos.line := parser.lex.pos.line; |
pos.col := parser.lex.pos.col; |
pos.parser := parser |
END getpos; |
PROCEDURE NextPos (parser: PARS.PARSER; VAR pos: PARS.POSITION); |
BEGIN |
PARS.Next(parser); |
getpos(parser, pos) |
END NextPos; |
PROCEDURE strlen (e: PARS.EXPR): INTEGER; |
VAR |
res: INTEGER; |
BEGIN |
ASSERT(isString(e)); |
IF e._type = tCHAR THEN |
res := 1 |
ELSE |
res := LENGTH(e.value.string(SCAN.STRING).s) |
END |
RETURN res |
END strlen; |
PROCEDURE _length (s: ARRAY OF CHAR): INTEGER; |
VAR |
i, res: INTEGER; |
BEGIN |
i := 0; |
res := 0; |
WHILE (i < LEN(s)) & (s[i] # 0X) DO |
IF (s[i] <= CHR(127)) OR (s[i] >= CHR(192)) THEN |
INC(res) |
END; |
INC(i) |
END |
RETURN res |
END _length; |
PROCEDURE utf8strlen (e: PARS.EXPR): INTEGER; |
VAR |
res: INTEGER; |
BEGIN |
ASSERT(isStringW(e)); |
IF e._type.typ IN {PROG.tCHAR, PROG.tWCHAR} THEN |
res := 1 |
ELSE |
res := _length(e.value.string(SCAN.STRING).s) |
END |
RETURN res |
END utf8strlen; |
PROCEDURE StrToWChar (s: ARRAY OF CHAR): INTEGER; |
VAR |
res: ARRAY 2 OF WCHAR; |
BEGIN |
ASSERT(STRINGS.Utf8To16(s, res) = 1) |
RETURN ORD(res[0]) |
END StrToWChar; |
PROCEDURE isStringW1 (e: PARS.EXPR): BOOLEAN; |
RETURN isString(e) & (utf8strlen(e) = 1) & (strlen(e) > 1) |
END isStringW1; |
PROCEDURE assigncomp (e: PARS.EXPR; t: PROG._TYPE): BOOLEAN; |
VAR |
res: BOOLEAN; |
BEGIN |
IF isExpr(e) OR (e.obj IN {ePROC, eIMP}) THEN |
IF t = e._type THEN |
res := TRUE |
ELSIF isInt(e) & (t.typ IN {PROG.tBYTE, PROG.tINTEGER}) THEN |
IF (e.obj = eCONST) & (t = tBYTE) THEN |
res := ARITH.range(e.value, 0, 255) |
ELSE |
res := TRUE |
END |
ELSIF |
(e.obj = eCONST) & isChar(e) & (t = tWCHAR) |
OR isStringW1(e) & (t = tWCHAR) |
OR PROG.isBaseOf(t, e._type) |
OR ~PROG.isOpenArray(t) & ~PROG.isOpenArray(e._type) & PROG.isTypeEq(t, e._type) |
OR isNil(e) & (t.typ IN {PROG.tPOINTER, PROG.tPROCEDURE}) |
OR PROG.arrcomp(e._type, t) |
OR isString(e) & (t.typ = PROG.tARRAY) & (t.base = tCHAR) & (t.length > strlen(e)) |
OR isStringW(e) & (t.typ = PROG.tARRAY) & (t.base = tWCHAR) & (t.length > utf8strlen(e)) |
THEN |
res := TRUE |
ELSE |
res := FALSE |
END |
ELSE |
res := FALSE |
END |
RETURN res |
END assigncomp; |
PROCEDURE String (e: PARS.EXPR): INTEGER; |
VAR |
offset: INTEGER; |
string: SCAN.STRING; |
BEGIN |
IF strlen(e) # 1 THEN |
string := e.value.string(SCAN.STRING); |
IF string.offset = -1 THEN |
string.offset := IL.putstr(string.s); |
END; |
offset := string.offset |
ELSE |
offset := IL.putstr1(ARITH.Int(e.value)) |
END |
RETURN offset |
END String; |
PROCEDURE StringW (e: PARS.EXPR): INTEGER; |
VAR |
offset: INTEGER; |
string: SCAN.STRING; |
BEGIN |
IF utf8strlen(e) # 1 THEN |
string := e.value.string(SCAN.STRING); |
IF string.offsetW = -1 THEN |
string.offsetW := IL.putstrW(string.s); |
END; |
offset := string.offsetW |
ELSE |
IF e._type.typ IN {PROG.tWCHAR, PROG.tCHAR} THEN |
offset := IL.putstrW1(ARITH.Int(e.value)) |
ELSE (* e._type.typ = PROG.tSTRING *) |
string := e.value.string(SCAN.STRING); |
IF string.offsetW = -1 THEN |
string.offsetW := IL.putstrW(string.s); |
END; |
offset := string.offsetW |
END |
END |
RETURN offset |
END StringW; |
PROCEDURE CheckRange (range, line, errno: INTEGER); |
VAR |
label: INTEGER; |
BEGIN |
label := IL.NewLabel(); |
IL.AddCmd2(IL.opCHKIDX, label, range); |
IL.OnError(line, errno); |
IL.SetLabel(label) |
END CheckRange; |
PROCEDURE Float (parser: PARS.PARSER; e: PARS.EXPR); |
VAR |
pos: PARS.POSITION; |
BEGIN |
getpos(parser, pos); |
IL.Float(ARITH.Float(e.value), pos.line, pos.col) |
END Float; |
PROCEDURE assign (parser: PARS.PARSER; e: PARS.EXPR; VarType: PROG._TYPE; line: INTEGER): BOOLEAN; |
VAR |
res: BOOLEAN; |
label: INTEGER; |
BEGIN |
IF isExpr(e) OR (e.obj IN {ePROC, eIMP}) THEN |
res := TRUE; |
IF PROG.arrcomp(e._type, VarType) THEN |
IF ~PROG.isOpenArray(VarType) THEN |
IL.Const(VarType.length) |
END; |
IL.AddCmd(IL.opCOPYA, VarType.base.size); |
label := IL.NewLabel(); |
IL.Jmp(IL.opJNZ, label); |
IL.OnError(line, errCOPY); |
IL.SetLabel(label) |
ELSIF isInt(e) & (VarType.typ IN {PROG.tBYTE, PROG.tINTEGER}) THEN |
IF VarType = tINTEGER THEN |
IF e.obj = eCONST THEN |
IL.AddCmd(IL.opSAVEC, ARITH.Int(e.value)) |
ELSE |
IL.AddCmd0(IL.opSAVE) |
END |
ELSE |
IF e.obj = eCONST THEN |
res := ARITH.range(e.value, 0, 255); |
IF res THEN |
IL.AddCmd(IL.opSAVE8C, ARITH.Int(e.value)) |
END |
ELSE |
IF chkBYTE IN Options.checking THEN |
label := IL.NewLabel(); |
IL.AddCmd2(IL.opCHKBYTE, label, 0); |
IL.OnError(line, errBYTE); |
IL.SetLabel(label) |
END; |
IL.AddCmd0(IL.opSAVE8) |
END |
END |
ELSIF isSet(e) & (VarType = tSET) THEN |
IF e.obj = eCONST THEN |
IL.AddCmd(IL.opSAVEC, ARITH.Int(e.value)) |
ELSE |
IL.AddCmd0(IL.opSAVE) |
END |
ELSIF isBoolean(e) & (VarType = tBOOLEAN) THEN |
IF e.obj = eCONST THEN |
IL.AddCmd(IL.opSBOOLC, ARITH.Int(e.value)) |
ELSE |
IL.AddCmd0(IL.opSBOOL) |
END |
ELSIF isReal(e) & (VarType = tREAL) THEN |
IF e.obj = eCONST THEN |
Float(parser, e) |
END; |
IL.savef(e.obj = eCONST) |
ELSIF isChar(e) & (VarType = tCHAR) THEN |
IF e.obj = eCONST THEN |
IL.AddCmd(IL.opSAVE8C, ARITH.Int(e.value)) |
ELSE |
IL.AddCmd0(IL.opSAVE8) |
END |
ELSIF (e.obj = eCONST) & isChar(e) & (VarType = tWCHAR) THEN |
IL.AddCmd(IL.opSAVE16C, ARITH.Int(e.value)) |
ELSIF isStringW1(e) & (VarType = tWCHAR) THEN |
IL.AddCmd(IL.opSAVE16C, StrToWChar(e.value.string(SCAN.STRING).s)) |
ELSIF isCharW(e) & (VarType = tWCHAR) THEN |
IF e.obj = eCONST THEN |
IL.AddCmd(IL.opSAVE16C, ARITH.Int(e.value)) |
ELSE |
IL.AddCmd0(IL.opSAVE16) |
END |
ELSIF PROG.isBaseOf(VarType, e._type) THEN |
IF VarType.typ = PROG.tPOINTER THEN |
IL.AddCmd0(IL.opSAVE) |
ELSE |
IL.AddCmd(IL.opCOPY, VarType.size) |
END |
ELSIF (e._type.typ = PROG.tCARD32) & (VarType.typ = PROG.tCARD32) THEN |
IL.AddCmd0(IL.opSAVE32) |
ELSIF ~PROG.isOpenArray(VarType) & ~PROG.isOpenArray(e._type) & PROG.isTypeEq(VarType, e._type) THEN |
IF e.obj = ePROC THEN |
IL.AssignProc(e.ident.proc.label) |
ELSIF e.obj = eIMP THEN |
IL.AssignImpProc(e.ident._import) |
ELSE |
IF VarType.typ = PROG.tPROCEDURE THEN |
IL.AddCmd0(IL.opSAVE) |
ELSE |
IL.AddCmd(IL.opCOPY, VarType.size) |
END |
END |
ELSIF isNil(e) & (VarType.typ IN {PROG.tPOINTER, PROG.tPROCEDURE}) THEN |
IL.AddCmd(IL.opSAVEC, 0) |
ELSIF isString(e) & ((VarType.typ = PROG.tARRAY) & (VarType.base = tCHAR) & (VarType.length > strlen(e))) THEN |
IL.saves(String(e), strlen(e) + 1) |
ELSIF isStringW(e) & ((VarType.typ = PROG.tARRAY) & (VarType.base = tWCHAR) & (VarType.length > utf8strlen(e))) THEN |
IL.saves(StringW(e), (utf8strlen(e) + 1) * 2) |
ELSE |
res := FALSE |
END |
ELSE |
res := FALSE |
END |
RETURN res |
END assign; |
PROCEDURE LoadConst (e: PARS.EXPR); |
BEGIN |
IL.Const(ARITH.Int(e.value)) |
END LoadConst; |
PROCEDURE paramcomp (parser: PARS.PARSER; pos: PARS.POSITION; e: PARS.EXPR; p: PROG.PARAM); |
VAR |
stroffs: INTEGER; |
PROCEDURE arrcomp (e: PARS.EXPR; p: PROG.PARAM): BOOLEAN; |
VAR |
t1, t2: PROG._TYPE; |
BEGIN |
t1 := p._type; |
t2 := e._type; |
WHILE (t2.typ = PROG.tARRAY) & PROG.isOpenArray(t1) DO |
t1 := t1.base; |
t2 := t2.base |
END |
RETURN PROG.isTypeEq(t1, t2) |
END arrcomp; |
PROCEDURE ArrLen (t: PROG._TYPE; n: INTEGER): INTEGER; |
VAR |
res: INTEGER; |
BEGIN |
REPEAT |
res := t.length; |
t := t.base; |
DEC(n) |
UNTIL (n < 0) OR (t.typ # PROG.tARRAY); |
ASSERT(n < 0) |
RETURN res |
END ArrLen; |
PROCEDURE OpenArray (t, t2: PROG._TYPE); |
VAR |
n, d1, d2: INTEGER; |
BEGIN |
IF t.length # 0 THEN |
IL.Param1; |
n := PROG.Dim(t2) - 1; |
WHILE n >= 0 DO |
IL.Const(ArrLen(t, n)); |
IL.Param1; |
DEC(n) |
END |
ELSE |
d1 := PROG.Dim(t); |
d2 := PROG.Dim(t2); |
IF d1 # d2 THEN |
n := d2 - d1; |
WHILE d2 > d1 DO |
IL.Const(ArrLen(t, d2 - 1)); |
DEC(d2) |
END; |
d2 := PROG.Dim(t2); |
WHILE n > 0 DO |
IL.AddCmd(IL.opROT, d2); |
DEC(n) |
END |
END; |
IL.AddCmd(IL.opPARAM, PROG.Dim(t2) + 1) |
END |
END OpenArray; |
BEGIN |
IF p.vPar THEN |
PARS.check(isVar(e), pos, 93); |
IF p._type.typ = PROG.tRECORD THEN |
PARS.check(PROG.isBaseOf(p._type, e._type), pos, 66); |
IF e.obj = eVREC THEN |
IF e.ident # NIL THEN |
IL.AddCmd(IL.opVADR, e.ident.offset - 1) |
ELSE |
IL.AddCmd0(IL.opPUSHT) |
END |
ELSE |
IL.Const(e._type.num) |
END; |
IL.AddCmd(IL.opPARAM, 2) |
ELSIF PROG.isOpenArray(p._type) THEN |
PARS.check(arrcomp(e, p), pos, 66); |
OpenArray(e._type, p._type) |
ELSE |
PARS.check(PROG.isTypeEq(e._type, p._type), pos, 66); |
IL.Param1 |
END; |
PARS.check(~e.readOnly, pos, 94) |
ELSE |
PARS.check(isExpr(e) OR isProc(e), pos, 66); |
IF PROG.isOpenArray(p._type) THEN |
IF e._type.typ = PROG.tARRAY THEN |
PARS.check(arrcomp(e, p), pos, 66); |
OpenArray(e._type, p._type) |
ELSIF isString(e) & (p._type.typ = PROG.tARRAY) & (p._type.base = tCHAR) THEN |
IL.StrAdr(String(e)); |
IL.Param1; |
IL.Const(strlen(e) + 1); |
IL.Param1 |
ELSIF isStringW(e) & (p._type.typ = PROG.tARRAY) & (p._type.base = tWCHAR) THEN |
IL.StrAdr(StringW(e)); |
IL.Param1; |
IL.Const(utf8strlen(e) + 1); |
IL.Param1 |
ELSE |
PARS.error(pos, 66) |
END |
ELSE |
PARS.check(~PROG.isOpenArray(e._type), pos, 66); |
PARS.check(assigncomp(e, p._type), pos, 66); |
IF e.obj = eCONST THEN |
IF e._type = tREAL THEN |
Float(parser, e); |
IL.AddCmd0(IL.opPUSHF) |
ELSIF e._type.typ = PROG.tNIL THEN |
IL.Const(0); |
IL.Param1 |
ELSIF isStringW1(e) & (p._type = tWCHAR) THEN |
IL.Const(StrToWChar(e.value.string(SCAN.STRING).s)); |
IL.Param1 |
ELSIF (e._type.typ = PROG.tSTRING) OR |
(e._type.typ IN {PROG.tCHAR, PROG.tWCHAR}) & (p._type.typ = PROG.tARRAY) & (p._type.base.typ IN {PROG.tCHAR, PROG.tWCHAR}) THEN |
IF p._type.base = tCHAR THEN |
stroffs := String(e); |
IL.StrAdr(stroffs); |
IF (CPU = TARGETS.cpuMSP430) & (p._type.size - strlen(e) - 1 > MSP430.IntVectorSize) THEN |
ERRORS.WarningMsg(pos.line, pos.col, 0) |
END |
ELSE (* WCHAR *) |
stroffs := StringW(e); |
IL.StrAdr(stroffs) |
END; |
IL.set_dmin(stroffs + p._type.size); |
IL.Param1 |
ELSE |
LoadConst(e); |
IL.Param1 |
END |
ELSIF e.obj = ePROC THEN |
PARS.check(e.ident.global, pos, 85); |
IL.PushProc(e.ident.proc.label); |
IL.Param1 |
ELSIF e.obj = eIMP THEN |
IL.PushImpProc(e.ident._import); |
IL.Param1 |
ELSIF isExpr(e) & (e._type = tREAL) THEN |
IL.AddCmd0(IL.opPUSHF) |
ELSE |
IF (p._type = tBYTE) & (e._type = tINTEGER) & (chkBYTE IN Options.checking) THEN |
CheckRange(256, pos.line, errBYTE) |
END; |
IL.Param1 |
END |
END |
END |
END paramcomp; |
PROCEDURE PExpression (parser: PARS.PARSER; VAR e: PARS.EXPR); |
BEGIN |
parser.expression(parser, e) |
END PExpression; |
PROCEDURE stProc (parser: PARS.PARSER; VAR e: PARS.EXPR); |
VAR |
e1, e2: PARS.EXPR; |
pos: PARS.POSITION; |
proc, |
label, |
size, |
n, i: INTEGER; |
code: ARITH.VALUE; |
wchar, |
comma: BOOLEAN; |
cmd1, |
cmd2: IL.COMMAND; |
PROCEDURE varparam (parser: PARS.PARSER; pos: PARS.POSITION; isfunc: isXXX; readOnly: BOOLEAN; VAR e: PARS.EXPR); |
BEGIN |
parser.designator(parser, e); |
PARS.check(isVar(e), pos, 93); |
PARS.check(isfunc(e), pos, 66); |
IF readOnly THEN |
PARS.check(~e.readOnly, pos, 94) |
END |
END varparam; |
PROCEDURE shift_minmax (proc: INTEGER): CHAR; |
VAR |
res: CHAR; |
BEGIN |
CASE proc OF |
|PROG.stASR: res := "A" |
|PROG.stLSL: res := "L" |
|PROG.stROR: res := "O" |
|PROG.stLSR: res := "R" |
|PROG.stMIN: res := "m" |
|PROG.stMAX: res := "x" |
END |
RETURN res |
END shift_minmax; |
BEGIN |
ASSERT(e.obj IN {eSTPROC, eSTFUNC, eSYSPROC, eSYSFUNC}); |
proc := e.stproc; |
(* IF (proc # PROG.sysNOP) & (proc # PROG.sysEINT) & (proc # PROG.sysDINT) THEN *) |
PARS.checklex(parser, SCAN.lxLROUND); |
PARS.Next(parser); |
(* END; *) |
getpos(parser, pos); |
IF e.obj IN {eSTPROC, eSYSPROC} THEN |
CASE proc OF |
|PROG.stASSERT: |
PExpression(parser, e); |
PARS.check(isBoolean(e), pos, 66); |
IF e.obj = eCONST THEN |
IF ~ARITH.getBool(e.value) THEN |
IL.OnError(pos.line, errASSERT) |
END |
ELSE |
label := IL.NewLabel(); |
IL.not; |
IL.AndOrOpt(label); |
IL.OnError(pos.line, errASSERT); |
IL.SetLabel(label) |
END |
|PROG.stINC, PROG.stDEC: |
IL.pushBegEnd(begcall, endcall); |
varparam(parser, pos, isInt, TRUE, e); |
IF e._type = tINTEGER THEN |
IF parser.sym = SCAN.lxCOMMA THEN |
NextPos(parser, pos); |
IL.setlast(begcall); |
PExpression(parser, e2); |
IL.setlast(endcall.prev(IL.COMMAND)); |
PARS.check(isInt(e2), pos, 66); |
IF e2.obj = eCONST THEN |
IL.AddCmd(IL.opINCC, ARITH.Int(e2.value) * (ORD(proc = PROG.stINC) * 2 - 1)) |
ELSE |
IL.AddCmd0(IL.opINC + ORD(proc = PROG.stDEC)) |
END |
ELSE |
IL.AddCmd(IL.opINCC, ORD(proc = PROG.stINC) * 2 - 1) |
END |
ELSE (* e._type = tBYTE *) |
IF parser.sym = SCAN.lxCOMMA THEN |
NextPos(parser, pos); |
IL.setlast(begcall); |
PExpression(parser, e2); |
IL.setlast(endcall.prev(IL.COMMAND)); |
PARS.check(isInt(e2), pos, 66); |
IF e2.obj = eCONST THEN |
IL.AddCmd(IL.opINCCB + ORD(proc = PROG.stDEC), ARITH.Int(e2.value)) |
ELSE |
IL.AddCmd0(IL.opINCB + ORD(proc = PROG.stDEC)) |
END |
ELSE |
IL.AddCmd(IL.opINCCB + ORD(proc = PROG.stDEC), 1) |
END |
END; |
IL.popBegEnd(begcall, endcall) |
|PROG.stINCL, PROG.stEXCL: |
IL.pushBegEnd(begcall, endcall); |
varparam(parser, pos, isSet, TRUE, e); |
PARS.checklex(parser, SCAN.lxCOMMA); |
NextPos(parser, pos); |
IL.setlast(begcall); |
PExpression(parser, e2); |
IL.setlast(endcall.prev(IL.COMMAND)); |
PARS.check(isInt(e2), pos, 66); |
IF e2.obj = eCONST THEN |
PARS.check(ARITH.range(e2.value, 0, UTILS.target.maxSet), pos, 56); |
IL.AddCmd(IL.opINCLC + ORD(proc = PROG.stEXCL), ARITH.Int(e2.value)) |
ELSE |
IL.AddCmd0(IL.opINCL + ORD(proc = PROG.stEXCL)) |
END; |
IL.popBegEnd(begcall, endcall) |
|PROG.stNEW: |
varparam(parser, pos, isPtr, TRUE, e); |
IF CPU = TARGETS.cpuMSP430 THEN |
PARS.check(e._type.base.size + 16 < Options.ram, pos, 63) |
END; |
IL.New(e._type.base.size, e._type.base.num) |
|PROG.stDISPOSE: |
varparam(parser, pos, isPtr, TRUE, e); |
IL.AddCmd0(IL.opDISP) |
|PROG.stPACK: |
varparam(parser, pos, isReal, TRUE, e); |
PARS.checklex(parser, SCAN.lxCOMMA); |
NextPos(parser, pos); |
PExpression(parser, e2); |
PARS.check(isInt(e2), pos, 66); |
IF e2.obj = eCONST THEN |
IL.AddCmd(IL.opPACKC, ARITH.Int(e2.value)) |
ELSE |
IL.AddCmd0(IL.opPACK) |
END |
|PROG.stUNPK: |
varparam(parser, pos, isReal, TRUE, e); |
PARS.checklex(parser, SCAN.lxCOMMA); |
NextPos(parser, pos); |
varparam(parser, pos, isInteger, TRUE, e2); |
IL.AddCmd0(IL.opUNPK) |
|PROG.stCOPY: |
IL.pushBegEnd(begcall, endcall); |
PExpression(parser, e); |
IF isString(e) OR isCharArray(e) THEN |
wchar := FALSE |
ELSIF isStringW(e) OR isCharArrayW(e) THEN |
wchar := TRUE |
ELSE |
PARS.error(pos, 66) |
END; |
IF isCharArrayX(e) & ~PROG.isOpenArray(e._type) THEN |
IL.Const(e._type.length) |
END; |
PARS.checklex(parser, SCAN.lxCOMMA); |
NextPos(parser, pos); |
IL.setlast(begcall); |
IF wchar THEN |
varparam(parser, pos, isCharArrayW, TRUE, e1) |
ELSE |
IF e.obj = eCONST THEN |
varparam(parser, pos, isCharArrayX, TRUE, e1) |
ELSE |
varparam(parser, pos, isCharArray, TRUE, e1) |
END; |
wchar := e1._type.base = tWCHAR |
END; |
IF ~PROG.isOpenArray(e1._type) THEN |
IL.Const(e1._type.length) |
END; |
IL.setlast(endcall.prev(IL.COMMAND)); |
IF e.obj = eCONST THEN |
IF wchar THEN |
IL.StrAdr(StringW(e)); |
IL.Const(utf8strlen(e) + 1) |
ELSE |
IL.StrAdr(String(e)); |
IL.Const(strlen(e) + 1) |
END |
END; |
IL.AddCmd(IL.opCOPYS, e1._type.base.size); |
IL.popBegEnd(begcall, endcall) |
|PROG.sysGET, PROG.sysGET8, PROG.sysGET16, PROG.sysGET32: |
PExpression(parser, e); |
PARS.check(isInt(e), pos, 66); |
PARS.checklex(parser, SCAN.lxCOMMA); |
NextPos(parser, pos); |
parser.designator(parser, e2); |
PARS.check(isVar(e2), pos, 93); |
IF proc = PROG.sysGET THEN |
PARS.check(e2._type.typ IN PROG.BASICTYPES + {PROG.tPOINTER, PROG.tPROCEDURE}, pos, 66) |
ELSE |
PARS.check(e2._type.typ IN {PROG.tINTEGER, PROG.tBYTE, PROG.tCHAR, PROG.tSET, PROG.tWCHAR, PROG.tCARD32}, pos, 66) |
END; |
CASE proc OF |
|PROG.sysGET: size := e2._type.size |
|PROG.sysGET8: size := 1 |
|PROG.sysGET16: size := 2 |
|PROG.sysGET32: size := 4 |
END; |
PARS.check(size <= e2._type.size, pos, 66); |
IF e.obj = eCONST THEN |
IL.AddCmd2(IL.opGETC, ARITH.Int(e.value), size) |
ELSE |
IL.AddCmd(IL.opGET, size) |
END |
|PROG.sysPUT, PROG.sysPUT8, PROG.sysPUT16, PROG.sysPUT32: |
IL.pushBegEnd(begcall, endcall); |
PExpression(parser, e); |
PARS.check(isInt(e), pos, 66); |
IF e.obj = eCONST THEN |
LoadConst(e) |
END; |
PARS.checklex(parser, SCAN.lxCOMMA); |
NextPos(parser, pos); |
IL.setlast(begcall); |
PExpression(parser, e2); |
PARS.check(isExpr(e2), pos, 66); |
IF proc = PROG.sysPUT THEN |
PARS.check(e2._type.typ IN PROG.BASICTYPES + {PROG.tPOINTER, PROG.tPROCEDURE}, pos, 66); |
IF e2.obj = eCONST THEN |
IF e2._type = tREAL THEN |
Float(parser, e2); |
IL.setlast(endcall.prev(IL.COMMAND)); |
IL.savef(FALSE) |
ELSE |
LoadConst(e2); |
IL.setlast(endcall.prev(IL.COMMAND)); |
IL.SysPut(e2._type.size) |
END |
ELSE |
IL.setlast(endcall.prev(IL.COMMAND)); |
IF e2._type = tREAL THEN |
IL.savef(FALSE) |
ELSIF e2._type = tBYTE THEN |
IL.SysPut(tINTEGER.size) |
ELSE |
IL.SysPut(e2._type.size) |
END |
END |
ELSIF (proc = PROG.sysPUT8) OR (proc = PROG.sysPUT16) OR (proc = PROG.sysPUT32) THEN |
PARS.check(e2._type.typ IN {PROG.tINTEGER, PROG.tBYTE, PROG.tCHAR, PROG.tSET, PROG.tWCHAR, PROG.tCARD32}, pos, 66); |
IF e2.obj = eCONST THEN |
LoadConst(e2) |
END; |
IL.setlast(endcall.prev(IL.COMMAND)); |
CASE proc OF |
|PROG.sysPUT8: size := 1 |
|PROG.sysPUT16: size := 2 |
|PROG.sysPUT32: size := 4 |
END; |
IL.SysPut(size) |
END; |
IL.popBegEnd(begcall, endcall) |
|PROG.sysMOVE: |
FOR i := 1 TO 2 DO |
PExpression(parser, e); |
PARS.check(isInt(e), pos, 66); |
IF e.obj = eCONST THEN |
LoadConst(e) |
END; |
PARS.checklex(parser, SCAN.lxCOMMA); |
NextPos(parser, pos) |
END; |
PExpression(parser, e); |
PARS.check(isInt(e), pos, 66); |
IF e.obj = eCONST THEN |
LoadConst(e) |
END; |
IL.AddCmd0(IL.opMOVE) |
|PROG.sysCOPY: |
FOR i := 1 TO 2 DO |
parser.designator(parser, e); |
PARS.check(isVar(e), pos, 93); |
n := PROG.Dim(e._type); |
WHILE n > 0 DO |
IL.drop; |
DEC(n) |
END; |
PARS.checklex(parser, SCAN.lxCOMMA); |
NextPos(parser, pos) |
END; |
PExpression(parser, e); |
PARS.check(isInt(e), pos, 66); |
IF e.obj = eCONST THEN |
LoadConst(e) |
END; |
IL.AddCmd0(IL.opMOVE) |
|PROG.sysCODE: |
REPEAT |
getpos(parser, pos); |
PARS.ConstExpression(parser, code); |
PARS.check(code.typ = ARITH.tINTEGER, pos, 43); |
IF TARGETS.WordSize > TARGETS.InstrSize THEN |
CASE TARGETS.InstrSize OF |
|1: PARS.check(ARITH.range(code, 0, 255), pos, 42) |
|2: PARS.check(ARITH.range(code, 0, 65535), pos, 110) |
END |
END; |
IL.AddCmd(IL.opCODE, ARITH.getInt(code)); |
comma := parser.sym = SCAN.lxCOMMA; |
IF comma THEN |
PARS.Next(parser) |
ELSE |
PARS.checklex(parser, SCAN.lxRROUND) |
END |
UNTIL (parser.sym = SCAN.lxRROUND) & ~comma |
(* |
|PROG.sysNOP, PROG.sysDINT, PROG.sysEINT: |
IF parser.sym = SCAN.lxLROUND THEN |
PARS.Next(parser); |
PARS.checklex(parser, SCAN.lxRROUND); |
PARS.Next(parser) |
END; |
ASSERT(CPU = cpuMSP430); |
CASE proc OF |
|PROG.sysNOP: IL.AddCmd(IL.opCODE, 4303H) |
|PROG.sysDINT: IL.AddCmd(IL.opCODE, 0C232H); IL.AddCmd(IL.opCODE, 4303H) |
|PROG.sysEINT: IL.AddCmd(IL.opCODE, 0D232H) |
END |
*) |
END; |
e.obj := eEXPR; |
e._type := NIL |
ELSIF e.obj IN {eSTFUNC, eSYSFUNC} THEN |
CASE e.stproc OF |
|PROG.stABS: |
PExpression(parser, e); |
PARS.check(isInt(e) OR isReal(e), pos, 66); |
IF e.obj = eCONST THEN |
PARS.check(ARITH.abs(e.value), pos, 39) |
ELSE |
IL.abs(isReal(e)) |
END |
|PROG.stASR, PROG.stLSL, PROG.stROR, PROG.stLSR, PROG.stMIN, PROG.stMAX: |
PExpression(parser, e); |
PARS.check(isInt(e), pos, 66); |
PARS.checklex(parser, SCAN.lxCOMMA); |
NextPos(parser, pos); |
PExpression(parser, e2); |
PARS.check(isInt(e2), pos, 66); |
e._type := tINTEGER; |
IF (e.obj = eCONST) & (e2.obj = eCONST) THEN |
ASSERT(ARITH.opInt(e.value, e2.value, shift_minmax(proc))) |
ELSE |
IF e.obj = eCONST THEN |
IL.shift_minmax1(shift_minmax(proc), ARITH.Int(e.value)) |
ELSIF e2.obj = eCONST THEN |
IL.shift_minmax2(shift_minmax(proc), ARITH.Int(e2.value)) |
ELSE |
IL.shift_minmax(shift_minmax(proc)) |
END; |
e.obj := eEXPR |
END |
|PROG.stCHR: |
PExpression(parser, e); |
PARS.check(isInt(e), pos, 66); |
e._type := tCHAR; |
IF e.obj = eCONST THEN |
ARITH.setChar(e.value, ARITH.getInt(e.value)); |
PARS.check(ARITH.check(e.value), pos, 107) |
ELSE |
IF chkCHR IN Options.checking THEN |
CheckRange(256, pos.line, errCHR) |
ELSE |
IL.AddCmd0(IL.opCHR) |
END |
END |
|PROG.stWCHR: |
PExpression(parser, e); |
PARS.check(isInt(e), pos, 66); |
e._type := tWCHAR; |
IF e.obj = eCONST THEN |
ARITH.setWChar(e.value, ARITH.getInt(e.value)); |
PARS.check(ARITH.check(e.value), pos, 101) |
ELSE |
IF chkWCHR IN Options.checking THEN |
CheckRange(65536, pos.line, errWCHR) |
ELSE |
IL.AddCmd0(IL.opWCHR) |
END |
END |
|PROG.stFLOOR: |
PExpression(parser, e); |
PARS.check(isReal(e), pos, 66); |
e._type := tINTEGER; |
IF e.obj = eCONST THEN |
PARS.check(ARITH.floor(e.value), pos, 39) |
ELSE |
IL.AddCmd0(IL.opFLOOR) |
END |
|PROG.stFLT: |
PExpression(parser, e); |
PARS.check(isInt(e), pos, 66); |
e._type := tREAL; |
IF e.obj = eCONST THEN |
ARITH.flt(e.value) |
ELSE |
IL.AddCmd2(IL.opFLT, pos.line, pos.col) |
END |
|PROG.stLEN: |
cmd1 := IL.getlast(); |
varparam(parser, pos, isArr, FALSE, e); |
IF e._type.length > 0 THEN |
cmd2 := IL.getlast(); |
IL.delete2(cmd1.next, cmd2); |
IL.setlast(cmd1); |
ASSERT(ARITH.setInt(e.value, e._type.length)); |
e.obj := eCONST |
ELSE |
IL.len(PROG.Dim(e._type)) |
END; |
e._type := tINTEGER |
|PROG.stLENGTH: |
PExpression(parser, e); |
IF isCharArray(e) THEN |
IF e._type.length > 0 THEN |
IL.Const(e._type.length) |
END; |
IL.AddCmd0(IL.opLENGTH) |
ELSIF isCharArrayW(e) THEN |
IF e._type.length > 0 THEN |
IL.Const(e._type.length) |
END; |
IL.AddCmd0(IL.opLENGTHW) |
ELSE |
PARS.error(pos, 66); |
END; |
e._type := tINTEGER |
|PROG.stODD: |
PExpression(parser, e); |
PARS.check(isInt(e), pos, 66); |
e._type := tBOOLEAN; |
IF e.obj = eCONST THEN |
ARITH.odd(e.value) |
ELSE |
IL.AddCmd(IL.opMODR, 2) |
END |
|PROG.stORD: |
IL.AddCmd(IL.opPRECALL, 0); |
PExpression(parser, e); |
PARS.check(isChar(e) OR isBoolean(e) OR isSet(e) OR isCharW(e) OR isStringW1(e), pos, 66); |
IF e.obj = eCONST THEN |
IF isStringW1(e) THEN |
ASSERT(ARITH.setInt(e.value, StrToWChar(e.value.string(SCAN.STRING).s))) |
ELSE |
ARITH.ord(e.value) |
END |
ELSE |
IF isBoolean(e) THEN |
IL._ord |
END |
END; |
e._type := tINTEGER |
|PROG.stBITS: |
PExpression(parser, e); |
PARS.check(isInt(e), pos, 66); |
IF e.obj = eCONST THEN |
ARITH.bits(e.value) |
END; |
e._type := tSET |
|PROG.sysADR: |
parser.designator(parser, e); |
IF isVar(e) THEN |
n := PROG.Dim(e._type); |
WHILE n > 0 DO |
IL.drop; |
DEC(n) |
END |
ELSIF e.obj = ePROC THEN |
IL.PushProc(e.ident.proc.label) |
ELSIF e.obj = eIMP THEN |
IL.PushImpProc(e.ident._import) |
ELSE |
PARS.error(pos, 108) |
END; |
e._type := tINTEGER |
|PROG.sysSADR: |
PExpression(parser, e); |
PARS.check(isString(e), pos, 66); |
IL.StrAdr(String(e)); |
e._type := tINTEGER; |
e.obj := eEXPR |
|PROG.sysWSADR: |
PExpression(parser, e); |
PARS.check(isStringW(e), pos, 66); |
IL.StrAdr(StringW(e)); |
e._type := tINTEGER; |
e.obj := eEXPR |
|PROG.sysTYPEID: |
PExpression(parser, e); |
PARS.check(e.obj = eTYPE, pos, 68); |
IF e._type.typ = PROG.tRECORD THEN |
ASSERT(ARITH.setInt(e.value, e._type.num)) |
ELSIF e._type.typ = PROG.tPOINTER THEN |
ASSERT(ARITH.setInt(e.value, e._type.base.num)) |
ELSE |
PARS.error(pos, 52) |
END; |
e.obj := eCONST; |
e._type := tINTEGER |
|PROG.sysINF: |
IL.AddCmd2(IL.opINF, pos.line, pos.col); |
e.obj := eEXPR; |
e._type := tREAL |
|PROG.sysSIZE: |
PExpression(parser, e); |
PARS.check(e.obj = eTYPE, pos, 68); |
ASSERT(ARITH.setInt(e.value, e._type.size)); |
e.obj := eCONST; |
e._type := tINTEGER |
END |
END; |
(* IF (proc # PROG.sysNOP) & (proc # PROG.sysEINT) & (proc # PROG.sysDINT) THEN *) |
PARS.checklex(parser, SCAN.lxRROUND); |
PARS.Next(parser); |
(* END; *) |
IF e.obj # eCONST THEN |
e.obj := eEXPR |
END |
END stProc; |
PROCEDURE ActualParameters (parser: PARS.PARSER; VAR e: PARS.EXPR); |
VAR |
proc: PROG._TYPE; |
param: LISTS.ITEM; |
e1: PARS.EXPR; |
pos: PARS.POSITION; |
BEGIN |
ASSERT(parser.sym = SCAN.lxLROUND); |
IF (e.obj IN {ePROC, eIMP}) OR isExpr(e) THEN |
proc := e._type; |
PARS.check1(proc.typ = PROG.tPROCEDURE, parser, 86); |
PARS.Next(parser); |
param := proc.params.first; |
WHILE param # NIL DO |
getpos(parser, pos); |
IL.setlast(begcall); |
IF param(PROG.PARAM).vPar THEN |
parser.designator(parser, e1) |
ELSE |
PExpression(parser, e1) |
END; |
paramcomp(parser, pos, e1, param(PROG.PARAM)); |
param := param.next; |
IF param # NIL THEN |
PARS.checklex(parser, SCAN.lxCOMMA); |
PARS.Next(parser) |
END |
END; |
PARS.checklex(parser, SCAN.lxRROUND); |
PARS.Next(parser); |
e.obj := eEXPR; |
e._type := proc.base |
ELSIF e.obj IN {eSTPROC, eSTFUNC, eSYSPROC, eSYSFUNC} THEN |
stProc(parser, e) |
ELSE |
PARS.check1(FALSE, parser, 86) |
END |
END ActualParameters; |
PROCEDURE qualident (parser: PARS.PARSER; VAR e: PARS.EXPR); |
VAR |
ident: PROG.IDENT; |
imp: BOOLEAN; |
pos: PARS.POSITION; |
BEGIN |
PARS.checklex(parser, SCAN.lxIDENT); |
getpos(parser, pos); |
imp := FALSE; |
ident := PROG.getIdent(parser.unit, parser.lex.ident, FALSE); |
PARS.check1(ident # NIL, parser, 48); |
IF ident.typ = PROG.idMODULE THEN |
PARS.ExpectSym(parser, SCAN.lxPOINT); |
PARS.ExpectSym(parser, SCAN.lxIDENT); |
ident := PROG.getIdent(ident.unit, parser.lex.ident, FALSE); |
PARS.check1((ident # NIL) & ident.export, parser, 48); |
imp := TRUE |
END; |
PARS.Next(parser); |
e.readOnly := FALSE; |
e.ident := ident; |
CASE ident.typ OF |
|PROG.idCONST: |
e.obj := eCONST; |
e._type := ident._type; |
e.value := ident.value |
|PROG.idTYPE: |
e.obj := eTYPE; |
e._type := ident._type |
|PROG.idVAR: |
e.obj := eVAR; |
e._type := ident._type; |
e.readOnly := imp |
|PROG.idPROC: |
e.obj := ePROC; |
e._type := ident._type |
|PROG.idIMP: |
e.obj := eIMP; |
e._type := ident._type |
|PROG.idVPAR: |
e._type := ident._type; |
IF e._type.typ = PROG.tRECORD THEN |
e.obj := eVREC |
ELSE |
e.obj := eVPAR |
END |
|PROG.idPARAM: |
e.obj := ePARAM; |
e._type := ident._type; |
e.readOnly := (e._type.typ IN {PROG.tRECORD, PROG.tARRAY}) |
|PROG.idSTPROC: |
e.obj := eSTPROC; |
e._type := ident._type; |
e.stproc := ident.stproc |
|PROG.idSTFUNC: |
e.obj := eSTFUNC; |
e._type := ident._type; |
e.stproc := ident.stproc |
|PROG.idSYSPROC: |
e.obj := eSYSPROC; |
e._type := ident._type; |
e.stproc := ident.stproc |
|PROG.idSYSFUNC: |
PARS.check(~parser.constexp, pos, 109); |
e.obj := eSYSFUNC; |
e._type := ident._type; |
e.stproc := ident.stproc |
|PROG.idNONE: |
PARS.error(pos, 115) |
END; |
IF isVar(e) THEN |
PARS.check(e.ident.global OR (e.ident.scopeLvl = parser.unit.scopeLvl), pos, 105) |
END |
END qualident; |
PROCEDURE deref (pos: PARS.POSITION; e: PARS.EXPR; load: BOOLEAN; error: INTEGER); |
VAR |
label: INTEGER; |
BEGIN |
IF load THEN |
IL.load(e._type.size) |
END; |
IF chkPTR IN Options.checking THEN |
label := IL.NewLabel(); |
IL.Jmp(IL.opJNZ1, label); |
IL.OnError(pos.line, error); |
IL.SetLabel(label) |
END |
END deref; |
PROCEDURE designator (parser: PARS.PARSER; VAR e: PARS.EXPR); |
VAR |
field: PROG.FIELD; |
pos: PARS.POSITION; |
t, idx: PARS.EXPR; |
PROCEDURE LoadAdr (e: PARS.EXPR); |
VAR |
offset: INTEGER; |
PROCEDURE OpenArray (e: PARS.EXPR); |
VAR |
offset, n: INTEGER; |
BEGIN |
offset := e.ident.offset; |
n := PROG.Dim(e._type); |
WHILE n >= 0 DO |
IL.AddCmd(IL.opVADR, offset); |
DEC(offset); |
DEC(n) |
END |
END OpenArray; |
BEGIN |
IF e.obj = eVAR THEN |
offset := PROG.getOffset(e.ident); |
IF e.ident.global THEN |
IL.AddCmd(IL.opGADR, offset) |
ELSE |
IL.AddCmd(IL.opLADR, -offset) |
END |
ELSIF e.obj = ePARAM THEN |
IF (e._type.typ = PROG.tRECORD) OR ((e._type.typ = PROG.tARRAY) & (e._type.length > 0)) THEN |
IL.AddCmd(IL.opVADR, e.ident.offset) |
ELSIF PROG.isOpenArray(e._type) THEN |
OpenArray(e) |
ELSE |
IL.AddCmd(IL.opLADR, e.ident.offset) |
END |
ELSIF e.obj IN {eVPAR, eVREC} THEN |
IF PROG.isOpenArray(e._type) THEN |
OpenArray(e) |
ELSE |
IL.AddCmd(IL.opVADR, e.ident.offset) |
END |
END |
END LoadAdr; |
PROCEDURE OpenIdx (parser: PARS.PARSER; pos: PARS.POSITION; e: PARS.EXPR); |
VAR |
label, offset, n, k: INTEGER; |
_type: PROG._TYPE; |
BEGIN |
IF chkIDX IN Options.checking THEN |
label := IL.NewLabel(); |
IL.AddCmd2(IL.opCHKIDX2, label, 0); |
IL.OnError(pos.line, errIDX); |
IL.SetLabel(label) |
ELSE |
IL.AddCmd(IL.opCHKIDX2, -1) |
END; |
_type := PROG.OpenBase(e._type); |
IF _type.size # 1 THEN |
IL.AddCmd(IL.opMULC, _type.size) |
END; |
n := PROG.Dim(e._type) - 1; |
k := n; |
WHILE n > 0 DO |
IL.AddCmd0(IL.opMUL); |
DEC(n) |
END; |
IL.AddCmd0(IL.opADD); |
offset := e.ident.offset - 1; |
n := k; |
WHILE n > 0 DO |
IL.AddCmd(IL.opVADR, offset); |
DEC(offset); |
DEC(n) |
END |
END OpenIdx; |
BEGIN |
qualident(parser, e); |
IF e.obj IN {ePROC, eIMP} THEN |
PROG.UseProc(parser.unit, e.ident.proc) |
END; |
IF isVar(e) THEN |
LoadAdr(e) |
END; |
WHILE parser.sym = SCAN.lxPOINT DO |
getpos(parser, pos); |
PARS.check1(isExpr(e) & (e._type.typ IN {PROG.tRECORD, PROG.tPOINTER}), parser, 73); |
IF e._type.typ = PROG.tPOINTER THEN |
deref(pos, e, TRUE, errPTR) |
END; |
PARS.ExpectSym(parser, SCAN.lxIDENT); |
IF e._type.typ = PROG.tPOINTER THEN |
e._type := e._type.base; |
e.readOnly := FALSE |
END; |
field := PROG.getField(e._type, parser.lex.ident, parser.unit); |
PARS.check1(field # NIL, parser, 74); |
e._type := field._type; |
IF e.obj = eVREC THEN |
e.obj := eVPAR |
END; |
IF field.offset # 0 THEN |
IL.AddCmd(IL.opADDC, field.offset) |
END; |
PARS.Next(parser); |
e.ident := NIL |
ELSIF parser.sym = SCAN.lxLSQUARE DO |
REPEAT |
PARS.check1(isArr(e), parser, 75); |
NextPos(parser, pos); |
PExpression(parser, idx); |
PARS.check(isInt(idx), pos, 76); |
IF idx.obj = eCONST THEN |
IF e._type.length > 0 THEN |
PARS.check(ARITH.range(idx.value, 0, e._type.length - 1), pos, 83); |
IF ARITH.Int(idx.value) > 0 THEN |
IL.AddCmd(IL.opADDC, ARITH.Int(idx.value) * e._type.base.size) |
END |
ELSE |
PARS.check(ARITH.range(idx.value, 0, UTILS.target.maxInt), pos, 83); |
LoadConst(idx); |
OpenIdx(parser, pos, e) |
END |
ELSE |
IF e._type.length > 0 THEN |
IF chkIDX IN Options.checking THEN |
CheckRange(e._type.length, pos.line, errIDX) |
END; |
IF e._type.base.size # 1 THEN |
IL.AddCmd(IL.opMULC, e._type.base.size) |
END; |
IL.AddCmd0(IL.opADD) |
ELSE |
OpenIdx(parser, pos, e) |
END |
END; |
e._type := e._type.base |
UNTIL parser.sym # SCAN.lxCOMMA; |
PARS.checklex(parser, SCAN.lxRSQUARE); |
PARS.Next(parser); |
IF ~(isArr(e) & (e._type.length = 0) & (parser.sym = SCAN.lxLSQUARE)) THEN |
e.ident := NIL |
END |
ELSIF parser.sym = SCAN.lxCARET DO |
getpos(parser, pos); |
PARS.check1(isPtr(e), parser, 77); |
deref(pos, e, TRUE, errPTR); |
e._type := e._type.base; |
e.readOnly := FALSE; |
PARS.Next(parser); |
e.ident := NIL; |
e.obj := eVREC |
ELSIF (parser.sym = SCAN.lxLROUND) & isExpr(e) & (e._type.typ IN {PROG.tRECORD, PROG.tPOINTER}) DO |
IF e._type.typ = PROG.tRECORD THEN |
PARS.check1(e.obj = eVREC, parser, 78) |
END; |
NextPos(parser, pos); |
qualident(parser, t); |
PARS.check(t.obj = eTYPE, pos, 79); |
IF e._type.typ = PROG.tRECORD THEN |
PARS.check(t._type.typ = PROG.tRECORD, pos, 80); |
IF chkGUARD IN Options.checking THEN |
IF e.ident = NIL THEN |
IL.TypeGuard(IL.opTYPEGD, t._type.num, pos.line, errGUARD) |
ELSE |
IL.AddCmd(IL.opVADR, e.ident.offset - 1); |
IL.TypeGuard(IL.opTYPEGR, t._type.num, pos.line, errGUARD) |
END |
END; |
ELSE |
PARS.check(t._type.typ = PROG.tPOINTER, pos, 81); |
IF chkGUARD IN Options.checking THEN |
IL.TypeGuard(IL.opTYPEGP, t._type.base.num, pos.line, errGUARD) |
END |
END; |
PARS.check(PROG.isBaseOf(e._type, t._type), pos, 82); |
e._type := t._type; |
PARS.checklex(parser, SCAN.lxRROUND); |
PARS.Next(parser) |
END |
END designator; |
PROCEDURE ProcCall (e: PARS.EXPR; procType: PROG._TYPE; isfloat: BOOLEAN; parser: PARS.PARSER; pos: PARS.POSITION; CallStat: BOOLEAN); |
VAR |
cconv, |
parSize, |
callconv, |
fparSize, |
int, flt, |
stk_par: INTEGER; |
BEGIN |
cconv := procType.call; |
parSize := procType.parSize; |
IF cconv IN {PROG._win64, PROG.win64} THEN |
callconv := IL.call_win64; |
fparSize := LSL(ORD(PROG.getFloatParamsPos(procType, 3, int, flt)), 5) + MIN(parSize, 4) |
ELSIF cconv IN {PROG._systemv, PROG.systemv} THEN |
callconv := IL.call_sysv; |
fparSize := LSL(ORD(PROG.getFloatParamsPos(procType, PROG.MAXSYSVPARAM - 1, int, flt)), 5) + parSize; |
stk_par := MAX(0, int - 6) + MAX(0, flt - 8) |
ELSE |
callconv := IL.call_stack; |
fparSize := 0 |
END; |
IL.setlast(begcall); |
IL.AddCmd(IL.opPRECALL, ORD(isfloat)); |
IF cconv IN {PROG._ccall, PROG.ccall} THEN |
IL.AddCmd(IL.opALIGN16, parSize) |
ELSIF cconv IN {PROG._win64, PROG.win64} THEN |
IL.AddCmd(IL.opWIN64ALIGN16, parSize) |
ELSIF cconv IN {PROG._systemv, PROG.systemv} THEN |
IL.AddCmd(IL.opSYSVALIGN16, parSize + stk_par) |
END; |
IL.setlast(endcall.prev(IL.COMMAND)); |
IF e.obj = eIMP THEN |
IL.CallImp(e.ident._import, callconv, fparSize) |
ELSIF e.obj = ePROC THEN |
IL.Call(e.ident.proc.label, callconv, fparSize) |
ELSIF isExpr(e) THEN |
deref(pos, e, CallStat, errPROC); |
IL.CallP(callconv, fparSize) |
END; |
IF cconv IN {PROG._ccall, PROG.ccall} THEN |
IL.AddCmd(IL.opCLEANUP, parSize); |
IL.AddCmd0(IL.opPOPSP) |
ELSIF cconv IN {PROG._win64, PROG.win64} THEN |
IL.AddCmd(IL.opCLEANUP, MAX(parSize + parSize MOD 2, 4) + 1); |
IL.AddCmd0(IL.opPOPSP) |
ELSIF cconv IN {PROG._systemv, PROG.systemv} THEN |
IL.AddCmd(IL.opCLEANUP, parSize + stk_par); |
IL.AddCmd0(IL.opPOPSP) |
ELSIF cconv IN {PROG._cdecl, PROG.cdecl, PROG.default16, PROG.code, PROG._code} THEN |
IL.AddCmd(IL.opCLEANUP, parSize) |
END; |
IF CallStat THEN |
IL.AddCmd0(IL.opRES); |
IL.drop |
ELSE |
IF isfloat THEN |
IL.AddCmd2(IL.opRESF, pos.line, pos.col) |
ELSE |
IL.AddCmd0(IL.opRES) |
END |
END |
END ProcCall; |
PROCEDURE expression (parser: PARS.PARSER; VAR e: PARS.EXPR); |
VAR |
pos, pos0, pos1: PARS.POSITION; |
e1: PARS.EXPR; |
op, cmp, error: INTEGER; |
constant, eq: BOOLEAN; |
PROCEDURE relation (sym: INTEGER): BOOLEAN; |
RETURN (sym = SCAN.lxEQ) OR (sym = SCAN.lxNE) OR |
(sym = SCAN.lxLT) OR (sym = SCAN.lxLE) OR |
(sym = SCAN.lxGT) OR (sym = SCAN.lxGE) OR |
(sym = SCAN.lxIN) OR (sym = SCAN.lxIS) |
END relation; |
PROCEDURE AddOperator (sym: INTEGER): BOOLEAN; |
RETURN (sym = SCAN.lxPLUS) OR (sym = SCAN.lxMINUS) OR |
(sym = SCAN.lxOR) |
END AddOperator; |
PROCEDURE MulOperator (sym: INTEGER): BOOLEAN; |
RETURN (sym = SCAN.lxMUL) OR (sym = SCAN.lxSLASH) OR |
(sym = SCAN.lxDIV) OR (sym = SCAN.lxMOD) OR |
(sym = SCAN.lxAND) |
END MulOperator; |
PROCEDURE element (parser: PARS.PARSER; VAR e: PARS.EXPR); |
VAR |
e1, e2: PARS.EXPR; |
pos: PARS.POSITION; |
range: BOOLEAN; |
BEGIN |
range := FALSE; |
getpos(parser, pos); |
expression(parser, e1); |
PARS.check(isInt(e1), pos, 76); |
IF e1.obj = eCONST THEN |
PARS.check(ARITH.range(e1.value, 0, UTILS.target.maxSet), pos, 44) |
END; |
range := parser.sym = SCAN.lxRANGE; |
IF range THEN |
NextPos(parser, pos); |
expression(parser, e2); |
PARS.check(isInt(e2), pos, 76); |
IF e2.obj = eCONST THEN |
PARS.check(ARITH.range(e2.value, 0, UTILS.target.maxSet), pos, 44) |
END |
ELSE |
IF e1.obj = eCONST THEN |
e2 := e1 |
END |
END; |
e._type := tSET; |
IF (e1.obj = eCONST) & (e2.obj = eCONST) THEN |
ARITH.constrSet(e.value, e1.value, e2.value); |
e.obj := eCONST |
ELSE |
IF range THEN |
IF e1.obj = eCONST THEN |
IL.AddCmd(IL.opRSETL, ARITH.Int(e1.value)) |
ELSIF e2.obj = eCONST THEN |
IL.AddCmd(IL.opRSETR, ARITH.Int(e2.value)) |
ELSE |
IL.AddCmd0(IL.opRSET) |
END |
ELSE |
IL.AddCmd0(IL.opRSET1) |
END; |
e.obj := eEXPR |
END |
END element; |
PROCEDURE set (parser: PARS.PARSER; VAR e: PARS.EXPR); |
VAR |
e1: PARS.EXPR; |
BEGIN |
ASSERT(parser.sym = SCAN.lxLCURLY); |
e.obj := eCONST; |
e._type := tSET; |
ARITH.emptySet(e.value); |
PARS.Next(parser); |
IF parser.sym # SCAN.lxRCURLY THEN |
element(parser, e1); |
IF e1.obj = eCONST THEN |
ARITH.opSet(e.value, e1.value, "+") |
ELSE |
e.obj := eEXPR |
END; |
WHILE parser.sym = SCAN.lxCOMMA DO |
PARS.Next(parser); |
element(parser, e1); |
IF (e.obj = eCONST) & (e1.obj = eCONST) THEN |
ARITH.opSet(e.value, e1.value, "+") |
ELSE |
IF e.obj = eCONST THEN |
IL.AddCmd(IL.opADDSC, ARITH.Int(e.value)) |
ELSIF e1.obj = eCONST THEN |
IL.AddCmd(IL.opADDSC, ARITH.Int(e1.value)) |
ELSE |
IL.AddCmd0(IL.opADDS) |
END; |
e.obj := eEXPR |
END |
END; |
PARS.checklex(parser, SCAN.lxRCURLY) |
END; |
PARS.Next(parser); |
END set; |
PROCEDURE factor (parser: PARS.PARSER; VAR e: PARS.EXPR); |
VAR |
sym: INTEGER; |
pos: PARS.POSITION; |
e1: PARS.EXPR; |
isfloat: BOOLEAN; |
PROCEDURE LoadVar (e: PARS.EXPR; parser: PARS.PARSER; pos: PARS.POSITION); |
BEGIN |
IF ~(e._type.typ IN {PROG.tRECORD, PROG.tARRAY}) THEN |
IF e._type = tREAL THEN |
IL.AddCmd2(IL.opLOADF, pos.line, pos.col) |
ELSE |
IL.load(e._type.size) |
END |
END |
END LoadVar; |
BEGIN |
sym := parser.sym; |
IF (sym = SCAN.lxINTEGER) OR (sym = SCAN.lxHEX) OR (sym = SCAN.lxFLOAT) OR (sym = SCAN.lxCHAR) OR (sym = SCAN.lxSTRING) THEN |
e.obj := eCONST; |
e.value := parser.lex.value; |
e._type := PROG.getType(e.value.typ); |
PARS.Next(parser) |
ELSIF sym = SCAN.lxNIL THEN |
e.obj := eCONST; |
e._type := PROG.program.stTypes.tNIL; |
PARS.Next(parser) |
ELSIF (sym = SCAN.lxTRUE) OR (sym = SCAN.lxFALSE) THEN |
e.obj := eCONST; |
ARITH.setbool(e.value, sym = SCAN.lxTRUE); |
e._type := tBOOLEAN; |
PARS.Next(parser) |
ELSIF sym = SCAN.lxLCURLY THEN |
set(parser, e) |
ELSIF sym = SCAN.lxIDENT THEN |
getpos(parser, pos); |
IL.pushBegEnd(begcall, endcall); |
designator(parser, e); |
IF isVar(e) THEN |
LoadVar(e, parser, pos) |
END; |
IF parser.sym = SCAN.lxLROUND THEN |
e1 := e; |
ActualParameters(parser, e); |
PARS.check(e._type # NIL, pos, 59); |
isfloat := e._type = tREAL; |
IF e1.obj IN {ePROC, eIMP} THEN |
ProcCall(e1, e1.ident._type, isfloat, parser, pos, FALSE) |
ELSIF isExpr(e1) THEN |
ProcCall(e1, e1._type, isfloat, parser, pos, FALSE) |
END |
END; |
IL.popBegEnd(begcall, endcall) |
ELSIF sym = SCAN.lxLROUND THEN |
PARS.Next(parser); |
expression(parser, e); |
PARS.checklex(parser, SCAN.lxRROUND); |
PARS.Next(parser); |
IF isExpr(e) & (e.obj # eCONST) THEN |
e.obj := eEXPR |
END |
ELSIF sym = SCAN.lxNOT THEN |
NextPos(parser, pos); |
factor(parser, e); |
PARS.check(isBoolean(e), pos, 72); |
IF e.obj # eCONST THEN |
IL.not; |
e.obj := eEXPR |
ELSE |
ASSERT(ARITH.neg(e.value)) |
END |
ELSE |
PARS.check1(FALSE, parser, 34) |
END |
END factor; |
PROCEDURE term (parser: PARS.PARSER; VAR e: PARS.EXPR); |
VAR |
pos: PARS.POSITION; |
e1: PARS.EXPR; |
op, label, label1: INTEGER; |
BEGIN |
factor(parser, e); |
label := -1; |
WHILE MulOperator(parser.sym) DO |
op := parser.sym; |
getpos(parser, pos); |
PARS.Next(parser); |
IF op = SCAN.lxAND THEN |
IF ~parser.constexp THEN |
IF label = -1 THEN |
label := IL.NewLabel() |
END; |
IF (e.obj = eCONST) & isBoolean(e) THEN |
IL.Const(ORD(ARITH.getBool(e.value))) |
END; |
IL.Jmp(IL.opJZ, label) |
END |
END; |
factor(parser, e1); |
CASE op OF |
|SCAN.lxMUL: |
PARS.check(isInt(e) & isInt(e1) OR isReal(e) & isReal(e1) OR isSet(e) & isSet(e1), pos, 37); |
IF (e.obj = eCONST) & (e1.obj = eCONST) THEN |
CASE e.value.typ OF |
|ARITH.tINTEGER: PARS.check(ARITH.opInt(e.value, e1.value, "*"), pos, 39) |
|ARITH.tREAL: PARS.check(ARITH.opFloat(e.value, e1.value, "*"), pos, 40) |
|ARITH.tSET: ARITH.opSet(e.value, e1.value, "*") |
END |
ELSE |
IF isInt(e) THEN |
IF e.obj = eCONST THEN |
IL.AddCmd(IL.opMULC, ARITH.Int(e.value)) |
ELSIF e1.obj = eCONST THEN |
IL.AddCmd(IL.opMULC, ARITH.Int(e1.value)) |
ELSE |
IL.AddCmd0(IL.opMUL) |
END |
ELSIF isReal(e) THEN |
IF e.obj = eCONST THEN |
Float(parser, e) |
ELSIF e1.obj = eCONST THEN |
Float(parser, e1) |
END; |
IL.AddCmd0(IL.opMULF) |
ELSIF isSet(e) THEN |
IF e.obj = eCONST THEN |
IL.AddCmd(IL.opMULSC, ARITH.Int(e.value)) |
ELSIF e1.obj = eCONST THEN |
IL.AddCmd(IL.opMULSC, ARITH.Int(e1.value)) |
ELSE |
IL.AddCmd0(IL.opMULS) |
END |
END; |
e.obj := eEXPR |
END |
|SCAN.lxSLASH: |
PARS.check(isReal(e) & isReal(e1) OR isSet(e) & isSet(e1), pos, 37); |
IF (e1.obj = eCONST) & isReal(e1) THEN |
PARS.check(~ARITH.isZero(e1.value), pos, 45) |
END; |
IF (e.obj = eCONST) & (e1.obj = eCONST) THEN |
CASE e.value.typ OF |
|ARITH.tREAL: PARS.check(ARITH.opFloat(e.value, e1.value, "/"), pos, 40) |
|ARITH.tSET: ARITH.opSet(e.value, e1.value, "/") |
END |
ELSE |
IF isReal(e) THEN |
IF e.obj = eCONST THEN |
Float(parser, e); |
IL.AddCmd0(IL.opDIVFI) |
ELSIF e1.obj = eCONST THEN |
Float(parser, e1); |
IL.AddCmd0(IL.opDIVF) |
ELSE |
IL.AddCmd0(IL.opDIVF) |
END |
ELSIF isSet(e) THEN |
IF e.obj = eCONST THEN |
IL.AddCmd(IL.opDIVSC, ARITH.Int(e.value)) |
ELSIF e1.obj = eCONST THEN |
IL.AddCmd(IL.opDIVSC, ARITH.Int(e1.value)) |
ELSE |
IL.AddCmd0(IL.opDIVS) |
END |
END; |
e.obj := eEXPR |
END |
|SCAN.lxDIV, SCAN.lxMOD: |
PARS.check(isInt(e) & isInt(e1), pos, 37); |
IF e1.obj = eCONST THEN |
PARS.check(ARITH.Int(e1.value) > 0, pos, 122) |
END; |
IF (e.obj = eCONST) & (e1.obj = eCONST) THEN |
IF op = SCAN.lxDIV THEN |
PARS.check(ARITH.opInt(e.value, e1.value, "D"), pos, 39) |
ELSE |
ASSERT(ARITH.opInt(e.value, e1.value, "M")) |
END |
ELSE |
IF e1.obj # eCONST THEN |
label1 := IL.NewLabel(); |
IL.Jmp(IL.opJG, label1) |
END; |
IF e.obj = eCONST THEN |
IL.OnError(pos.line, errDIV); |
IL.SetLabel(label1); |
IL.AddCmd(IL.opDIVL + ORD(op = SCAN.lxMOD), ARITH.Int(e.value)) |
ELSIF e1.obj = eCONST THEN |
IL.AddCmd(IL.opDIVR + ORD(op = SCAN.lxMOD), ARITH.Int(e1.value)) |
ELSE |
IL.OnError(pos.line, errDIV); |
IL.SetLabel(label1); |
IL.AddCmd0(IL.opDIV + ORD(op = SCAN.lxMOD)) |
END; |
e.obj := eEXPR |
END |
|SCAN.lxAND: |
PARS.check(isBoolean(e) & isBoolean(e1), pos, 37); |
IF (e.obj = eCONST) & (e1.obj = eCONST) & parser.constexp THEN |
ARITH.opBoolean(e.value, e1.value, "&") |
ELSE |
e.obj := eEXPR; |
IF e1.obj = eCONST THEN |
IL.Const(ORD(ARITH.getBool(e1.value))) |
END |
END |
END |
END; |
IF label # -1 THEN |
label1 := IL.NewLabel(); |
IL.Jmp(IL.opJNZ, label1); |
IL.SetLabel(label); |
IL.Const(0); |
IL.drop; |
label := IL.NewLabel(); |
IL.Jmp(IL.opJMP, label); |
IL.SetLabel(label1); |
IL.Const(1); |
IL.SetLabel(label); |
IL.AddCmd0(IL.opAND) |
END |
END term; |
PROCEDURE SimpleExpression (parser: PARS.PARSER; VAR e: PARS.EXPR); |
VAR |
pos: PARS.POSITION; |
op: INTEGER; |
e1: PARS.EXPR; |
s, s1: SCAN.TEXTSTR; |
plus, minus: BOOLEAN; |
label, label1: INTEGER; |
BEGIN |
plus := parser.sym = SCAN.lxPLUS; |
minus := parser.sym = SCAN.lxMINUS; |
IF plus OR minus THEN |
getpos(parser, pos); |
PARS.Next(parser) |
END; |
term(parser, e); |
IF plus OR minus THEN |
PARS.check(isInt(e) OR isReal(e) OR isSet(e), pos, 36); |
IF minus & (e.obj = eCONST) THEN |
PARS.check(ARITH.neg(e.value), pos, 39) |
END; |
IF e.obj # eCONST THEN |
IF minus THEN |
IF isInt(e) THEN |
IL.AddCmd0(IL.opUMINUS) |
ELSIF isReal(e) THEN |
IL.AddCmd0(IL.opUMINF) |
ELSIF isSet(e) THEN |
IL.AddCmd0(IL.opUMINS) |
END |
END; |
e.obj := eEXPR |
END |
END; |
label := -1; |
WHILE AddOperator(parser.sym) DO |
op := parser.sym; |
getpos(parser, pos); |
PARS.Next(parser); |
IF op = SCAN.lxOR THEN |
IF ~parser.constexp THEN |
IF label = -1 THEN |
label := IL.NewLabel() |
END; |
IF (e.obj = eCONST) & isBoolean(e) THEN |
IL.Const(ORD(ARITH.getBool(e.value))) |
END; |
IL.Jmp(IL.opJNZ, label) |
END |
END; |
term(parser, e1); |
CASE op OF |
|SCAN.lxPLUS, SCAN.lxMINUS: |
minus := op = SCAN.lxMINUS; |
IF minus THEN |
op := ORD("-") |
ELSE |
op := ORD("+") |
END; |
PARS.check(isInt(e) & isInt(e1) OR isReal(e) & isReal(e1) OR isSet(e) & isSet(e1) OR isString(e) & isString(e1) & ~minus, pos, 37); |
IF (e.obj = eCONST) & (e1.obj = eCONST) THEN |
CASE e.value.typ OF |
|ARITH.tINTEGER: |
PARS.check(ARITH.opInt(e.value, e1.value, CHR(op)), pos, 39) |
|ARITH.tREAL: |
PARS.check(ARITH.opFloat(e.value, e1.value, CHR(op)), pos, 40) |
|ARITH.tSET: |
ARITH.opSet(e.value, e1.value, CHR(op)) |
|ARITH.tCHAR, ARITH.tSTRING: |
IF e.value.typ = ARITH.tCHAR THEN |
ARITH.charToStr(e.value, s) |
ELSE |
s := e.value.string(SCAN.STRING).s |
END; |
IF e1.value.typ = ARITH.tCHAR THEN |
ARITH.charToStr(e1.value, s1) |
ELSE |
s1 := e1.value.string(SCAN.STRING).s |
END; |
PARS.check(ARITH.concat(s, s1), pos, 5); |
e.value.string := SCAN.enterStr(s); |
e.value.typ := ARITH.tSTRING; |
e._type := PROG.program.stTypes.tSTRING |
END |
ELSE |
IF isInt(e) THEN |
IF e.obj = eCONST THEN |
IL.AddCmd(IL.opADDC - ORD(minus), ARITH.Int(e.value)) |
ELSIF e1.obj = eCONST THEN |
IL.AddCmd(IL.opADDC + ORD(minus), ARITH.Int(e1.value)) |
ELSE |
IL.AddCmd0(IL.opADD + ORD(minus)) |
END |
ELSIF isReal(e) THEN |
IF e.obj = eCONST THEN |
Float(parser, e); |
IL.AddCmd0(IL.opADDF - ORD(minus)) |
ELSIF e1.obj = eCONST THEN |
Float(parser, e1); |
IL.AddCmd0(IL.opADDF + ORD(minus)) |
ELSE |
IL.AddCmd0(IL.opADDF + ORD(minus)) |
END |
ELSIF isSet(e) THEN |
IF e.obj = eCONST THEN |
IL.AddCmd(IL.opADDSC - ORD(minus), ARITH.Int(e.value)) |
ELSIF e1.obj = eCONST THEN |
IL.AddCmd(IL.opADDSC + ORD(minus), ARITH.Int(e1.value)) |
ELSE |
IL.AddCmd0(IL.opADDS + ORD(minus)) |
END |
END; |
e.obj := eEXPR |
END |
|SCAN.lxOR: |
PARS.check(isBoolean(e) & isBoolean(e1), pos, 37); |
IF (e.obj = eCONST) & (e1.obj = eCONST) & parser.constexp THEN |
ARITH.opBoolean(e.value, e1.value, "|") |
ELSE |
e.obj := eEXPR; |
IF e1.obj = eCONST THEN |
IL.Const(ORD(ARITH.getBool(e1.value))) |
END |
END |
END |
END; |
IF label # -1 THEN |
label1 := IL.NewLabel(); |
IL.Jmp(IL.opJZ, label1); |
IL.SetLabel(label); |
IL.Const(1); |
IL.drop; |
label := IL.NewLabel(); |
IL.Jmp(IL.opJMP, label); |
IL.SetLabel(label1); |
IL.Const(0); |
IL.SetLabel(label); |
IL.AddCmd0(IL.opOR) |
END |
END SimpleExpression; |
PROCEDURE cmpcode (op: INTEGER): INTEGER; |
VAR |
res: INTEGER; |
BEGIN |
CASE op OF |
|SCAN.lxEQ: res := ARITH.opEQ |
|SCAN.lxNE: res := ARITH.opNE |
|SCAN.lxLT: res := ARITH.opLT |
|SCAN.lxLE: res := ARITH.opLE |
|SCAN.lxGT: res := ARITH.opGT |
|SCAN.lxGE: res := ARITH.opGE |
|SCAN.lxIN: res := ARITH.opIN |
|SCAN.lxIS: res := ARITH.opIS |
END |
RETURN res |
END cmpcode; |
PROCEDURE invcmpcode (op: INTEGER): INTEGER; |
VAR |
res: INTEGER; |
BEGIN |
CASE op OF |
|SCAN.lxEQ: res := ARITH.opEQ |
|SCAN.lxNE: res := ARITH.opNE |
|SCAN.lxLT: res := ARITH.opGT |
|SCAN.lxLE: res := ARITH.opGE |
|SCAN.lxGT: res := ARITH.opLT |
|SCAN.lxGE: res := ARITH.opLE |
|SCAN.lxIN: res := ARITH.opIN |
|SCAN.lxIS: res := ARITH.opIS |
END |
RETURN res |
END invcmpcode; |
PROCEDURE BoolCmp (eq, val: BOOLEAN); |
BEGIN |
IF eq = val THEN |
IL.AddCmd0(IL.opNEC) |
ELSE |
IL.AddCmd0(IL.opEQC) |
END |
END BoolCmp; |
PROCEDURE strcmp (VAR e, e1: PARS.EXPR; op: INTEGER): BOOLEAN; |
VAR |
res: BOOLEAN; |
cmp: INTEGER; |
BEGIN |
res := TRUE; |
cmp := cmpcode(op); |
IF isString(e) & isCharArray(e1) THEN |
IL.StrAdr(String(e)); |
IL.Const(strlen(e) + 1); |
IL.AddCmd0(IL.opEQS + invcmpcode(op)) |
ELSIF (isString(e) OR isStringW(e)) & isCharArrayW(e1) THEN |
IL.StrAdr(StringW(e)); |
IL.Const(utf8strlen(e) + 1); |
IL.AddCmd0(IL.opEQSW + invcmpcode(op)) |
ELSIF isCharArray(e) & isString(e1) THEN |
IL.StrAdr(String(e1)); |
IL.Const(strlen(e1) + 1); |
IL.AddCmd0(IL.opEQS + cmp) |
ELSIF isCharArrayW(e) & (isString(e1) OR isStringW(e1)) THEN |
IL.StrAdr(StringW(e1)); |
IL.Const(utf8strlen(e1) + 1); |
IL.AddCmd0(IL.opEQSW + cmp) |
ELSIF isCharArrayW(e) & isCharArrayW(e1) THEN |
IL.AddCmd0(IL.opEQSW + cmp) |
ELSIF isCharArray(e) & isCharArray(e1) THEN |
IL.AddCmd0(IL.opEQS + cmp) |
ELSIF isString(e) & isString(e1) THEN |
PARS.strcmp(e.value, e1.value, op) |
ELSE |
res := FALSE |
END |
RETURN res |
END strcmp; |
BEGIN |
getpos(parser, pos0); |
SimpleExpression(parser, e); |
IF relation(parser.sym) THEN |
IF (isCharArray(e) OR isCharArrayW(e)) & (e._type.length # 0) THEN |
IL.Const(e._type.length) |
END; |
op := parser.sym; |
getpos(parser, pos); |
PARS.Next(parser); |
getpos(parser, pos1); |
SimpleExpression(parser, e1); |
IF (isCharArray(e1) OR isCharArrayW(e1)) & (e1._type.length # 0) THEN |
IL.Const(e1._type.length) |
END; |
constant := (e.obj = eCONST) & (e1.obj = eCONST); |
error := 0; |
cmp := cmpcode(op); |
CASE op OF |
|SCAN.lxEQ, SCAN.lxNE: |
eq := op = SCAN.lxEQ; |
IF isInt(e) & isInt(e1) OR isSet(e) & isSet(e1) OR isChar(e) & isChar(e1) OR isCharW(e) & isCharW(e1) OR |
isCharW(e) & isChar(e1) & (e1.obj = eCONST) OR isCharW(e1) & isChar(e) & (e.obj = eCONST) OR |
isCharW(e1) & (e1.obj = eCONST) & isChar(e) & (e.obj = eCONST) OR |
isCharW(e) & (e.obj = eCONST) & isChar(e1) & (e1.obj = eCONST) OR |
isPtr(e) & isPtr(e1) & (PROG.isBaseOf(e._type, e1._type) OR PROG.isBaseOf(e1._type, e._type)) THEN |
IF constant THEN |
ARITH.relation(e.value, e1.value, cmp, error) |
ELSE |
IF e.obj = eCONST THEN |
IL.AddCmd(IL.opEQC + cmp, ARITH.Int(e.value)) |
ELSIF e1.obj = eCONST THEN |
IL.AddCmd(IL.opEQC + cmp, ARITH.Int(e1.value)) |
ELSE |
IL.AddCmd0(IL.opEQ + cmp) |
END |
END |
ELSIF isStringW1(e) & isCharW(e1) THEN |
IL.AddCmd(IL.opEQC + cmp, StrToWChar(e.value.string(SCAN.STRING).s)) |
ELSIF isStringW1(e1) & isCharW(e) THEN |
IL.AddCmd(IL.opEQC + cmp, StrToWChar(e1.value.string(SCAN.STRING).s)) |
ELSIF isBoolean(e) & isBoolean(e1) THEN |
IF constant THEN |
ARITH.relation(e.value, e1.value, cmp, error) |
ELSE |
IF e.obj = eCONST THEN |
BoolCmp(eq, ARITH.Int(e.value) # 0) |
ELSIF e1.obj = eCONST THEN |
BoolCmp(eq, ARITH.Int(e1.value) # 0) |
ELSE |
IF eq THEN |
IL.AddCmd0(IL.opEQB) |
ELSE |
IL.AddCmd0(IL.opNEB) |
END |
END |
END |
ELSIF isReal(e) & isReal(e1) THEN |
IF constant THEN |
ARITH.relation(e.value, e1.value, cmp, error) |
ELSE |
IF e.obj = eCONST THEN |
Float(parser, e) |
ELSIF e1.obj = eCONST THEN |
Float(parser, e1) |
END; |
IL.AddCmd0(IL.opEQF + cmp) |
END |
ELSIF (isStringW(e) OR isCharArrayX(e)) & (isStringW(e1) OR isCharArrayX(e1)) THEN |
IF ~strcmp(e, e1, op) THEN |
PARS.error(pos, 37) |
END |
ELSIF isPtr(e) & isNil(e1) OR isNil(e) & isPtr(e1) THEN |
IL.AddCmd0(IL.opEQC + cmp) |
ELSIF isProc(e) & isNil(e1) THEN |
IF e.obj IN {ePROC, eIMP} THEN |
PARS.check(e.ident.global, pos0, 85); |
constant := TRUE; |
e.obj := eCONST; |
ARITH.setbool(e.value, ~eq) |
ELSE |
IL.AddCmd0(IL.opEQC + cmp) |
END |
ELSIF isNil(e) & isProc(e1) THEN |
IF e1.obj IN {ePROC, eIMP} THEN |
PARS.check(e1.ident.global, pos1, 85); |
constant := TRUE; |
e.obj := eCONST; |
ARITH.setbool(e.value, ~eq) |
ELSE |
IL.AddCmd0(IL.opEQC + cmp) |
END |
ELSIF isProc(e) & isProc(e1) & PROG.isTypeEq(e._type, e1._type) THEN |
IF e.obj = ePROC THEN |
PARS.check(e.ident.global, pos0, 85) |
END; |
IF e1.obj = ePROC THEN |
PARS.check(e1.ident.global, pos1, 85) |
END; |
IF (e.obj IN {ePROC, eIMP}) & (e1.obj IN {ePROC, eIMP}) THEN |
constant := TRUE; |
e.obj := eCONST; |
IF eq THEN |
ARITH.setbool(e.value, e.ident = e1.ident) |
ELSE |
ARITH.setbool(e.value, e.ident # e1.ident) |
END |
ELSIF e.obj = ePROC THEN |
IL.ProcCmp(e.ident.proc.label, eq) |
ELSIF e1.obj = ePROC THEN |
IL.ProcCmp(e1.ident.proc.label, eq) |
ELSIF e.obj = eIMP THEN |
IL.ProcImpCmp(e.ident._import, eq) |
ELSIF e1.obj = eIMP THEN |
IL.ProcImpCmp(e1.ident._import, eq) |
ELSE |
IL.AddCmd0(IL.opEQ + cmp) |
END |
ELSIF isNil(e) & isNil(e1) THEN |
constant := TRUE; |
e.obj := eCONST; |
ARITH.setbool(e.value, eq) |
ELSE |
PARS.error(pos, 37) |
END |
|SCAN.lxLT, SCAN.lxLE, SCAN.lxGT, SCAN.lxGE: |
IF isInt(e) & isInt(e1) OR isChar(e) & isChar(e1) OR isCharW(e) & isCharW(e1) OR |
isCharW(e) & isChar(e1) & (e1.obj = eCONST) OR isCharW(e1) & isChar(e) & (e.obj = eCONST) OR |
isCharW(e1) & (e1.obj = eCONST) & isChar(e) & (e.obj = eCONST) OR |
isCharW(e) & (e.obj = eCONST) & isChar(e1) & (e1.obj = eCONST) THEN |
IF constant THEN |
ARITH.relation(e.value, e1.value, cmp, error) |
ELSE |
IF e.obj = eCONST THEN |
IL.AddCmd(IL.opEQC + invcmpcode(op), ARITH.Int(e.value)) |
ELSIF e1.obj = eCONST THEN |
IL.AddCmd(IL.opEQC + cmp, ARITH.Int(e1.value)) |
ELSE |
IL.AddCmd0(IL.opEQ + cmp) |
END |
END |
ELSIF isStringW1(e) & isCharW(e1) THEN |
IL.AddCmd(IL.opEQC + invcmpcode(op), StrToWChar(e.value.string(SCAN.STRING).s)) |
ELSIF isStringW1(e1) & isCharW(e) THEN |
IL.AddCmd(IL.opEQC + cmp, StrToWChar(e1.value.string(SCAN.STRING).s)) |
ELSIF isReal(e) & isReal(e1) THEN |
IF constant THEN |
ARITH.relation(e.value, e1.value, cmp, error) |
ELSE |
IF e.obj = eCONST THEN |
Float(parser, e); |
IL.AddCmd0(IL.opEQF + invcmpcode(op)) |
ELSIF e1.obj = eCONST THEN |
Float(parser, e1); |
IL.AddCmd0(IL.opEQF + cmp) |
ELSE |
IL.AddCmd0(IL.opEQF + cmp) |
END |
END |
ELSIF (isStringW(e) OR isCharArrayX(e)) & (isStringW(e1) OR isCharArrayX(e1)) THEN |
IF ~strcmp(e, e1, op) THEN |
PARS.error(pos, 37) |
END |
ELSE |
PARS.error(pos, 37) |
END |
|SCAN.lxIN: |
PARS.check(isInt(e) & isSet(e1), pos, 37); |
IF e.obj = eCONST THEN |
PARS.check(ARITH.range(e.value, 0, UTILS.target.maxSet), pos0, 56) |
END; |
IF constant THEN |
ARITH.relation(e.value, e1.value, ARITH.opIN, error) |
ELSE |
IF e.obj = eCONST THEN |
IL.AddCmd(IL.opINL, ARITH.Int(e.value)) |
ELSIF e1.obj = eCONST THEN |
IL.AddCmd(IL.opINR, ARITH.Int(e1.value)) |
ELSE |
IL.AddCmd0(IL.opIN) |
END |
END |
|SCAN.lxIS: |
PARS.check(isRecPtr(e), pos, 73); |
PARS.check(e1.obj = eTYPE, pos1, 79); |
IF isRec(e) THEN |
PARS.check(e.obj = eVREC, pos0, 78); |
PARS.check(e1._type.typ = PROG.tRECORD, pos1, 80); |
IF e.ident = NIL THEN |
IL.TypeCheck(e1._type.num) |
ELSE |
IL.AddCmd(IL.opVADR, e.ident.offset - 1); |
IL.TypeCheckRec(e1._type.num) |
END |
ELSE |
PARS.check(e1._type.typ = PROG.tPOINTER, pos1, 81); |
IL.TypeCheck(e1._type.base.num) |
END; |
PARS.check(PROG.isBaseOf(e._type, e1._type), pos1, 82) |
END; |
ASSERT(error = 0); |
e._type := tBOOLEAN; |
IF ~constant THEN |
e.obj := eEXPR |
END |
END |
END expression; |
PROCEDURE ElementaryStatement (parser: PARS.PARSER); |
VAR |
e, e1: PARS.EXPR; |
pos: PARS.POSITION; |
line: INTEGER; |
call: BOOLEAN; |
BEGIN |
getpos(parser, pos); |
IL.pushBegEnd(begcall, endcall); |
designator(parser, e); |
IF parser.sym = SCAN.lxASSIGN THEN |
line := parser.lex.pos.line; |
PARS.check(isVar(e), pos, 93); |
PARS.check(~e.readOnly, pos, 94); |
IL.setlast(begcall); |
NextPos(parser, pos); |
expression(parser, e1); |
IL.setlast(endcall.prev(IL.COMMAND)); |
PARS.check(assign(parser, e1, e._type, line), pos, 91); |
IF e1.obj = ePROC THEN |
PARS.check(e1.ident.global, pos, 85) |
END; |
call := FALSE |
ELSIF parser.sym = SCAN.lxEQ THEN |
PARS.check1(FALSE, parser, 96) |
ELSIF parser.sym = SCAN.lxLROUND THEN |
e1 := e; |
ActualParameters(parser, e1); |
PARS.check((e1._type = NIL) OR ODD(e._type.call), pos, 92); |
call := TRUE |
ELSE |
IF e.obj IN {eSYSPROC, eSTPROC} THEN |
stProc(parser, e); |
call := FALSE |
ELSE |
PARS.check(isProc(e), pos, 86); |
PARS.check((e._type.base = NIL) OR ODD(e._type.call), pos, 92); |
PARS.check1(e._type.params.first = NIL, parser, 64); |
call := TRUE |
END |
END; |
IF call THEN |
IF e.obj IN {ePROC, eIMP} THEN |
ProcCall(e, e.ident._type, FALSE, parser, pos, TRUE) |
ELSIF isExpr(e) THEN |
ProcCall(e, e._type, FALSE, parser, pos, TRUE) |
END |
END; |
IL.popBegEnd(begcall, endcall) |
END ElementaryStatement; |
PROCEDURE IfStatement (parser: PARS.PARSER; _if: BOOLEAN); |
VAR |
e: PARS.EXPR; |
pos: PARS.POSITION; |
label, L: INTEGER; |
BEGIN |
L := IL.NewLabel(); |
IF ~_if THEN |
IL.AddCmd(IL.opNOP, IL.begin_loop); |
IL.SetLabel(L) |
END; |
REPEAT |
NextPos(parser, pos); |
label := IL.NewLabel(); |
expression(parser, e); |
PARS.check(isBoolean(e), pos, 72); |
IF e.obj = eCONST THEN |
IF ~ARITH.getBool(e.value) THEN |
IL.Jmp(IL.opJMP, label) |
END |
ELSE |
IL.AndOrOpt(label) |
END; |
IF _if THEN |
PARS.checklex(parser, SCAN.lxTHEN) |
ELSE |
PARS.checklex(parser, SCAN.lxDO) |
END; |
PARS.Next(parser); |
parser.StatSeq(parser); |
IF ~_if OR (parser.sym # SCAN.lxEND) THEN |
IL.Jmp(IL.opJMP, L) |
END; |
IL.SetLabel(label) |
UNTIL parser.sym # SCAN.lxELSIF; |
IF _if THEN |
IF parser.sym = SCAN.lxELSE THEN |
PARS.Next(parser); |
parser.StatSeq(parser) |
END; |
IL.SetLabel(L) |
ELSE |
IL.AddCmd(IL.opNOP, IL.end_loop) |
END; |
PARS.checklex(parser, SCAN.lxEND); |
PARS.Next(parser) |
END IfStatement; |
PROCEDURE RepeatStatement (parser: PARS.PARSER); |
VAR |
e: PARS.EXPR; |
pos: PARS.POSITION; |
label: INTEGER; |
L: IL.COMMAND; |
BEGIN |
IL.AddCmd(IL.opNOP, IL.begin_loop); |
label := IL.NewLabel(); |
IL.SetLabel(label); |
L := IL.getlast(); |
PARS.Next(parser); |
parser.StatSeq(parser); |
PARS.checklex(parser, SCAN.lxUNTIL); |
NextPos(parser, pos); |
expression(parser, e); |
PARS.check(isBoolean(e), pos, 72); |
IF e.obj = eCONST THEN |
IF ~ARITH.getBool(e.value) THEN |
IL.Jmp(IL.opJMP, label) |
END |
ELSE |
IL.AndOrOpt(label); |
L.param1 := label |
END; |
IL.AddCmd(IL.opNOP, IL.end_loop) |
END RepeatStatement; |
PROCEDURE LabelCmp (a, b: AVL.DATA): INTEGER; |
VAR |
La, Ra, Lb, Rb, res: INTEGER; |
BEGIN |
La := a(CASE_LABEL).range.a; |
Ra := a(CASE_LABEL).range.b; |
Lb := b(CASE_LABEL).range.a; |
Rb := b(CASE_LABEL).range.b; |
IF (Ra < Lb) OR (La > Rb) THEN |
res := ORD(La > Lb) - ORD(La < Lb) |
ELSE |
res := 0 |
END |
RETURN res |
END LabelCmp; |
PROCEDURE DestroyLabel (VAR label: AVL.DATA); |
BEGIN |
C.push(CaseLabels, label); |
label := NIL |
END DestroyLabel; |
PROCEDURE NewVariant (label: INTEGER; cmd: IL.COMMAND): CASE_VARIANT; |
VAR |
res: CASE_VARIANT; |
citem: C.ITEM; |
BEGIN |
citem := C.pop(CaseVar); |
IF citem = NIL THEN |
NEW(res) |
ELSE |
res := citem(CASE_VARIANT) |
END; |
res.label := label; |
res.cmd := cmd; |
res.processed := FALSE |
RETURN res |
END NewVariant; |
PROCEDURE CaseStatement (parser: PARS.PARSER); |
VAR |
e: PARS.EXPR; |
pos: PARS.POSITION; |
PROCEDURE Label (parser: PARS.PARSER; caseExpr: PARS.EXPR; VAR _type: PROG._TYPE): INTEGER; |
VAR |
a: INTEGER; |
label: PARS.EXPR; |
pos: PARS.POSITION; |
value: ARITH.VALUE; |
BEGIN |
getpos(parser, pos); |
_type := NIL; |
IF isChar(caseExpr) THEN |
PARS.ConstExpression(parser, value); |
PARS.check(value.typ = ARITH.tCHAR, pos, 99); |
a := ARITH.getInt(value) |
ELSIF isCharW(caseExpr) THEN |
PARS.ConstExpression(parser, value); |
IF (value.typ = ARITH.tSTRING) & (_length(value.string(SCAN.STRING).s) = 1) & (LENGTH(value.string(SCAN.STRING).s) > 1) THEN |
ASSERT(ARITH.setInt(value, StrToWChar(value.string(SCAN.STRING).s))) |
ELSE |
PARS.check(value.typ IN {ARITH.tWCHAR, ARITH.tCHAR}, pos, 99) |
END; |
a := ARITH.getInt(value) |
ELSIF isInt(caseExpr) THEN |
PARS.ConstExpression(parser, value); |
PARS.check(value.typ = ARITH.tINTEGER, pos, 99); |
a := ARITH.getInt(value) |
ELSIF isRecPtr(caseExpr) THEN |
qualident(parser, label); |
PARS.check(label.obj = eTYPE, pos, 79); |
PARS.check(PROG.isBaseOf(caseExpr._type, label._type), pos, 99); |
IF isRec(caseExpr) THEN |
a := label._type.num |
ELSE |
a := label._type.base.num |
END; |
_type := label._type |
END |
RETURN a |
END Label; |
PROCEDURE CheckType (node: AVL.NODE; _type: PROG._TYPE; parser: PARS.PARSER; pos: PARS.POSITION); |
BEGIN |
IF node # NIL THEN |
PARS.check(~(PROG.isBaseOf(node.data(CASE_LABEL)._type, _type) OR PROG.isBaseOf(_type, node.data(CASE_LABEL)._type)), pos, 100); |
CheckType(node.left, _type, parser, pos); |
CheckType(node.right, _type, parser, pos) |
END |
END CheckType; |
PROCEDURE LabelRange (parser: PARS.PARSER; caseExpr: PARS.EXPR; VAR tree: AVL.NODE; variant: INTEGER): AVL.NODE; |
VAR |
label: CASE_LABEL; |
citem: C.ITEM; |
pos, pos1: PARS.POSITION; |
node: AVL.NODE; |
newnode: BOOLEAN; |
range: RANGE; |
BEGIN |
citem := C.pop(CaseLabels); |
IF citem = NIL THEN |
NEW(label) |
ELSE |
label := citem(CASE_LABEL) |
END; |
label.variant := variant; |
label.self := IL.NewLabel(); |
getpos(parser, pos1); |
range.a := Label(parser, caseExpr, label._type); |
IF parser.sym = SCAN.lxRANGE THEN |
PARS.check1(~isRecPtr(caseExpr), parser, 53); |
NextPos(parser, pos); |
range.b := Label(parser, caseExpr, label._type); |
PARS.check(range.a <= range.b, pos, 103) |
ELSE |
range.b := range.a |
END; |
label.range := range; |
IF isRecPtr(caseExpr) THEN |
CheckType(tree, label._type, parser, pos1) |
END; |
tree := AVL.insert(tree, label, LabelCmp, newnode, node); |
PARS.check(newnode, pos1, 100) |
RETURN node |
END LabelRange; |
PROCEDURE CaseLabelList (parser: PARS.PARSER; caseExpr: PARS.EXPR; VAR tree: AVL.NODE; variant: INTEGER): AVL.NODE; |
VAR |
exit: BOOLEAN; |
res: AVL.NODE; |
BEGIN |
exit := FALSE; |
REPEAT |
res := LabelRange(parser, caseExpr, tree, variant); |
IF parser.sym = SCAN.lxCOMMA THEN |
PARS.check1(~isRecPtr(caseExpr), parser, 53); |
PARS.Next(parser) |
ELSE |
exit := TRUE |
END |
UNTIL exit |
RETURN res |
END CaseLabelList; |
PROCEDURE _case (parser: PARS.PARSER; caseExpr: PARS.EXPR; VAR tree: AVL.NODE; _end: INTEGER); |
VAR |
sym: INTEGER; |
t: PROG._TYPE; |
variant: INTEGER; |
node: AVL.NODE; |
last: IL.COMMAND; |
BEGIN |
sym := parser.sym; |
IF sym # SCAN.lxBAR THEN |
variant := IL.NewLabel(); |
node := CaseLabelList(parser, caseExpr, tree, variant); |
PARS.checklex(parser, SCAN.lxCOLON); |
PARS.Next(parser); |
IF isRecPtr(caseExpr) THEN |
t := caseExpr._type; |
caseExpr.ident._type := node.data(CASE_LABEL)._type |
END; |
last := IL.getlast(); |
IL.SetLabel(variant); |
IF ~isRecPtr(caseExpr) THEN |
LISTS.push(CaseVariants, NewVariant(variant, last)) |
END; |
parser.StatSeq(parser); |
IL.Jmp(IL.opJMP, _end); |
IF isRecPtr(caseExpr) THEN |
caseExpr.ident._type := t |
END |
END |
END _case; |
PROCEDURE Table (node: AVL.NODE; _else: INTEGER); |
VAR |
L, R: INTEGER; |
range: RANGE; |
left, right: AVL.NODE; |
last: IL.COMMAND; |
v: CASE_VARIANT; |
BEGIN |
IF node # NIL THEN |
range := node.data(CASE_LABEL).range; |
left := node.left; |
IF left # NIL THEN |
L := left.data(CASE_LABEL).self |
ELSE |
L := _else |
END; |
right := node.right; |
IF right # NIL THEN |
R := right.data(CASE_LABEL).self |
ELSE |
R := _else |
END; |
last := IL.getlast(); |
v := CaseVariants.last(CASE_VARIANT); |
WHILE (v # NIL) & (v.label # 0) & (v.label # node.data(CASE_LABEL).variant) DO |
v := v.prev(CASE_VARIANT) |
END; |
ASSERT((v # NIL) & (v.label # 0)); |
IL.setlast(v.cmd); |
IL.SetLabel(node.data(CASE_LABEL).self); |
IL._case(range.a, range.b, L, R); |
IF v.processed THEN |
IL.Jmp(IL.opJMP, node.data(CASE_LABEL).variant) |
END; |
v.processed := TRUE; |
IL.setlast(last); |
Table(left, _else); |
Table(right, _else) |
END |
END Table; |
PROCEDURE TableT (node: AVL.NODE); |
BEGIN |
IF node # NIL THEN |
IL.AddCmd2(IL.opCASET, node.data(CASE_LABEL).variant, node.data(CASE_LABEL).range.a); |
TableT(node.left); |
TableT(node.right) |
END |
END TableT; |
PROCEDURE ParseCase (parser: PARS.PARSER; e: PARS.EXPR; pos: PARS.POSITION); |
VAR |
table, _end, _else: INTEGER; |
tree: AVL.NODE; |
item: LISTS.ITEM; |
BEGIN |
LISTS.push(CaseVariants, NewVariant(0, NIL)); |
_end := IL.NewLabel(); |
_else := IL.NewLabel(); |
table := IL.NewLabel(); |
IL.AddCmd(IL.opSWITCH, ORD(isRecPtr(e))); |
IL.Jmp(IL.opJMP, table); |
tree := NIL; |
_case(parser, e, tree, _end); |
WHILE parser.sym = SCAN.lxBAR DO |
PARS.Next(parser); |
_case(parser, e, tree, _end) |
END; |
IL.SetLabel(_else); |
IF parser.sym = SCAN.lxELSE THEN |
PARS.Next(parser); |
parser.StatSeq(parser); |
IL.Jmp(IL.opJMP, _end) |
ELSE |
IL.OnError(pos.line, errCASE) |
END; |
PARS.checklex(parser, SCAN.lxEND); |
PARS.Next(parser); |
IF isRecPtr(e) THEN |
IL.SetLabel(table); |
TableT(tree); |
IL.Jmp(IL.opJMP, _else) |
ELSE |
tree.data(CASE_LABEL).self := table; |
Table(tree, _else) |
END; |
AVL.destroy(tree, DestroyLabel); |
IL.SetLabel(_end); |
IL.AddCmd0(IL.opENDSW); |
REPEAT |
item := LISTS.pop(CaseVariants); |
C.push(CaseVar, item) |
UNTIL item(CASE_VARIANT).cmd = NIL |
END ParseCase; |
BEGIN |
NextPos(parser, pos); |
expression(parser, e); |
PARS.check(isInt(e) OR isChar(e) OR isCharW(e) OR isPtr(e) OR isRec(e), pos, 95); |
IF isRecPtr(e) THEN |
PARS.check(isVar(e), pos, 93); |
PARS.check(e.ident # NIL, pos, 106) |
END; |
IF isRec(e) THEN |
PARS.check(e.obj = eVREC, pos, 78) |
END; |
IF e.obj = eCONST THEN |
LoadConst(e) |
ELSIF isRec(e) THEN |
IL.drop; |
IL.AddCmd(IL.opLADR, e.ident.offset - 1); |
IL.load(TARGETS.WordSize) |
ELSIF isPtr(e) THEN |
deref(pos, e, FALSE, errPTR); |
IL.AddCmd(IL.opSUBR, TARGETS.WordSize); |
IL.load(TARGETS.WordSize) |
END; |
PARS.checklex(parser, SCAN.lxOF); |
PARS.Next(parser); |
ParseCase(parser, e, pos) |
END CaseStatement; |
PROCEDURE ForStatement (parser: PARS.PARSER); |
VAR |
e: PARS.EXPR; |
pos, pos2: PARS.POSITION; |
step: ARITH.VALUE; |
st: INTEGER; |
ident: PROG.IDENT; |
offset: INTEGER; |
L1, L2: INTEGER; |
BEGIN |
IL.AddCmd(IL.opNOP, IL.begin_loop); |
L1 := IL.NewLabel(); |
L2 := IL.NewLabel(); |
PARS.ExpectSym(parser, SCAN.lxIDENT); |
ident := PROG.getIdent(parser.unit, parser.lex.ident, TRUE); |
PARS.check1(ident # NIL, parser, 48); |
PARS.check1(ident.typ = PROG.idVAR, parser, 93); |
PARS.check1(ident._type = tINTEGER, parser, 97); |
PARS.ExpectSym(parser, SCAN.lxASSIGN); |
NextPos(parser, pos); |
expression(parser, e); |
PARS.check(isInt(e), pos, 76); |
offset := PROG.getOffset(ident); |
IF ident.global THEN |
IL.AddCmd(IL.opGADR, offset) |
ELSE |
IL.AddCmd(IL.opLADR, -offset) |
END; |
IF e.obj = eCONST THEN |
IL.AddCmd(IL.opSAVEC, ARITH.Int(e.value)) |
ELSE |
IL.AddCmd0(IL.opSAVE) |
END; |
IL.SetLabel(L1); |
IF ident.global THEN |
IL.AddCmd(IL.opGADR, offset) |
ELSE |
IL.AddCmd(IL.opLADR, -offset) |
END; |
IL.load(ident._type.size); |
PARS.checklex(parser, SCAN.lxTO); |
NextPos(parser, pos2); |
expression(parser, e); |
PARS.check(isInt(e), pos2, 76); |
IF parser.sym = SCAN.lxBY THEN |
NextPos(parser, pos); |
PARS.ConstExpression(parser, step); |
PARS.check(step.typ = ARITH.tINTEGER, pos, 76); |
st := ARITH.getInt(step); |
PARS.check(st # 0, pos, 98) |
ELSE |
st := 1 |
END; |
IF e.obj = eCONST THEN |
IF st > 0 THEN |
IL.AddCmd(IL.opLEC, ARITH.Int(e.value)); |
IF ARITH.Int(e.value) = UTILS.target.maxInt THEN |
ERRORS.WarningMsg(pos2.line, pos2.col, 1) |
END |
ELSE |
IL.AddCmd(IL.opGEC, ARITH.Int(e.value)); |
IF ARITH.Int(e.value) = UTILS.target.minInt THEN |
ERRORS.WarningMsg(pos2.line, pos2.col, 1) |
END |
END |
ELSE |
IF st > 0 THEN |
IL.AddCmd0(IL.opLE) |
ELSE |
IL.AddCmd0(IL.opGE) |
END |
END; |
IL.Jmp(IL.opJZ, L2); |
PARS.checklex(parser, SCAN.lxDO); |
PARS.Next(parser); |
parser.StatSeq(parser); |
IF ident.global THEN |
IL.AddCmd(IL.opGADR, offset) |
ELSE |
IL.AddCmd(IL.opLADR, -offset) |
END; |
IL.AddCmd(IL.opINCC, st); |
IL.Jmp(IL.opJMP, L1); |
PARS.checklex(parser, SCAN.lxEND); |
PARS.Next(parser); |
IL.SetLabel(L2); |
IL.AddCmd(IL.opNOP, IL.end_loop) |
END ForStatement; |
PROCEDURE statement (parser: PARS.PARSER); |
VAR |
sym: INTEGER; |
BEGIN |
sym := parser.sym; |
IF sym = SCAN.lxIDENT THEN |
ElementaryStatement(parser) |
ELSIF sym = SCAN.lxIF THEN |
IfStatement(parser, TRUE) |
ELSIF sym = SCAN.lxWHILE THEN |
IfStatement(parser, FALSE) |
ELSIF sym = SCAN.lxREPEAT THEN |
RepeatStatement(parser) |
ELSIF sym = SCAN.lxCASE THEN |
CaseStatement(parser) |
ELSIF sym = SCAN.lxFOR THEN |
ForStatement(parser) |
END |
END statement; |
PROCEDURE StatSeq (parser: PARS.PARSER); |
BEGIN |
statement(parser); |
WHILE parser.sym = SCAN.lxSEMI DO |
PARS.Next(parser); |
statement(parser) |
END |
END StatSeq; |
PROCEDURE chkreturn (parser: PARS.PARSER; e: PARS.EXPR; t: PROG._TYPE; pos: PARS.POSITION): BOOLEAN; |
VAR |
res: BOOLEAN; |
BEGIN |
res := assigncomp(e, t); |
IF res THEN |
IF e.obj = eCONST THEN |
IF e._type = tREAL THEN |
Float(parser, e) |
ELSIF e._type.typ = PROG.tNIL THEN |
IL.Const(0) |
ELSE |
LoadConst(e) |
END |
ELSIF (e._type = tINTEGER) & (t = tBYTE) & (chkBYTE IN Options.checking) THEN |
CheckRange(256, pos.line, errBYTE) |
ELSIF e.obj = ePROC THEN |
PARS.check(e.ident.global, pos, 85); |
IL.PushProc(e.ident.proc.label) |
ELSIF e.obj = eIMP THEN |
IL.PushImpProc(e.ident._import) |
END |
END |
RETURN res |
END chkreturn; |
PROCEDURE setrtl; |
VAR |
rtl: PROG.UNIT; |
PROCEDURE getproc (rtl: PROG.UNIT; name: SCAN.IDSTR; idx: INTEGER); |
VAR |
id: PROG.IDENT; |
ident: SCAN.IDENT; |
BEGIN |
SCAN.setIdent(ident, name); |
id := PROG.getIdent(rtl, ident, FALSE); |
IF (id # NIL) & (id._import # NIL) THEN |
IL.set_rtl(idx, -id._import(IL.IMPORT_PROC).label); |
id.proc.used := TRUE |
ELSIF (id # NIL) & (id.proc # NIL) THEN |
IL.set_rtl(idx, id.proc.label); |
id.proc.used := TRUE |
ELSE |
ERRORS.WrongRTL(name) |
END |
END getproc; |
BEGIN |
rtl := PROG.program.rtl; |
ASSERT(rtl # NIL); |
getproc(rtl, "_strcmp", IL._strcmp); |
getproc(rtl, "_length", IL._length); |
getproc(rtl, "_arrcpy", IL._arrcpy); |
getproc(rtl, "_is", IL._is); |
getproc(rtl, "_guard", IL._guard); |
getproc(rtl, "_guardrec", IL._guardrec); |
getproc(rtl, "_new", IL._new); |
getproc(rtl, "_rot", IL._rot); |
getproc(rtl, "_strcpy", IL._strcpy); |
getproc(rtl, "_move", IL._move); |
getproc(rtl, "_set", IL._set); |
getproc(rtl, "_set1", IL._set1); |
getproc(rtl, "_lengthw", IL._lengthw); |
getproc(rtl, "_strcmpw", IL._strcmpw); |
getproc(rtl, "_init", IL._init); |
IF CPU IN {TARGETS.cpuX86, TARGETS.cpuAMD64} THEN |
getproc(rtl, "_error", IL._error); |
getproc(rtl, "_divmod", IL._divmod); |
getproc(rtl, "_exit", IL._exit); |
getproc(rtl, "_dispose", IL._dispose); |
getproc(rtl, "_isrec", IL._isrec); |
getproc(rtl, "_dllentry", IL._dllentry); |
getproc(rtl, "_sofinit", IL._sofinit) |
ELSIF CPU IN {TARGETS.cpuTHUMB, TARGETS.cpuRVM32I, TARGETS.cpuRVM64I} THEN |
getproc(rtl, "_fmul", IL._fmul); |
getproc(rtl, "_fdiv", IL._fdiv); |
getproc(rtl, "_fdivi", IL._fdivi); |
getproc(rtl, "_fadd", IL._fadd); |
getproc(rtl, "_fsub", IL._fsub); |
getproc(rtl, "_fsubi", IL._fsubi); |
getproc(rtl, "_fcmp", IL._fcmp); |
getproc(rtl, "_floor", IL._floor); |
getproc(rtl, "_flt", IL._flt); |
getproc(rtl, "_pack", IL._pack); |
getproc(rtl, "_unpk", IL._unpk); |
IF CPU IN {TARGETS.cpuRVM32I, TARGETS.cpuRVM64I} THEN |
getproc(rtl, "_error", IL._error) |
END |
END |
END setrtl; |
PROCEDURE compile* (path, lib_path, modname, outname: PARS.PATH; target: INTEGER; options: PROG.OPTIONS); |
VAR |
parser: PARS.PARSER; |
ext: PARS.PATH; |
BEGIN |
tINTEGER := PROG.program.stTypes.tINTEGER; |
tBYTE := PROG.program.stTypes.tBYTE; |
tCHAR := PROG.program.stTypes.tCHAR; |
tSET := PROG.program.stTypes.tSET; |
tBOOLEAN := PROG.program.stTypes.tBOOLEAN; |
tWCHAR := PROG.program.stTypes.tWCHAR; |
tREAL := PROG.program.stTypes.tREAL; |
Options := options; |
CPU := TARGETS.CPU; |
ext := UTILS.FILE_EXT; |
CaseLabels := C.create(); |
CaseVar := C.create(); |
CaseVariants := LISTS.create(NIL); |
LISTS.push(CaseVariants, NewVariant(0, NIL)); |
IL.init(CPU); |
IF TARGETS.RTL THEN |
parser := PARS.create(path, lib_path, StatSeq, expression, designator, chkreturn); |
IF parser.open(parser, UTILS.RTL_NAME, UTILS.FILE_EXT) THEN |
parser.parse(parser); |
PARS.destroy(parser) |
ELSE |
PARS.destroy(parser); |
parser := PARS.create(lib_path, lib_path, StatSeq, expression, designator, chkreturn); |
IF parser.open(parser, UTILS.RTL_NAME, UTILS.FILE_EXT) THEN |
parser.parse(parser); |
PARS.destroy(parser) |
ELSE |
ERRORS.FileNotFound(lib_path, UTILS.RTL_NAME, UTILS.FILE_EXT) |
END |
END |
END; |
parser := PARS.create(path, lib_path, StatSeq, expression, designator, chkreturn); |
parser.main := TRUE; |
IF parser.open(parser, modname, UTILS.FILE_EXT) THEN |
parser.parse(parser) |
ELSE |
ERRORS.FileNotFound(path, modname, UTILS.FILE_EXT) |
END; |
PARS.destroy(parser); |
IF PROG.program.bss > UTILS.MAX_GLOBAL_SIZE THEN |
ERRORS.Error(204) |
END; |
IF TARGETS.RTL THEN |
setrtl |
END; |
PROG.DelUnused(IL.DelImport); |
IL.set_bss(PROG.program.bss); |
CASE CPU OF |
|TARGETS.cpuAMD64: AMD64.CodeGen(outname, target, options) |
|TARGETS.cpuX86: X86.CodeGen(outname, target, options) |
|TARGETS.cpuMSP430: MSP430.CodeGen(outname, target, options) |
|TARGETS.cpuTHUMB: THUMB.CodeGen(outname, target, options) |
|TARGETS.cpuRVM32I, |
TARGETS.cpuRVM64I: RVMxI.CodeGen(outname, target, options) |
END |
END compile; |
END STATEMENTS. |
/programs/develop/oberon07/source/STRINGS.ob07 |
---|
0,0 → 1,342 |
(* |
BSD 2-Clause License |
Copyright (c) 2018-2021, Anton Krotov |
All rights reserved. |
*) |
MODULE STRINGS; |
IMPORT UTILS; |
PROCEDURE copy* (src: ARRAY OF CHAR; VAR dst: ARRAY OF CHAR; spos, dpos, count: INTEGER); |
BEGIN |
WHILE count > 0 DO |
dst[dpos] := src[spos]; |
INC(spos); |
INC(dpos); |
DEC(count) |
END |
END copy; |
PROCEDURE append* (VAR s1: ARRAY OF CHAR; s2: ARRAY OF CHAR); |
VAR |
n1, n2: INTEGER; |
BEGIN |
n1 := LENGTH(s1); |
n2 := LENGTH(s2); |
ASSERT(n1 + n2 < LEN(s1)); |
copy(s2, s1, 0, n1, n2); |
s1[n1 + n2] := 0X |
END append; |
PROCEDURE IntToStr* (x: INTEGER; VAR str: ARRAY OF CHAR); |
VAR |
i, a: INTEGER; |
BEGIN |
IF x = UTILS.minint THEN |
IF UTILS.bit_depth = 32 THEN |
COPY("-2147483648", str) |
ELSIF UTILS.bit_depth = 64 THEN |
COPY("-9223372036854775808", str) |
END |
ELSE |
i := 0; |
IF x < 0 THEN |
x := -x; |
i := 1; |
str[0] := "-" |
END; |
a := x; |
REPEAT |
INC(i); |
a := a DIV 10 |
UNTIL a = 0; |
str[i] := 0X; |
REPEAT |
DEC(i); |
str[i] := CHR(x MOD 10 + ORD("0")); |
x := x DIV 10 |
UNTIL x = 0 |
END |
END IntToStr; |
PROCEDURE search* (s: ARRAY OF CHAR; VAR pos: INTEGER; c: CHAR; forward: BOOLEAN); |
VAR |
length: INTEGER; |
BEGIN |
length := LENGTH(s); |
IF (0 <= pos) & (pos < length) THEN |
IF forward THEN |
WHILE (pos < length) & (s[pos] # c) DO |
INC(pos) |
END; |
IF pos = length THEN |
pos := -1 |
END |
ELSE |
WHILE (pos >= 0) & (s[pos] # c) DO |
DEC(pos) |
END |
END |
ELSE |
pos := -1 |
END |
END search; |
PROCEDURE replace* (VAR s: ARRAY OF CHAR; find, repl: CHAR); |
VAR |
i, strlen: INTEGER; |
BEGIN |
strlen := LENGTH(s) - 1; |
FOR i := 0 TO strlen DO |
IF s[i] = find THEN |
s[i] := repl |
END |
END |
END replace; |
PROCEDURE trim* (source: ARRAY OF CHAR; VAR result: ARRAY OF CHAR); |
VAR |
LenS, start, _end, i, j: INTEGER; |
BEGIN |
LenS := LENGTH(source) - 1; |
j := 0; |
IF LenS >= 0 THEN |
start := 0; |
WHILE (start <= LenS) & (source[start] <= 20X) DO |
INC(start) |
END; |
_end := LenS; |
WHILE (_end >= 0) & (source[_end] <= 20X) DO |
DEC(_end) |
END; |
FOR i := start TO _end DO |
result[j] := source[i]; |
INC(j) |
END |
END; |
result[j] := 0X |
END trim; |
PROCEDURE letter* (c: CHAR): BOOLEAN; |
RETURN ("a" <= c) & (c <= "z") OR ("A" <= c) & (c <= "Z") OR (c = "_") |
END letter; |
PROCEDURE digit* (c: CHAR): BOOLEAN; |
RETURN ("0" <= c) & (c <= "9") |
END digit; |
PROCEDURE hexdigit* (c: CHAR): BOOLEAN; |
RETURN ("0" <= c) & (c <= "9") OR ("A" <= c) & (c <= "F") |
END hexdigit; |
PROCEDURE space* (c: CHAR): BOOLEAN; |
RETURN (0X < c) & (c <= 20X) |
END space; |
PROCEDURE cap* (VAR c: CHAR); |
BEGIN |
IF ("a" <= c) & (c <= "z") THEN |
c := CHR(ORD(c) - 32) |
END |
END cap; |
PROCEDURE UpCase* (VAR str: ARRAY OF CHAR); |
VAR |
i: INTEGER; |
BEGIN |
i := LENGTH(str) - 1; |
WHILE i >= 0 DO |
cap(str[i]); |
DEC(i) |
END |
END UpCase; |
PROCEDURE StrToInt* (str: ARRAY OF CHAR; VAR x: INTEGER): BOOLEAN; |
VAR |
i, k: INTEGER; |
res: BOOLEAN; |
BEGIN |
res := TRUE; |
i := 0; |
x := 0; |
k := LENGTH(str); |
WHILE i < k DO |
IF digit(str[i]) THEN |
x := x * 10 + ORD(str[i]) - ORD("0") |
ELSE |
i := k; |
res := FALSE |
END; |
INC(i) |
END |
RETURN res |
END StrToInt; |
PROCEDURE CheckVer (str: ARRAY OF CHAR): BOOLEAN; |
VAR |
i, k: INTEGER; |
res: BOOLEAN; |
BEGIN |
k := LENGTH(str); |
res := k < LEN(str); |
IF res & digit(str[0]) THEN |
i := 0; |
WHILE (i < k) & digit(str[i]) DO |
INC(i) |
END; |
IF (i < k) & (str[i] = ".") THEN |
INC(i); |
IF i < k THEN |
WHILE (i < k) & digit(str[i]) DO |
INC(i) |
END |
ELSE |
res := FALSE |
END |
ELSE |
res := FALSE |
END; |
res := res & (i = k) |
ELSE |
res := FALSE |
END |
RETURN res |
END CheckVer; |
PROCEDURE StrToVer* (str: ARRAY OF CHAR; VAR major, minor: INTEGER): BOOLEAN; |
VAR |
i: INTEGER; |
res: BOOLEAN; |
BEGIN |
res := CheckVer(str); |
IF res THEN |
i := 0; |
minor := 0; |
major := 0; |
WHILE digit(str[i]) DO |
major := major * 10 + ORD(str[i]) - ORD("0"); |
INC(i) |
END; |
INC(i); |
WHILE digit(str[i]) DO |
minor := minor * 10 + ORD(str[i]) - ORD("0"); |
INC(i) |
END |
END |
RETURN res |
END StrToVer; |
PROCEDURE Utf8To16* (src: ARRAY OF CHAR; VAR dst: ARRAY OF WCHAR): INTEGER; |
VAR |
i, j, u, srclen, dstlen: INTEGER; |
c: CHAR; |
BEGIN |
srclen := LEN(src); |
dstlen := LEN(dst); |
i := 0; |
j := 0; |
WHILE (i < srclen) & (j < dstlen) & (src[i] # 0X) DO |
c := src[i]; |
CASE c OF |
|00X..7FX: |
u := ORD(c) |
|0C1X..0DFX: |
u := (ORD(c) - 0C0H) * 64; |
IF i + 1 < srclen THEN |
INC(i); |
INC(u, ORD(src[i]) MOD 64) |
END |
|0E1X..0EFX: |
u := (ORD(c) - 0E0H) * 4096; |
IF i + 1 < srclen THEN |
INC(i); |
INC(u, (ORD(src[i]) MOD 64) * 64) |
END; |
IF i + 1 < srclen THEN |
INC(i); |
INC(u, ORD(src[i]) MOD 64) |
END |
(* |
|0F1X..0F7X: |
|0F9X..0FBX: |
|0FDX: |
*) |
ELSE |
END; |
INC(i); |
dst[j] := WCHR(u); |
INC(j) |
END; |
IF j < dstlen THEN |
dst[j] := WCHR(0) |
END |
RETURN j |
END Utf8To16; |
PROCEDURE HashStr* (name: ARRAY OF CHAR): INTEGER; |
VAR |
i, h: INTEGER; |
g: SET; |
BEGIN |
h := 0; |
i := 0; |
WHILE name[i] # 0X DO |
h := h * 16 + ORD(name[i]); |
g := BITS(h) * {28..31}; |
h := ORD(BITS(h) / BITS(LSR(ORD(g), 24)) - g); |
INC(i) |
END |
RETURN h |
END HashStr; |
END STRINGS. |
/programs/develop/oberon07/source/TARGETS.ob07 |
---|
0,0 → 1,153 |
(* |
BSD 2-Clause License |
Copyright (c) 2019-2021, Anton Krotov |
All rights reserved. |
*) |
MODULE TARGETS; |
IMPORT UTILS; |
CONST |
MSP430* = 0; |
Win32C* = 1; |
Win32GUI* = 2; |
Win32DLL* = 3; |
KolibriOS* = 4; |
KolibriOSDLL* = 5; |
Win64C* = 6; |
Win64GUI* = 7; |
Win64DLL* = 8; |
Linux32* = 9; |
Linux32SO* = 10; |
Linux64* = 11; |
Linux64SO* = 12; |
STM32CM3* = 13; |
RVM32I* = 14; |
RVM64I* = 15; |
cpuX86* = 0; cpuAMD64* = 1; cpuMSP430* = 2; cpuTHUMB* = 3; |
cpuRVM32I* = 4; cpuRVM64I* = 5; |
osNONE* = 0; osWIN32* = 1; osWIN64* = 2; |
osLINUX32* = 3; osLINUX64* = 4; osKOS* = 5; |
noDISPOSE = {MSP430, STM32CM3, RVM32I, RVM64I}; |
noRTL = {MSP430}; |
libRVM32I = "RVMxI" + UTILS.slash + "32"; |
libRVM64I = "RVMxI" + UTILS.slash + "64"; |
TYPE |
STRING = ARRAY 32 OF CHAR; |
TARGET = RECORD |
target, CPU, OS, RealSize: INTEGER; |
ComLinePar*, LibDir, FileExt: STRING |
END; |
VAR |
Targets*: ARRAY 16 OF TARGET; |
CPUs: ARRAY 6 OF |
RECORD |
BitDepth, InstrSize: INTEGER; |
LittleEndian: BOOLEAN |
END; |
target*, CPU*, BitDepth*, OS*, RealSize*, WordSize*, AdrSize*, InstrSize*: INTEGER; |
ComLinePar*, LibDir*, FileExt*: STRING; |
Import*, Dispose*, RTL*, Dll*, LittleEndian*: BOOLEAN; |
PROCEDURE Enter (idx, CPU, RealSize, OS: INTEGER; ComLinePar, LibDir, FileExt: STRING); |
BEGIN |
Targets[idx].target := idx; |
Targets[idx].CPU := CPU; |
Targets[idx].RealSize := RealSize; |
Targets[idx].OS := OS; |
Targets[idx].ComLinePar := ComLinePar; |
Targets[idx].LibDir := LibDir; |
Targets[idx].FileExt := FileExt; |
END Enter; |
PROCEDURE Select* (ComLineParam: ARRAY OF CHAR): BOOLEAN; |
VAR |
i: INTEGER; |
res: BOOLEAN; |
BEGIN |
i := 0; |
WHILE (i < LEN(Targets)) & (Targets[i].ComLinePar # ComLineParam) DO |
INC(i) |
END; |
res := i < LEN(Targets); |
IF res THEN |
target := Targets[i].target; |
CPU := Targets[i].CPU; |
BitDepth := CPUs[CPU].BitDepth; |
InstrSize := CPUs[CPU].InstrSize; |
LittleEndian := CPUs[CPU].LittleEndian; |
RealSize := Targets[i].RealSize; |
OS := Targets[i].OS; |
ComLinePar := Targets[i].ComLinePar; |
LibDir := Targets[i].LibDir; |
FileExt := Targets[i].FileExt; |
Import := OS IN {osWIN32, osWIN64, osKOS}; |
Dispose := ~(target IN noDISPOSE); |
RTL := ~(target IN noRTL); |
Dll := target IN {Linux32SO, Linux64SO, Win32DLL, Win64DLL, KolibriOSDLL}; |
WordSize := BitDepth DIV 8; |
AdrSize := WordSize |
END |
RETURN res |
END Select; |
PROCEDURE EnterCPU (cpu, BitDepth, InstrSize: INTEGER; LittleEndian: BOOLEAN); |
BEGIN |
CPUs[cpu].BitDepth := BitDepth; |
CPUs[cpu].InstrSize := InstrSize; |
CPUs[cpu].LittleEndian := LittleEndian |
END EnterCPU; |
BEGIN |
EnterCPU(cpuX86, 32, 1, TRUE); |
EnterCPU(cpuAMD64, 64, 1, TRUE); |
EnterCPU(cpuMSP430, 16, 2, TRUE); |
EnterCPU(cpuTHUMB, 32, 2, TRUE); |
EnterCPU(cpuRVM32I, 32, 4, TRUE); |
EnterCPU(cpuRVM64I, 64, 8, TRUE); |
Enter( MSP430, cpuMSP430, 0, osNONE, "msp430", "MSP430", ".hex"); |
Enter( Win32C, cpuX86, 8, osWIN32, "win32con", "Windows", ".exe"); |
Enter( Win32GUI, cpuX86, 8, osWIN32, "win32gui", "Windows", ".exe"); |
Enter( Win32DLL, cpuX86, 8, osWIN32, "win32dll", "Windows", ".dll"); |
Enter( KolibriOS, cpuX86, 8, osKOS, "kosexe", "KolibriOS", ""); |
Enter( KolibriOSDLL, cpuX86, 8, osKOS, "kosdll", "KolibriOS", ".obj"); |
Enter( Win64C, cpuAMD64, 8, osWIN64, "win64con", "Windows", ".exe"); |
Enter( Win64GUI, cpuAMD64, 8, osWIN64, "win64gui", "Windows", ".exe"); |
Enter( Win64DLL, cpuAMD64, 8, osWIN64, "win64dll", "Windows", ".dll"); |
Enter( Linux32, cpuX86, 8, osLINUX32, "linux32exe", "Linux", ""); |
Enter( Linux32SO, cpuX86, 8, osLINUX32, "linux32so", "Linux", ".so"); |
Enter( Linux64, cpuAMD64, 8, osLINUX64, "linux64exe", "Linux", ""); |
Enter( Linux64SO, cpuAMD64, 8, osLINUX64, "linux64so", "Linux", ".so"); |
Enter( STM32CM3, cpuTHUMB, 4, osNONE, "stm32cm3", "STM32CM3", ".hex"); |
Enter( RVM32I, cpuRVM32I, 4, osNONE, "rvm32i", libRVM32I, ".bin"); |
Enter( RVM64I, cpuRVM64I, 8, osNONE, "rvm64i", libRVM64I, ".bin"); |
END TARGETS. |
/programs/develop/oberon07/source/THUMB.ob07 |
---|
0,0 → 1,2466 |
(* |
BSD 2-Clause License |
Copyright (c) 2019-2021, Anton Krotov |
All rights reserved. |
*) |
MODULE THUMB; |
IMPORT PROG, LISTS, CHL := CHUNKLISTS, BIN, REG, IL, C := CONSOLE, |
UTILS, WR := WRITER, HEX, ERRORS, TARGETS; |
CONST |
R0 = 0; R1 = 1; R2 = 2; R3 = 3; R4 = 4; |
SP = 13; LR = 14; PC = 15; |
ACC = R0; |
je = 0; jne = 1; jnb = 2; jb = 3; jge = 10; jl = 11; jg = 12; jle = 13; |
inf = 7F800000H; |
minROM* = 16; maxROM* = 65536; |
minRAM* = 4; maxRAM* = 65536; |
maxIVT* = 1023; |
_THUMB2 = 0; _IT = 1; _SDIV = 2; _CBXZ = 3; |
CortexM0 = {}; |
CortexM1 = {}; |
CortexM3 = {_THUMB2, _IT, _SDIV, _CBXZ}; |
CortexM23 = {_SDIV, _CBXZ}; |
TYPE |
COMMAND = IL.COMMAND; |
ANYCODE = POINTER TO RECORD (LISTS.ITEM) |
offset: INTEGER |
END; |
CODE = POINTER TO RECORD (ANYCODE) |
code: INTEGER |
END; |
LABEL = POINTER TO RECORD (ANYCODE) |
label: INTEGER |
END; |
JUMP = POINTER TO RECORD (ANYCODE) |
label, diff, len, cond: INTEGER; |
short: BOOLEAN |
END; |
JMP = POINTER TO RECORD (JUMP) |
END; |
JCC = POINTER TO RECORD (JUMP) |
END; |
CBXZ = POINTER TO RECORD (JUMP) |
reg: INTEGER |
END; |
CALL = POINTER TO RECORD (JUMP) |
END; |
RELOC = POINTER TO RECORD (ANYCODE) |
reg, rel, value: INTEGER |
END; |
RELOCCODE = ARRAY 7 OF INTEGER; |
VAR |
R: REG.REGS; |
tcount: INTEGER; |
CodeList: LISTS.LIST; |
program: BIN.PROGRAM; |
StkCount: INTEGER; |
Target: RECORD |
FlashAdr, |
SRAMAdr, |
IVTLen, |
MinStack, |
Reserved: INTEGER; |
InstrSet: SET; |
isNXP: BOOLEAN |
END; |
IVT: ARRAY maxIVT + 1 OF INTEGER; |
sdivProc, trap, genTrap, entry, emptyProc, int0, genInt: INTEGER; |
PROCEDURE Code (code: INTEGER); |
VAR |
c: CODE; |
BEGIN |
NEW(c); |
c.code := code; |
LISTS.push(CodeList, c) |
END Code; |
PROCEDURE Label (label: INTEGER); |
VAR |
L: LABEL; |
BEGIN |
NEW(L); |
L.label := label; |
LISTS.push(CodeList, L) |
END Label; |
PROCEDURE jcc (cond, label: INTEGER); |
VAR |
j: JCC; |
BEGIN |
NEW(j); |
j.label := label; |
j.cond := cond; |
j.short := FALSE; |
j.len := 3; |
LISTS.push(CodeList, j) |
END jcc; |
PROCEDURE cbxz (cond, reg, label: INTEGER); |
VAR |
j: CBXZ; |
BEGIN |
NEW(j); |
j.label := label; |
j.cond := cond; |
j.reg := reg; |
j.short := FALSE; |
j.len := 4; |
LISTS.push(CodeList, j) |
END cbxz; |
PROCEDURE jmp (label: INTEGER); |
VAR |
j: JMP; |
BEGIN |
NEW(j); |
j.label := label; |
j.short := FALSE; |
j.len := 2; |
LISTS.push(CodeList, j) |
END jmp; |
PROCEDURE call (label: INTEGER); |
VAR |
c: CALL; |
BEGIN |
NEW(c); |
c.label := label; |
c.short := FALSE; |
c.len := 2; |
LISTS.push(CodeList, c) |
END call; |
PROCEDURE reloc (reg, rel, value: INTEGER); |
VAR |
r: RELOC; |
BEGIN |
NEW(r); |
r.reg := reg; |
r.rel := rel; |
r.value := value; |
LISTS.push(CodeList, r) |
END reloc; |
PROCEDURE NewLabel (): INTEGER; |
BEGIN |
BIN.NewLabel(program) |
RETURN IL.NewLabel() |
END NewLabel; |
PROCEDURE range (x, n: INTEGER): BOOLEAN; |
RETURN (0 <= x) & (x < LSL(1, n)) |
END range; |
PROCEDURE srange (x, n: INTEGER): BOOLEAN; |
RETURN (-LSL(1, n - 1) <= x) & (x < LSL(1, n - 1)) |
END srange; |
PROCEDURE gen1 (op, imm, rs, rd: INTEGER); |
BEGIN |
ASSERT(op IN {0..2}); |
ASSERT(range(imm, 5)); |
ASSERT(range(rs, 3)); |
ASSERT(range(rd, 3)); |
Code(LSL(op, 11) + LSL(imm, 6) + LSL(rs, 3) + rd) |
END gen1; |
PROCEDURE gen2 (i, op: BOOLEAN; imm, rs, rd: INTEGER); |
BEGIN |
ASSERT(range(imm, 3)); |
ASSERT(range(rs, 3)); |
ASSERT(range(rd, 3)); |
Code(1800H + LSL(ORD(i), 10) + LSL(ORD(op), 9) + LSL(imm, 6) + LSL(rs, 3) + rd) |
END gen2; |
PROCEDURE gen3 (op, rd, imm: INTEGER); |
BEGIN |
ASSERT(range(op, 2)); |
ASSERT(range(rd, 3)); |
ASSERT(range(imm, 8)); |
Code(2000H + LSL(op, 11) + LSL(rd, 8) + imm) |
END gen3; |
PROCEDURE gen4 (op, rs, rd: INTEGER); |
BEGIN |
ASSERT(range(op, 4)); |
ASSERT(range(rs, 3)); |
ASSERT(range(rd, 3)); |
Code(4000H + LSL(op, 6) + LSL(rs, 3) + rd) |
END gen4; |
PROCEDURE gen5 (op: INTEGER; h1, h2: BOOLEAN; rs, rd: INTEGER); |
BEGIN |
ASSERT(range(op, 2)); |
ASSERT(range(rs, 3)); |
ASSERT(range(rd, 3)); |
Code(4400H + LSL(op, 8) + LSL(ORD(h1), 7) + LSL(ORD(h2), 6) + LSL(rs, 3) + rd) |
END gen5; |
PROCEDURE gen7 (l, b: BOOLEAN; ro, rb, rd: INTEGER); |
BEGIN |
ASSERT(range(ro, 3)); |
ASSERT(range(rb, 3)); |
ASSERT(range(rd, 3)); |
Code(5000H + LSL(ORD(l), 11) + LSL(ORD(b), 10) + LSL(ro, 6) + LSL(rb, 3) + rd) |
END gen7; |
PROCEDURE gen8 (h, s: BOOLEAN; ro, rb, rd: INTEGER); |
BEGIN |
ASSERT(range(ro, 3)); |
ASSERT(range(rb, 3)); |
ASSERT(range(rd, 3)); |
Code(5200H + LSL(ORD(h), 11) + LSL(ORD(s), 10) + LSL(ro, 6) + LSL(rb, 3) + rd) |
END gen8; |
PROCEDURE gen9 (b, l: BOOLEAN; imm, rb, rd: INTEGER); |
BEGIN |
ASSERT(range(imm, 5)); |
ASSERT(range(rb, 3)); |
ASSERT(range(rd, 3)); |
Code(6000H + LSL(ORD(b), 12) + LSL(ORD(l), 11) + LSL(imm, 6) + LSL(rb, 3) + rd) |
END gen9; |
PROCEDURE gen10 (l: BOOLEAN; imm, rb, rd: INTEGER); |
BEGIN |
ASSERT(range(imm, 5)); |
ASSERT(range(rb, 3)); |
ASSERT(range(rd, 3)); |
Code(8000H + LSL(ORD(l), 11) + LSL(imm, 6) + LSL(rb, 3) + rd) |
END gen10; |
PROCEDURE gen11 (l: BOOLEAN; rd, imm: INTEGER); |
BEGIN |
ASSERT(range(rd, 3)); |
ASSERT(range(imm, 8)); |
Code(9000H + LSL(ORD(l), 11) + LSL(rd, 8) + imm) |
END gen11; |
PROCEDURE gen12 (sp: BOOLEAN; rd, imm: INTEGER); |
BEGIN |
ASSERT(range(rd, 3)); |
ASSERT(range(imm, 8)); |
Code(0A000H + LSL(ORD(sp), 11) + LSL(rd, 8) + imm) |
END gen12; |
PROCEDURE gen14 (l, r: BOOLEAN; rlist: SET); |
VAR |
i, n: INTEGER; |
BEGIN |
ASSERT(range(ORD(rlist), 8)); |
n := ORD(r); |
FOR i := 0 TO 7 DO |
IF i IN rlist THEN |
INC(n) |
END |
END; |
IF l THEN |
n := -n |
END; |
INC(StkCount, n); |
Code(0B400H + LSL(ORD(l), 11) + LSL(ORD(r), 8) + ORD(rlist)) |
END gen14; |
PROCEDURE split16 (imm16: INTEGER; VAR imm4, imm1, imm3, imm8: INTEGER); |
BEGIN |
ASSERT(range(imm16, 16)); |
imm8 := imm16 MOD 256; |
imm4 := LSR(imm16, 12); |
imm3 := LSR(imm16, 8) MOD 8; |
imm1 := LSR(imm16, 11) MOD 2; |
END split16; |
PROCEDURE LslImm (r, imm5: INTEGER); |
BEGIN |
gen1(0, imm5, r, r) |
END LslImm; |
PROCEDURE LsrImm (r, imm5: INTEGER); |
BEGIN |
gen1(1, imm5, r, r) |
END LsrImm; |
PROCEDURE AsrImm (r, imm5: INTEGER); |
BEGIN |
gen1(2, imm5, r, r) |
END AsrImm; |
PROCEDURE AddReg (rd, rs, rn: INTEGER); |
BEGIN |
gen2(FALSE, FALSE, rn, rs, rd) |
END AddReg; |
PROCEDURE SubReg (rd, rs, rn: INTEGER); |
BEGIN |
gen2(FALSE, TRUE, rn, rs, rd) |
END SubReg; |
PROCEDURE AddImm8 (rd, imm8: INTEGER); |
BEGIN |
IF imm8 # 0 THEN |
gen3(2, rd, imm8) |
END |
END AddImm8; |
PROCEDURE SubImm8 (rd, imm8: INTEGER); |
BEGIN |
IF imm8 # 0 THEN |
gen3(3, rd, imm8) |
END |
END SubImm8; |
PROCEDURE AddSubImm12 (r, imm12: INTEGER; sub: BOOLEAN); |
VAR |
imm4, imm1, imm3, imm8: INTEGER; |
BEGIN |
split16(imm12, imm4, imm1, imm3, imm8); |
Code(0F200H + LSL(imm1, 10) + r + 0A0H * ORD(sub)); (* addw/subw r, r, imm12 *) |
Code(LSL(imm3, 12) + LSL(r, 8) + imm8) |
END AddSubImm12; |
PROCEDURE MovImm8 (rd, imm8: INTEGER); |
BEGIN |
gen3(0, rd, imm8) |
END MovImm8; |
PROCEDURE CmpImm8 (rd, imm8: INTEGER); |
BEGIN |
gen3(1, rd, imm8) |
END CmpImm8; |
PROCEDURE Neg (r: INTEGER); |
BEGIN |
gen4(9, r, r) |
END Neg; |
PROCEDURE Mul (rd, rs: INTEGER); |
BEGIN |
gen4(13, rs, rd) |
END Mul; |
PROCEDURE Str32 (rs, rb: INTEGER); |
BEGIN |
gen9(FALSE, FALSE, 0, rb, rs) |
END Str32; |
PROCEDURE Ldr32 (rd, rb: INTEGER); |
BEGIN |
gen9(FALSE, TRUE, 0, rb, rd) |
END Ldr32; |
PROCEDURE Str16 (rs, rb: INTEGER); |
BEGIN |
gen10(FALSE, 0, rb, rs) |
END Str16; |
PROCEDURE Ldr16 (rd, rb: INTEGER); |
BEGIN |
gen10(TRUE, 0, rb, rd) |
END Ldr16; |
PROCEDURE Str8 (rs, rb: INTEGER); |
BEGIN |
gen9(TRUE, FALSE, 0, rb, rs) |
END Str8; |
PROCEDURE Ldr8 (rd, rb: INTEGER); |
BEGIN |
gen9(TRUE, TRUE, 0, rb, rd) |
END Ldr8; |
PROCEDURE Cmp (r1, r2: INTEGER); |
BEGIN |
gen4(10, r2, r1) |
END Cmp; |
PROCEDURE Tst (r: INTEGER); |
BEGIN |
gen3(1, r, 0) (* cmp r, 0 *) |
END Tst; |
PROCEDURE LdrSp (r, offset: INTEGER); |
BEGIN |
gen11(TRUE, r, offset) |
END LdrSp; |
PROCEDURE MovImm32 (r, imm32: INTEGER); |
BEGIN |
MovImm8(r, LSR(imm32, 24) MOD 256); |
LslImm(r, 8); |
AddImm8(r, LSR(imm32, 16) MOD 256); |
LslImm(r, 8); |
AddImm8(r, LSR(imm32, 8) MOD 256); |
LslImm(r, 8); |
AddImm8(r, imm32 MOD 256) |
END MovImm32; |
PROCEDURE low (x: INTEGER): INTEGER; |
RETURN x MOD 65536 |
END low; |
PROCEDURE high (x: INTEGER): INTEGER; |
RETURN (x DIV 65536) MOD 65536 |
END high; |
PROCEDURE movwt (r, imm16, t: INTEGER); |
VAR |
imm1, imm3, imm4, imm8: INTEGER; |
BEGIN |
ASSERT(range(r, 3)); |
ASSERT(range(imm16, 16)); |
ASSERT(range(t, 1)); |
split16(imm16, imm4, imm1, imm3, imm8); |
Code(0F240H + imm1 * 1024 + t * 128 + imm4); |
Code(imm3 * 4096 + r * 256 + imm8); |
END movwt; |
PROCEDURE inv0 (cond: INTEGER): INTEGER; |
RETURN ORD(BITS(cond) / {0}) |
END inv0; |
PROCEDURE fixup (CodeAdr, DataAdr, BssAdr: INTEGER); |
VAR |
code: ANYCODE; |
count: INTEGER; |
shorted: BOOLEAN; |
jump: JUMP; |
reloc, i, diff, len: INTEGER; |
RelocCode: RELOCCODE; |
PROCEDURE genjcc (cond, offset: INTEGER): INTEGER; |
BEGIN |
ASSERT(range(cond, 4)); |
ASSERT(srange(offset, 8)) |
RETURN 0D000H + cond * 256 + offset MOD 256 |
END genjcc; |
PROCEDURE genjmp (offset: INTEGER): INTEGER; |
BEGIN |
ASSERT(srange(offset, 11)) |
RETURN 0E000H + offset MOD 2048 |
END genjmp; |
PROCEDURE movwt (r, imm16, t: INTEGER; VAR code: RELOCCODE); |
VAR |
imm1, imm3, imm4, imm8: INTEGER; |
BEGIN |
split16(imm16, imm4, imm1, imm3, imm8); |
code[t * 2] := 0F240H + imm1 * 1024 + t * 128 + imm4; |
code[t * 2 + 1] := imm3 * 4096 + r * 256 + imm8 |
END movwt; |
PROCEDURE genmovimm32 (r, value: INTEGER; VAR code: RELOCCODE); |
BEGIN |
IF _THUMB2 IN Target.InstrSet THEN |
movwt(r, low(value), 0, code); |
movwt(r, high(value), 1, code) |
ELSE |
code[0] := 2000H + r * 256 + UTILS.Byte(value, 3); (* movs r, imm8 *) |
code[1] := 0200H + r * 9; (* lsls r, 8 *) |
code[2] := 3000H + r * 256 + UTILS.Byte(value, 2); (* adds r, imm8 *) |
code[3] := code[1]; (* lsls r, 8 *) |
code[4] := 3000H + r * 256 + UTILS.Byte(value, 1); (* adds r, imm8 *) |
code[5] := code[1]; (* lsls r, 8 *) |
code[6] := 3000H + r * 256 + UTILS.Byte(value, 0) (* adds r, imm8 *) |
END |
END genmovimm32; |
PROCEDURE PutCode (code: INTEGER); |
BEGIN |
BIN.PutCode16LE(program, code) |
END PutCode; |
PROCEDURE genlongjmp (offset: INTEGER); |
BEGIN |
ASSERT(srange(offset, 22)); |
PutCode(0F000H + ASR(offset, 11) MOD 2048); |
PutCode(0F800H + offset MOD 2048) |
END genlongjmp; |
PROCEDURE genbc (code: JUMP); |
BEGIN |
CASE code.len OF |
|1: PutCode(genjcc(code.cond, code.diff)) |
|2: PutCode(genjcc(inv0(code.cond), 0)); |
PutCode(genjmp(code.diff)) |
|3: PutCode(genjcc(inv0(code.cond), 1)); |
genlongjmp(code.diff) |
END |
END genbc; |
PROCEDURE SetIV (idx, label, CodeAdr: INTEGER); |
VAR |
l, h: LISTS.ITEM; |
BEGIN |
l := CodeList.first; |
h := l.next; |
WHILE idx > 0 DO |
l := h.next; |
h := l.next; |
DEC(idx) |
END; |
label := BIN.GetLabel(program, label) * 2 + CodeAdr + 1; |
l(CODE).code := low(label); |
h(CODE).code := high(label) |
END SetIV; |
BEGIN |
REPEAT |
shorted := FALSE; |
count := 0; |
code := CodeList.first(ANYCODE); |
WHILE code # NIL DO |
code.offset := count; |
CASE code OF |
|CODE: INC(count) |
|LABEL: BIN.SetLabel(program, code.label, count) |
|JUMP: INC(count, code.len); code.offset := count + ORD(code.short) |
|RELOC: INC(count, 7 - ORD(_THUMB2 IN Target.InstrSet) * 3 + code.rel MOD 2) |
END; |
code := code.next(ANYCODE) |
END; |
code := CodeList.first(ANYCODE); |
WHILE code # NIL DO |
IF code IS JUMP THEN |
jump := code(JUMP); |
jump.diff := BIN.GetLabel(program, jump.label) - jump.offset; |
len := jump.len; |
diff := jump.diff; |
CASE jump OF |
|JMP: |
IF (len = 2) & srange(diff, 11) THEN |
len := 1 |
END |
|JCC: |
CASE len OF |
|1: |
|2: IF srange(diff, 8) THEN DEC(len) END |
|3: IF srange(diff, 11) THEN DEC(len) END |
END |
|CBXZ: |
CASE len OF |
|1: |
|2: IF range(diff, 6) THEN DEC(len) END |
|3: IF srange(diff, 8) THEN DEC(len) END |
|4: IF srange(diff, 11) THEN DEC(len) END |
END |
|CALL: |
END; |
IF len # jump.len THEN |
jump.len := len; |
jump.short := TRUE; |
shorted := TRUE |
END |
END; |
code := code.next(ANYCODE) |
END |
UNTIL ~shorted; |
FOR i := 1 TO Target.IVTLen - 1 DO |
SetIV(i, IVT[i], CodeAdr) |
END; |
code := CodeList.first(ANYCODE); |
WHILE code # NIL DO |
CASE code OF |
|CODE: BIN.PutCode16LE(program, code.code) |
|LABEL: |
|JMP: |
IF code.len = 1 THEN |
PutCode(genjmp(code.diff)) |
ELSE |
genlongjmp(code.diff) |
END |
|JCC: genbc(code) |
|CBXZ: |
IF code.len > 1 THEN |
PutCode(2800H + code.reg * 256); (* cmp code.reg, 0 *) |
DEC(code.len); |
genbc(code) |
ELSE |
(* cb(n)z code.reg, L *) |
PutCode(0B100H + 800H * ORD(code.cond = jne) + 200H * (code.diff DIV 32) + (code.diff MOD 32) * 8 + code.reg) |
END |
|CALL: genlongjmp(code.diff) |
|RELOC: |
CASE code.rel OF |
|BIN.RCODE, BIN.PICCODE: reloc := BIN.GetLabel(program, code.value) * 2 + CodeAdr |
|BIN.RDATA, BIN.PICDATA: reloc := code.value + DataAdr |
|BIN.RBSS, BIN.PICBSS: reloc := code.value + BssAdr |
END; |
IF code.rel IN {BIN.PICCODE, BIN.PICDATA, BIN.PICBSS} THEN |
DEC(reloc, CodeAdr + 2 * (code.offset - 3 * ORD(_THUMB2 IN Target.InstrSet) + 9)) |
END; |
genmovimm32(code.reg, reloc, RelocCode); |
FOR i := 0 TO 6 - 3 * ORD(_THUMB2 IN Target.InstrSet) DO |
PutCode(RelocCode[i]) |
END; |
IF code.rel IN {BIN.PICCODE, BIN.PICDATA, BIN.PICBSS} THEN |
PutCode(4478H + code.reg) (* add code.reg, pc *) |
END |
END; |
code := code.next(ANYCODE) |
END |
END fixup; |
PROCEDURE push (r: INTEGER); |
BEGIN |
gen14(FALSE, FALSE, {r}) |
END push; |
PROCEDURE pop (r: INTEGER); |
BEGIN |
gen14(TRUE, FALSE, {r}) |
END pop; |
PROCEDURE mov (r1, r2: INTEGER); |
BEGIN |
IF (r1 < 8) & (r2 < 8) THEN |
gen1(0, 0, r2, r1) |
ELSE |
gen5(2, r1 >= 8, r2 >= 8, r2 MOD 8, r1 MOD 8) |
END |
END mov; |
PROCEDURE xchg (r1, r2: INTEGER); |
BEGIN |
push(r1); |
mov(r1, r2); |
pop(r2) |
END xchg; |
PROCEDURE drop; |
BEGIN |
REG.Drop(R) |
END drop; |
PROCEDURE GetAnyReg (): INTEGER; |
RETURN REG.GetAnyReg(R) |
END GetAnyReg; |
PROCEDURE UnOp (VAR r: INTEGER); |
BEGIN |
REG.UnOp(R, r) |
END UnOp; |
PROCEDURE BinOp (VAR r1, r2: INTEGER); |
BEGIN |
REG.BinOp(R, r1, r2) |
END BinOp; |
PROCEDURE PushAll (NumberOfParameters: INTEGER); |
BEGIN |
REG.PushAll(R); |
DEC(R.pushed, NumberOfParameters) |
END PushAll; |
PROCEDURE cond (op: INTEGER): INTEGER; |
VAR |
res: INTEGER; |
BEGIN |
CASE op OF |
|IL.opGT, IL.opGTC: res := jg |
|IL.opGE, IL.opGEC: res := jge |
|IL.opLT, IL.opLTC: res := jl |
|IL.opLE, IL.opLEC: res := jle |
|IL.opEQ, IL.opEQC: res := je |
|IL.opNE, IL.opNEC: res := jne |
END |
RETURN res |
END cond; |
PROCEDURE GetRegA; |
BEGIN |
ASSERT(REG.GetReg(R, ACC)) |
END GetRegA; |
PROCEDURE MovConst (r, c: INTEGER); |
BEGIN |
IF (0 <= c) & (c <= 255) THEN |
MovImm8(r, c) |
ELSIF (-255 <= c) & (c < 0) THEN |
MovImm8(r, -c); |
Neg(r) |
ELSIF UTILS.Log2(c) >= 0 THEN |
MovImm8(r, 1); |
LslImm(r, UTILS.Log2(c)) |
ELSIF c = UTILS.min32 THEN |
MovImm8(r, 1); |
LslImm(r, 31) |
ELSE |
IF _THUMB2 IN Target.InstrSet THEN |
movwt(r, low(c), 0); |
IF (c < 0) OR (c > 65535) THEN |
movwt(r, high(c), 1) |
END |
ELSE |
MovImm32(r, c) |
END |
END |
END MovConst; |
PROCEDURE CmpConst (r, c: INTEGER); |
VAR |
r2: INTEGER; |
BEGIN |
IF (0 <= c) & (c <= 255) THEN |
CmpImm8(r, c) |
ELSE |
r2 := GetAnyReg(); |
ASSERT(r2 # r); |
MovConst(r2, c); |
Cmp(r, r2); |
drop |
END |
END CmpConst; |
PROCEDURE LocalOffset (offset: INTEGER): INTEGER; |
RETURN offset + StkCount - ORD(offset > 0) |
END LocalOffset; |
PROCEDURE SetCC (cc, r: INTEGER); |
VAR |
L1, L2: INTEGER; |
BEGIN |
IF _IT IN Target.InstrSet THEN |
Code(0BF00H + cc * 16 + ((cc + 1) MOD 2) * 8 + 4); (* ite cc *) |
MovConst(r, 1); |
MovConst(r, 0) |
ELSE |
L1 := NewLabel(); |
L2 := NewLabel(); |
jcc(cc, L1); |
MovConst(r, 0); |
jmp(L2); |
Label(L1); |
MovConst(r, 1); |
Label(L2) |
END |
END SetCC; |
PROCEDURE PushConst (n: INTEGER); |
VAR |
r: INTEGER; |
BEGIN |
r := GetAnyReg(); |
MovConst(r, n); |
push(r); |
drop |
END PushConst; |
PROCEDURE AddConst (r, n: INTEGER); |
VAR |
r2: INTEGER; |
BEGIN |
IF n # 0 THEN |
IF (-255 <= n) & (n <= 255) THEN |
IF n > 0 THEN |
AddImm8(r, n) |
ELSE |
SubImm8(r, -n) |
END |
ELSIF (_THUMB2 IN Target.InstrSet) & (-4095 <= n) & (n <= 4095) THEN |
AddSubImm12(r, ABS(n), n < 0) |
ELSE |
r2 := GetAnyReg(); |
ASSERT(r2 # r); |
IF n > 0 THEN |
MovConst(r2, n); |
AddReg(r, r, r2) |
ELSE |
MovConst(r2, -n); |
SubReg(r, r, r2) |
END; |
drop |
END |
END |
END AddConst; |
PROCEDURE AddHH (r1, r2: INTEGER); |
BEGIN |
ASSERT((r1 >= 8) OR (r2 >= 8)); |
gen5(0, r1 >= 8, r2 >= 8, r2 MOD 8, r1 MOD 8) |
END AddHH; |
PROCEDURE AddSP (n: INTEGER); |
BEGIN |
IF n > 0 THEN |
IF n < 127 THEN |
Code(0B000H + n) (* add sp, n*4 *) |
ELSE |
ASSERT(R2 IN R.regs); |
MovConst(R2, n * 4); |
AddHH(SP, R2) |
END; |
DEC(StkCount, n) |
END |
END AddSP; |
PROCEDURE cbxz2 (c, r, label: INTEGER); |
BEGIN |
IF _CBXZ IN Target.InstrSet THEN |
cbxz(c, r, label) |
ELSE |
Tst(r); |
jcc(c, label) |
END |
END cbxz2; |
PROCEDURE cbz (r, label: INTEGER); |
BEGIN |
cbxz2(je, r, label) |
END cbz; |
PROCEDURE cbnz (r, label: INTEGER); |
BEGIN |
cbxz2(jne, r, label) |
END cbnz; |
PROCEDURE Shift (op, r1, r2: INTEGER); |
VAR |
L: INTEGER; |
BEGIN |
LslImm(r2, 27); |
LsrImm(r2, 27); |
L := NewLabel(); |
cbz(r2, L); |
CASE op OF |
|IL.opLSL, IL.opLSL1: gen4(2, r2, r1) |
|IL.opLSR, IL.opLSR1: gen4(3, r2, r1) |
|IL.opASR, IL.opASR1: gen4(4, r2, r1) |
|IL.opROR, IL.opROR1: gen4(7, r2, r1) |
END; |
Label(L) |
END Shift; |
PROCEDURE LocAdr (offs: INTEGER); |
VAR |
r1, n: INTEGER; |
BEGIN |
r1 := GetAnyReg(); |
n := LocalOffset(offs); |
IF n <= 255 THEN |
gen12(TRUE, r1, n) |
ELSE |
MovConst(r1, n * 4); |
AddHH(r1, SP) |
END |
END LocAdr; |
PROCEDURE CallRTL (proc, par: INTEGER); |
BEGIN |
call(IL.codes.rtl[proc]); |
AddSP(par) |
END CallRTL; |
PROCEDURE divmod; |
BEGIN |
call(sdivProc); |
AddSP(2) |
END divmod; |
PROCEDURE cpsid_i; |
BEGIN |
Code(0B672H) (* cpsid i *) |
END cpsid_i; |
PROCEDURE cpsie_i; |
BEGIN |
Code(0B662H) (* cpsie i *) |
END cpsie_i; |
PROCEDURE translate (pic, stroffs: INTEGER); |
VAR |
cmd, next: COMMAND; |
opcode, param1, param2: INTEGER; |
r1, r2, r3: INTEGER; |
a, n, cc, L, L2: INTEGER; |
BEGIN |
cmd := IL.codes.commands.first(COMMAND); |
WHILE cmd # NIL DO |
param1 := cmd.param1; |
param2 := cmd.param2; |
opcode := cmd.opcode; |
CASE opcode OF |
|IL.opJMP: |
jmp(param1) |
|IL.opLABEL: |
Label(param1) |
|IL.opHANDLER: |
IF param2 = 0 THEN |
int0 := param1 |
ELSIF param2 = 1 THEN |
trap := param1 |
ELSE |
IVT[param2] := param1 |
END |
|IL.opCALL: |
call(param1) |
|IL.opCALLP: |
UnOp(r1); |
AddImm8(r1, 1); (* Thumb mode *) |
gen5(3, TRUE, FALSE, r1, 0); (* blx r1 *) |
drop; |
ASSERT(R.top = -1) |
|IL.opENTER: |
ASSERT(R.top = -1); |
Label(param1); |
gen14(FALSE, TRUE, {}); (* push {lr} *) |
n := param2; |
IF n >= 5 THEN |
MovConst(ACC, 0); |
MovConst(R2, n); |
L := NewLabel(); |
Label(L); |
push(ACC); |
SubImm8(R2, 1); |
Tst(R2); |
jcc(jne, L) |
ELSIF n > 0 THEN |
MovConst(ACC, 0); |
WHILE n > 0 DO |
push(ACC); |
DEC(n) |
END |
END; |
StkCount := param2 |
|IL.opLEAVE, IL.opLEAVER, IL.opLEAVEF: |
IF opcode # IL.opLEAVE THEN |
UnOp(r1); |
IF r1 # ACC THEN |
mov(ACC, r1) |
END; |
drop |
END; |
ASSERT(R.top = -1); |
ASSERT(StkCount = param1); |
AddSP(param1); |
gen14(TRUE, TRUE, {}) (* pop {pc} *) |
|IL.opLEAVEC: |
gen5(3, FALSE, TRUE, 6, 0) (* bx lr *) |
|IL.opPRECALL: |
PushAll(0) |
|IL.opPARAM: |
n := param2; |
IF n = 1 THEN |
UnOp(r1); |
push(r1); |
drop |
ELSE |
ASSERT(R.top + 1 <= n); |
PushAll(n) |
END |
|IL.opCLEANUP: |
AddSP(param2) |
|IL.opRES, IL.opRESF: |
ASSERT(R.top = -1); |
GetRegA |
|IL.opPUSHC: |
PushConst(param2) |
|IL.opONERR: |
cpsid_i; |
MovConst(R0, param2); |
push(R0); |
DEC(StkCount); |
jmp(param1) |
|IL.opERR: |
call(genTrap) |
|IL.opNOP, IL.opAND, IL.opOR: |
|IL.opSADR: |
reloc(GetAnyReg(), BIN.RDATA + pic, stroffs + param2) |
|IL.opGADR: |
reloc(GetAnyReg(), BIN.RBSS + pic, param2) |
|IL.opLADR: |
LocAdr(param2) |
|IL.opGLOAD32: |
r1 := GetAnyReg(); |
reloc(r1, BIN.RBSS + pic, param2); |
Ldr32(r1, r1) |
|IL.opGLOAD16: |
r1 := GetAnyReg(); |
reloc(r1, BIN.RBSS + pic, param2); |
Ldr16(r1, r1) |
|IL.opGLOAD8: |
r1 := GetAnyReg(); |
reloc(r1, BIN.RBSS + pic, param2); |
Ldr8(r1, r1) |
|IL.opLADR_SAVE: |
UnOp(r1); |
n := LocalOffset(param2); |
IF n <= 255 THEN |
gen11(FALSE, r1, n) (* str r1, [sp, n*4] *) |
ELSE |
LocAdr(param2); |
BinOp(r1, r2); |
Str32(r1, r2); |
drop |
END; |
drop |
|IL.opLADR_INCC: |
n := LocalOffset(param1); |
IF n <= 255 THEN |
r1 := GetAnyReg(); |
LdrSp(r1, n); |
AddConst(r1, param2); |
gen11(FALSE, r1, n) (* str r1, [sp, n*4] *) |
ELSE |
LocAdr(param1); |
r1 := GetAnyReg(); |
BinOp(r2, r1); |
Ldr32(r1, r2); |
AddConst(r1, param2); |
BinOp(r2, r1); |
Str32(r1, r2); |
drop |
END; |
drop |
|IL.opLLOAD32, IL.opVADR, IL.opVLOAD32: |
r1 := GetAnyReg(); |
n := LocalOffset(param2); |
IF n <= 255 THEN |
LdrSp(r1, n) |
ELSE |
drop; |
LocAdr(param2); |
UnOp(r1); |
Ldr32(r1, r1) |
END; |
IF opcode = IL.opVLOAD32 THEN |
Ldr32(r1, r1) |
END |
|IL.opLLOAD16: |
LocAdr(param2); |
UnOp(r1); |
Ldr16(r1, r1) |
|IL.opLLOAD8: |
LocAdr(param2); |
UnOp(r1); |
Ldr8(r1, r1) |
|IL.opLOAD32, IL.opLOADF: |
UnOp(r1); |
Ldr32(r1, r1) |
|IL.opLOAD16: |
UnOp(r1); |
Ldr16(r1, r1) |
|IL.opLOAD8: |
UnOp(r1); |
Ldr8(r1, r1) |
|IL.opVLOAD16: |
LocAdr(param2); |
UnOp(r1); |
Ldr32(r1, r1); |
Ldr16(r1, r1) |
|IL.opVLOAD8: |
LocAdr(param2); |
UnOp(r1); |
Ldr32(r1, r1); |
Ldr8(r1, r1) |
|IL.opSBOOL: |
BinOp(r2, r1); |
Tst(r2); |
SetCC(jne, r2); |
Str8(r2, r1); |
drop; |
drop |
|IL.opSBOOLC: |
UnOp(r1); |
r2 := GetAnyReg(); |
MovConst(r2, ORD(param2 # 0)); |
Str8(r2, r1); |
drop; |
drop |
|IL.opSAVEC: |
UnOp(r1); |
r2 := GetAnyReg(); |
MovConst(r2, param2); |
Str32(r2, r1); |
drop; |
drop |
|IL.opSAVE16C: |
UnOp(r1); |
r2 := GetAnyReg(); |
MovConst(r2, low(param2)); |
Str16(r2, r1); |
drop; |
drop |
|IL.opSAVE8C: |
UnOp(r1); |
r2 := GetAnyReg(); |
MovConst(r2, param2 MOD 256); |
Str8(r2, r1); |
drop; |
drop |
|IL.opSAVE, IL.opSAVE32, IL.opSAVEF: |
BinOp(r2, r1); |
Str32(r2, r1); |
drop; |
drop |
|IL.opSAVEFI: |
BinOp(r2, r1); |
Str32(r1, r2); |
drop; |
drop |
|IL.opSAVE16: |
BinOp(r2, r1); |
Str16(r2, r1); |
drop; |
drop |
|IL.opSAVE8: |
BinOp(r2, r1); |
Str8(r2, r1); |
drop; |
drop |
|IL.opSAVEP: |
UnOp(r1); |
r2 := GetAnyReg(); |
reloc(r2, BIN.RCODE + pic, param2); |
Str32(r2, r1); |
drop; |
drop |
|IL.opPUSHP: |
reloc(GetAnyReg(), BIN.RCODE + pic, param2) |
|IL.opEQB, IL.opNEB: |
BinOp(r1, r2); |
drop; |
L := NewLabel(); |
cbz(r1, L); |
MovConst(r1, 1); |
Label(L); |
L := NewLabel(); |
cbz(r2, L); |
MovConst(r2, 1); |
Label(L); |
Cmp(r1, r2); |
IF opcode = IL.opEQB THEN |
SetCC(je, r1) |
ELSE |
SetCC(jne, r1) |
END |
|IL.opDROP: |
UnOp(r1); |
drop |
|IL.opJNZ1: |
UnOp(r1); |
cbnz(r1, param1) |
|IL.opJG: |
UnOp(r1); |
Tst(r1); |
jcc(jg, param1) |
|IL.opJNZ: |
UnOp(r1); |
cbnz(r1, param1); |
drop |
|IL.opJZ: |
UnOp(r1); |
cbz(r1, param1); |
drop |
|IL.opSWITCH: |
UnOp(r1); |
IF param2 = 0 THEN |
r2 := ACC |
ELSE |
r2 := R2 |
END; |
IF r1 # r2 THEN |
ASSERT(REG.GetReg(R, r2)); |
ASSERT(REG.Exchange(R, r1, r2)); |
drop |
END; |
drop |
|IL.opENDSW: |
|IL.opCASEL: |
GetRegA; |
CmpConst(ACC, param1); |
jcc(jl, param2); |
drop |
|IL.opCASER: |
GetRegA; |
CmpConst(ACC, param1); |
jcc(jg, param2); |
drop |
|IL.opCASELR: |
GetRegA; |
CmpConst(ACC, param1); |
IF param2 = cmd.param3 THEN |
jcc(jne, param2) |
ELSE |
jcc(jl, param2); |
jcc(jg, cmd.param3) |
END; |
drop |
|IL.opCODE: |
Code(param2) |
|IL.opEQ..IL.opGE, |
IL.opEQC..IL.opGEC: |
IF (IL.opEQ <= opcode) & (opcode <= IL.opGE) THEN |
BinOp(r1, r2); |
Cmp(r1, r2); |
drop |
ELSE |
UnOp(r1); |
CmpConst(r1, param2) |
END; |
drop; |
cc := cond(opcode); |
next := cmd.next(COMMAND); |
IF next.opcode = IL.opJNZ THEN |
jcc(cc, next.param1); |
cmd := next |
ELSIF next.opcode = IL.opJZ THEN |
jcc(inv0(cc), next.param1); |
cmd := next |
ELSE |
SetCC(cc, GetAnyReg()) |
END |
|IL.opINCC: |
UnOp(r1); |
r2 := GetAnyReg(); |
Ldr32(r2, r1); |
AddConst(r2, param2); |
Str32(r2, r1); |
drop; |
drop |
|IL.opINCCB, IL.opDECCB: |
IF opcode = IL.opDECCB THEN |
param2 := -param2 |
END; |
UnOp(r1); |
r2 := GetAnyReg(); |
Ldr8(r2, r1); |
AddConst(r2, param2); |
Str8(r2, r1); |
drop; |
drop |
|IL.opUMINUS: |
UnOp(r1); |
Neg(r1) |
|IL.opADD: |
BinOp(r1, r2); |
CASE cmd.next(COMMAND).opcode OF |
|IL.opLOAD32, IL.opLOADF: |
gen7(TRUE, FALSE, r2, r1, r1); (* ldr r1, [r1, r2] *) |
cmd := cmd.next(COMMAND) |
|IL.opLOAD8: |
gen7(TRUE, TRUE, r2, r1, r1); (* ldrb r1, [r1, r2] *) |
cmd := cmd.next(COMMAND) |
|IL.opLOAD16: |
gen8(TRUE, FALSE, r2, r1, r1); (* ldrh r1, [r1, r2] *) |
cmd := cmd.next(COMMAND) |
ELSE |
AddReg(r1, r1, r2) |
END; |
drop |
|IL.opADDC: |
UnOp(r1); |
AddConst(r1, param2) |
|IL.opSUB: |
BinOp(r1, r2); |
SubReg(r1, r1, r2); |
drop |
|IL.opSUBL, IL.opSUBR: |
UnOp(r1); |
AddConst(r1, -param2); |
IF opcode = IL.opSUBL THEN |
Neg(r1) |
END |
|IL.opMUL: |
BinOp(r1, r2); |
Mul(r1, r2); |
drop |
|IL.opMULC: |
UnOp(r1); |
a := param2; |
IF a > 1 THEN |
n := UTILS.Log2(a) |
ELSIF a < -1 THEN |
n := UTILS.Log2(-a) |
ELSE |
n := -1 |
END; |
IF a = 1 THEN |
ELSIF a = -1 THEN |
Neg(r1) |
ELSIF a = 0 THEN |
MovConst(r1, 0) |
ELSE |
IF n > 0 THEN |
IF a < 0 THEN |
Neg(r1) |
END; |
LslImm(r1, n) |
ELSE |
r2 := GetAnyReg(); |
MovConst(r2, a); |
Mul(r1, r2); |
drop |
END |
END |
|IL.opABS: |
UnOp(r1); |
Tst(r1); |
L := NewLabel(); |
jcc(jge, L); |
Neg(r1); |
Label(L) |
|IL.opNOT: |
UnOp(r1); |
Tst(r1); |
SetCC(je, r1) |
|IL.opORD: |
UnOp(r1); |
Tst(r1); |
SetCC(jne, r1) |
|IL.opCHR: |
UnOp(r1); |
Code(0B2C0H + r1 * 9) (* uxtb r1, r1 *) |
|IL.opWCHR: |
UnOp(r1); |
Code(0B280H + r1 * 9) (* uxth r1, r1 *) |
|IL.opASR, IL.opROR, IL.opLSL, IL.opLSR: |
BinOp(r1, r2); |
Shift(opcode, r1, r2); |
drop |
|IL.opASR1, IL.opROR1, IL.opLSL1, IL.opLSR1: |
MovConst(GetAnyReg(), param2); |
BinOp(r2, r1); |
Shift(opcode, r1, r2); |
INCL(R.regs, r2); |
DEC(R.top); |
R.stk[R.top] := r1 |
|IL.opASR2, IL.opROR2, IL.opLSL2, IL.opLSR2: |
n := param2 MOD 32; |
IF n # 0 THEN |
UnOp(r1); |
CASE opcode OF |
|IL.opASR2: AsrImm(r1, n) |
|IL.opROR2: r2 := GetAnyReg(); MovConst(r2, n); Shift(IL.opROR, r1, r2); drop |
|IL.opLSL2: LslImm(r1, n) |
|IL.opLSR2: LsrImm(r1, n) |
END |
END |
|IL.opCHKBYTE: |
BinOp(r1, r2); |
CmpConst(r1, 256); |
jcc(jb, param1) |
|IL.opCHKIDX: |
UnOp(r1); |
CmpConst(r1, param2); |
jcc(jb, param1) |
|IL.opCHKIDX2: |
BinOp(r1, r2); |
IF param2 # -1 THEN |
Cmp(r2, r1); |
jcc(jb, param1) |
END; |
INCL(R.regs, r1); |
DEC(R.top); |
R.stk[R.top] := r2 |
|IL.opLEN: |
n := param2; |
UnOp(r1); |
drop; |
EXCL(R.regs, r1); |
WHILE n > 0 DO |
UnOp(r2); |
drop; |
DEC(n) |
END; |
INCL(R.regs, r1); |
ASSERT(REG.GetReg(R, r1)) |
|IL.opINF: |
MovConst(GetAnyReg(), inf) |
|IL.opPUSHF: |
UnOp(r1); |
push(r1); |
drop |
|IL.opCONST: |
MovConst(GetAnyReg(), param2) |
|IL.opEQP, IL.opNEP: |
reloc(GetAnyReg(), BIN.RCODE + pic, param1); |
BinOp(r1, r2); |
Cmp(r1, r2); |
drop; |
IF opcode = IL.opEQP THEN |
SetCC(je, r1) |
ELSE |
SetCC(jne, r1) |
END |
|IL.opPUSHT: |
UnOp(r1); |
r2 := GetAnyReg(); |
mov(r2, r1); |
SubImm8(r2, 4); |
Ldr32(r2, r2) |
|IL.opGET, IL.opGETC: |
IF opcode = IL.opGET THEN |
BinOp(r1, r2) |
ELSIF opcode = IL.opGETC THEN |
UnOp(r2); |
r1 := GetAnyReg(); |
MovConst(r1, param1) |
END; |
drop; |
drop; |
CASE param2 OF |
|1: Ldr8(r1, r1); Str8(r1, r2) |
|2: Ldr16(r1, r1); Str16(r1, r2) |
|4: Ldr32(r1, r1); Str32(r1, r2) |
END |
|IL.opINC, IL.opDEC: |
BinOp(r2, r1); |
r3 := GetAnyReg(); |
Ldr32(r3, r1); |
IF opcode = IL.opINC THEN |
AddReg(r3, r3, r2) |
ELSE |
SubReg(r3, r3, r2) |
END; |
Str32(r3, r1); |
drop; |
drop; |
drop |
|IL.opINCB, IL.opDECB: |
BinOp(r2, r1); |
r3 := GetAnyReg(); |
Ldr8(r3, r1); |
IF opcode = IL.opINCB THEN |
AddReg(r3, r3, r2) |
ELSE |
SubReg(r3, r3, r2) |
END; |
Str8(r3, r1); |
drop; |
drop; |
drop |
|IL.opMIN, IL.opMAX: |
BinOp(r1, r2); |
Cmp(r1, r2); |
L := NewLabel(); |
IF opcode = IL.opMIN THEN |
cc := jle |
ELSE |
cc := jge |
END; |
jcc(cc, L); |
mov(r1, r2); |
Label(L); |
drop |
|IL.opMINC, IL.opMAXC: |
UnOp(r1); |
CmpConst(r1, param2); |
L := NewLabel(); |
IF opcode = IL.opMINC THEN |
cc := jle |
ELSE |
cc := jge |
END; |
jcc(cc, L); |
MovConst(r1, param2); |
Label(L) |
|IL.opMULS: |
BinOp(r1, r2); |
gen4(0, r2, r1); (* ands r1, r2 *) |
drop |
|IL.opMULSC: |
MovConst(GetAnyReg(), param2); |
BinOp(r1, r2); |
gen4(0, r2, r1); (* ands r1, r2 *) |
drop |
|IL.opDIVS: |
BinOp(r1, r2); |
gen4(1, r2, r1); (* eors r1, r2 *) |
drop |
|IL.opDIVSC: |
MovConst(GetAnyReg(), param2); |
BinOp(r1, r2); |
gen4(1, r2, r1); (* eors r1, r2 *) |
drop |
|IL.opADDS: |
BinOp(r1, r2); |
gen4(12, r2, r1); (* orrs r1, r2 *) |
drop |
|IL.opSUBS: |
BinOp(r1, r2); |
gen4(14, r2, r1); (* bics r1, r2 *) |
drop |
|IL.opADDSC: |
MovConst(GetAnyReg(), param2); |
BinOp(r1, r2); |
gen4(12, r2, r1); (* orrs r1, r2 *) |
drop |
|IL.opSUBSL: |
MovConst(GetAnyReg(), param2); |
BinOp(r1, r2); |
gen4(14, r1, r2); (* bics r2, r1 *) |
INCL(R.regs, r1); |
DEC(R.top); |
R.stk[R.top] := r2 |
|IL.opSUBSR: |
MovConst(GetAnyReg(), param2); |
BinOp(r1, r2); |
gen4(14, r2, r1); (* bics r1, r2 *) |
drop |
|IL.opUMINS: |
UnOp(r1); |
gen4(15, r1, r1) (* mvns r1, r1 *) |
|IL.opINCL, IL.opEXCL: |
BinOp(r1, r2); |
r3 := GetAnyReg(); |
MovConst(r3, 1); |
CmpConst(r1, 32); |
L := NewLabel(); |
jcc(jnb, L); |
gen4(2, r1, r3); (* lsls r3, r1 *) |
Ldr32(r1, r2); |
IF opcode = IL.opINCL THEN |
gen4(12, r3, r1) (* orrs r1, r3 *) |
ELSE |
gen4(14, r3, r1) (* bics r1, r3 *) |
END; |
Str32(r1, r2); |
Label(L); |
drop; |
drop; |
drop |
|IL.opINCLC, IL.opEXCLC: |
UnOp(r2); |
r1 := GetAnyReg(); |
r3 := GetAnyReg(); |
MovConst(r3, 1); |
LslImm(r3, param2); |
Ldr32(r1, r2); |
IF opcode = IL.opINCLC THEN |
gen4(12, r3, r1) (* orrs r1, r3 *) |
ELSE |
gen4(14, r3, r1) (* bics r1, r3 *) |
END; |
Str32(r1, r2); |
drop; |
drop; |
drop |
|IL.opLENGTH: |
PushAll(2); |
CallRTL(IL._length, 2); |
GetRegA |
|IL.opLENGTHW: |
PushAll(2); |
CallRTL(IL._lengthw, 2); |
GetRegA |
|IL.opSAVES: |
UnOp(r2); |
REG.PushAll_1(R); |
r1 := GetAnyReg(); |
reloc(r1, BIN.RDATA + pic, stroffs + param2); |
push(r1); |
drop; |
push(r2); |
drop; |
PushConst(param1); |
CallRTL(IL._move, 3) |
|IL.opEQS .. IL.opGES: |
PushAll(4); |
PushConst(opcode - IL.opEQS); |
CallRTL(IL._strcmp, 5); |
GetRegA |
|IL.opEQSW .. IL.opGESW: |
PushAll(4); |
PushConst(opcode - IL.opEQSW); |
CallRTL(IL._strcmpw, 5); |
GetRegA |
|IL.opCOPY: |
PushAll(2); |
PushConst(param2); |
CallRTL(IL._move, 3) |
|IL.opMOVE: |
PushAll(3); |
CallRTL(IL._move, 3) |
|IL.opCOPYA: |
PushAll(4); |
PushConst(param2); |
CallRTL(IL._arrcpy, 5); |
GetRegA |
|IL.opCOPYS: |
PushAll(4); |
PushConst(param2); |
CallRTL(IL._strcpy, 5) |
|IL.opDIV: |
PushAll(2); |
divmod; |
GetRegA |
|IL.opDIVL: |
UnOp(r1); |
REG.PushAll_1(R); |
PushConst(param2); |
push(r1); |
drop; |
divmod; |
GetRegA |
|IL.opDIVR: |
n := UTILS.Log2(param2); |
IF n > 0 THEN |
UnOp(r1); |
AsrImm(r1, n) |
ELSIF n < 0 THEN |
PushAll(1); |
PushConst(param2); |
divmod; |
GetRegA |
END |
|IL.opMOD: |
PushAll(2); |
divmod; |
mov(R0, R1); |
GetRegA |
|IL.opMODR: |
n := UTILS.Log2(param2); |
IF n > 0 THEN |
UnOp(r1); |
IF n = 8 THEN |
Code(0B2C0H + r1 * 9) (* uxtb r1, r1 *) |
ELSIF n = 16 THEN |
Code(0B280H + r1 * 9) (* uxth r1, r1 *) |
ELSE |
LslImm(r1, 32 - n); |
LsrImm(r1, 32 - n) |
END |
ELSIF n < 0 THEN |
PushAll(1); |
PushConst(param2); |
divmod; |
mov(R0, R1); |
GetRegA |
ELSE |
UnOp(r1); |
MovConst(r1, 0) |
END |
|IL.opMODL: |
UnOp(r1); |
REG.PushAll_1(R); |
PushConst(param2); |
push(r1); |
drop; |
divmod; |
mov(R0, R1); |
GetRegA |
|IL.opIN, IL.opINR: |
IF opcode = IL.opINR THEN |
r2 := GetAnyReg(); |
MovConst(r2, param2) |
END; |
L := NewLabel(); |
L2 := NewLabel(); |
BinOp(r1, r2); |
r3 := GetAnyReg(); |
CmpConst(r1, 32); |
jcc(jb, L); |
MovConst(r1, 0); |
jmp(L2); |
Label(L); |
MovConst(r3, 1); |
Shift(IL.opLSL, r3, r1); |
gen4(0, r3, r2); (* ands r2, r3 *) |
SetCC(jne, r1); |
Label(L2); |
drop; |
drop |
|IL.opINL: |
UnOp(r1); |
r2 := GetAnyReg(); |
MovConst(r2, LSL(1, param2)); |
gen4(0, r2, r1); (* ands r1, r2 *) |
SetCC(jne, r1); |
drop |
|IL.opRSET: |
PushAll(2); |
CallRTL(IL._set, 2); |
GetRegA |
|IL.opRSETR: |
PushAll(1); |
PushConst(param2); |
CallRTL(IL._set, 2); |
GetRegA |
|IL.opRSETL: |
UnOp(r1); |
REG.PushAll_1(R); |
PushConst(param2); |
push(r1); |
drop; |
CallRTL(IL._set, 2); |
GetRegA |
|IL.opRSET1: |
PushAll(1); |
CallRTL(IL._set1, 1); |
GetRegA |
|IL.opCONSTF: |
MovConst(GetAnyReg(), UTILS.d2s(cmd.float)) |
|IL.opMULF: |
PushAll(2); |
CallRTL(IL._fmul, 2); |
GetRegA |
|IL.opDIVF: |
PushAll(2); |
CallRTL(IL._fdiv, 2); |
GetRegA |
|IL.opDIVFI: |
PushAll(2); |
CallRTL(IL._fdivi, 2); |
GetRegA |
|IL.opADDF: |
PushAll(2); |
CallRTL(IL._fadd, 2); |
GetRegA |
|IL.opSUBFI: |
PushAll(2); |
CallRTL(IL._fsubi, 2); |
GetRegA |
|IL.opSUBF: |
PushAll(2); |
CallRTL(IL._fsub, 2); |
GetRegA |
|IL.opEQF..IL.opGEF: |
PushAll(2); |
PushConst(opcode - IL.opEQF); |
CallRTL(IL._fcmp, 3); |
GetRegA |
|IL.opFLOOR: |
PushAll(1); |
CallRTL(IL._floor, 1); |
GetRegA |
|IL.opFLT: |
PushAll(1); |
CallRTL(IL._flt, 1); |
GetRegA |
|IL.opUMINF: |
UnOp(r1); |
r2 := GetAnyReg(); |
MovConst(r2, 1); |
LslImm(r2, 31); |
gen4(1, r2, r1); (* eors r1, r2 *) |
drop |
|IL.opFABS: |
UnOp(r1); |
r2 := GetAnyReg(); |
MovConst(r2, 1); |
LslImm(r2, 31); |
gen4(14, r2, r1); (* bics r1, r2 *) |
drop |
|IL.opNEW: |
cpsid_i; |
PushAll(1); |
n := param2 + 4; |
ASSERT(UTILS.Align(n, 4)); |
PushConst(n); |
PushConst(param1); |
CallRTL(IL._new, 3); |
cpsie_i |
|IL.opTYPEGP: |
UnOp(r1); |
PushAll(0); |
push(r1); |
PushConst(param2); |
CallRTL(IL._guard, 2); |
GetRegA |
|IL.opIS: |
PushAll(1); |
PushConst(param2); |
CallRTL(IL._is, 2); |
GetRegA |
|IL.opISREC: |
PushAll(2); |
PushConst(param2); |
CallRTL(IL._guardrec, 3); |
GetRegA |
|IL.opTYPEGR: |
PushAll(1); |
PushConst(param2); |
CallRTL(IL._guardrec, 2); |
GetRegA |
|IL.opTYPEGD: |
UnOp(r1); |
PushAll(0); |
SubImm8(r1, 4); |
Ldr32(r1, r1); |
push(r1); |
PushConst(param2); |
CallRTL(IL._guardrec, 2); |
GetRegA |
|IL.opCASET: |
push(R2); |
push(R2); |
PushConst(param2); |
CallRTL(IL._guardrec, 2); |
pop(R2); |
cbnz(ACC, param1) |
|IL.opROT: |
PushAll(0); |
mov(R2, SP); |
push(R2); |
PushConst(param2); |
CallRTL(IL._rot, 2) |
|IL.opPACK: |
PushAll(2); |
CallRTL(IL._pack, 2) |
|IL.opPACKC: |
PushAll(1); |
PushConst(param2); |
CallRTL(IL._pack, 2) |
|IL.opUNPK: |
PushAll(2); |
CallRTL(IL._unpk, 2) |
END; |
cmd := cmd.next(COMMAND) |
END; |
ASSERT(R.pushed = 0); |
ASSERT(R.top = -1) |
END translate; |
PROCEDURE prolog (GlobSize, tcount, pic, sp, ivt_len: INTEGER); |
VAR |
r1, r2, i, dcount: INTEGER; |
BEGIN |
entry := NewLabel(); |
emptyProc := NewLabel(); |
genInt := NewLabel(); |
genTrap := NewLabel(); |
sdivProc := NewLabel(); |
trap := emptyProc; |
int0 := emptyProc; |
IVT[0] := sp; |
IVT[1] := entry; |
FOR i := 2 TO ivt_len - 1 DO |
IVT[i] := genInt |
END; |
FOR i := 0 TO ivt_len - 1 DO |
Code(low(IVT[i])); |
Code(high(IVT[i])) |
END; |
Label(entry); |
cpsie_i; |
r1 := GetAnyReg(); |
r2 := GetAnyReg(); |
reloc(r1, BIN.RDATA + pic, 0); |
FOR i := 0 TO tcount - 1 DO |
MovConst(r2, CHL.GetInt(IL.codes.types, i)); |
Str32(r2, r1); |
AddImm8(r1, 4) |
END; |
dcount := CHL.Length(IL.codes.data); |
FOR i := 0 TO dcount - 1 BY 4 DO |
MovConst(r2, BIN.get32le(IL.codes.data, i)); |
Str32(r2, r1); |
AddImm8(r1, 4) |
END; |
drop; |
drop; |
r1 := GetAnyReg(); |
MovConst(r1, sp); |
mov(SP, r1); |
reloc(r1, BIN.RDATA + pic, 0); |
push(r1); |
reloc(r1, BIN.RBSS + pic, 0); |
r2 := GetAnyReg(); |
MovConst(r2, GlobSize); |
AddReg(r1, r1, r2); |
drop; |
push(r1); |
drop; |
PushConst(tcount); |
CallRTL(IL._init, 3) |
END prolog; |
PROCEDURE epilog; |
VAR |
L1, L2, L3, L4: INTEGER; |
BEGIN |
(* L2: *) |
Code(0E7FEH); (* b L2 *) |
Label(genInt); |
Code(0F3EFH); Code(08005H); (* mrs r0, ipsr *) |
gen14(FALSE, TRUE, {R0}); (* push {lr, r0} *) |
call(int0); |
gen14(TRUE, TRUE, {R0}); (* pop {pc, r0} *) |
Label(emptyProc); |
Code(04770H); (* bx lr *) |
Label(genTrap); |
call(trap); |
call(entry); |
Label(sdivProc); |
IF _SDIV IN Target.InstrSet THEN |
Code(09800H); (* ldr r0, [sp] *) |
Code(09901H); (* ldr r1, [sp, 4] *) |
Code(0FB91H); (* sdiv r2, r1, r0 *) |
Code(0F2F0H); |
Code(00013H); (* movs r3, r2 *) |
Code(04343H); (* muls r3, r0, r3 *) |
Code(01AC9H); (* subs r1, r1, r3 *) |
Code(0DA01H); (* bge L *) |
Code(01809H); (* adds r1, r1, r0 *) |
Code(03A01H); (* subs r2, 1 *) |
(* L: *) |
Code(00010H); (* movs r0, r2 *) |
Code(04770H); (* bx lr *) |
ELSE |
(* a / b; a >= 0 *) |
L1 := NewLabel(); |
L2 := NewLabel(); |
L3 := NewLabel(); |
L4 := NewLabel(); |
LdrSp(R1, 1); |
LdrSp(R2, 0); |
MovConst(R0, 0); |
push(R4); |
Label(L4); |
Cmp(R1, R2); |
jcc(jl, L1); |
MovConst(R3, 2); |
mov(R4, R2); |
LslImm(R4, 1); |
Label(L3); |
Cmp(R1, R4); |
jcc(jl, L2); |
CmpConst(R4, 0); |
jcc(jle, L2); |
LslImm(R4, 1); |
LslImm(R3, 1); |
jmp(L3); |
Label(L2); |
LsrImm(R4, 1); |
LsrImm(R3, 1); |
SubReg(R1, R1, R4); |
AddReg(R0, R0, R3); |
jmp(L4); |
Label(L1); |
(* a / b; a < 0 *) |
L1 := NewLabel(); |
L2 := NewLabel(); |
L3 := NewLabel(); |
L4 := NewLabel(); |
Label(L4); |
CmpConst(R1, 0); |
jcc(jge, L1); |
MovConst(R3, 2); |
mov(R4, R2); |
LslImm(R4, 1); |
Neg(R1); |
Label(L3); |
Cmp(R1, R4); |
jcc(jl, L2); |
CmpConst(R4, 0); |
jcc(jle, L2); |
LslImm(R4, 1); |
LslImm(R3, 1); |
jmp(L3); |
Label(L2); |
Neg(R1); |
LsrImm(R4, 1); |
LsrImm(R3, 1); |
AddReg(R1, R1, R4); |
SubReg(R0, R0, R3); |
jmp(L4); |
Label(L1); |
pop(R4); |
Code(04770H); (* bx lr *) |
END |
END epilog; |
PROCEDURE SetTarget (FlashStart, SRAMStart: INTEGER; InstrSet: SET; isNXP: BOOLEAN); |
BEGIN |
Target.FlashAdr := FlashStart; |
Target.SRAMAdr := SRAMStart; |
Target.InstrSet := InstrSet; |
Target.isNXP := isNXP; |
Target.IVTLen := 256; (* >= 192 *) |
Target.Reserved := 0; |
Target.MinStack := 512; |
END SetTarget; |
PROCEDURE CodeGen* (outname: ARRAY OF CHAR; target: INTEGER; options: PROG.OPTIONS); |
VAR |
opt: PROG.OPTIONS; |
ram, rom, i, j: INTEGER; |
DataAdr, BssAdr, DataSize, BssSize, CodeSize: INTEGER; |
BEGIN |
ram := MIN(MAX(options.ram, minRAM), maxRAM) * 1024; |
rom := MIN(MAX(options.rom, minROM), maxROM) * 1024; |
IF target = TARGETS.STM32CM3 THEN |
SetTarget(08000000H, 20000000H, CortexM3, FALSE) |
END; |
tcount := CHL.Length(IL.codes.types); |
opt := options; |
CodeList := LISTS.create(NIL); |
program := BIN.create(IL.codes.lcount); |
REG.Init(R, push, pop, mov, xchg, {R0, R1, R2, R3}); |
StkCount := 0; |
DataAdr := Target.SRAMAdr + Target.Reserved; |
DataSize := CHL.Length(IL.codes.data) + tcount * 4 + Target.Reserved; |
WHILE DataSize MOD 4 # 0 DO |
CHL.PushByte(IL.codes.data, 0); |
INC(DataSize) |
END; |
BssAdr := DataAdr + DataSize - Target.Reserved; |
IL.set_bss(MAX(IL.codes.bss, MAX(IL.codes.dmin - CHL.Length(IL.codes.data), 4))); |
BssSize := IL.codes.bss; |
ASSERT(UTILS.Align(BssSize, 4)); |
prolog(BssSize, tcount, ORD(opt.pic), Target.SRAMAdr + ram, Target.IVTLen); |
translate(ORD(opt.pic), tcount * 4); |
epilog; |
fixup(Target.FlashAdr, DataAdr, BssAdr); |
INC(DataSize, BssSize); |
CodeSize := CHL.Length(program.code); |
IF CodeSize > rom THEN |
ERRORS.Error(203) |
END; |
IF DataSize > ram - Target.MinStack THEN |
ERRORS.Error(204) |
END; |
IF Target.isNXP THEN |
BIN.put32le(program.code, 2FCH, 0H); (* code read protection (CRP) *) |
(* NXP checksum *) |
j := 0; |
FOR i := 0 TO 6 DO |
INC(j, BIN.get32le(program.code, i * 4)) |
END; |
BIN.put32le(program.code, 1CH, -j) |
END; |
WR.Create(outname); |
HEX.Data2(program.code, 0, CodeSize, high(Target.FlashAdr)); |
HEX.End; |
WR.Close; |
C.Dashes; |
C.String( " rom: "); C.Int(CodeSize); C.String(" of "); C.Int(rom); C.String(" ("); C.Int(CodeSize * 100 DIV rom); C.StringLn("%)"); |
C.Ln; |
C.String( " ram: "); C.Int(DataSize); C.String(" of "); C.Int(ram); C.String(" ("); C.Int(DataSize * 100 DIV ram); C.StringLn("%)") |
END CodeGen; |
PROCEDURE SetIV* (idx: INTEGER): BOOLEAN; |
VAR |
res: BOOLEAN; |
BEGIN |
res := IVT[idx] = 0; |
IVT[idx] := 1 |
RETURN res |
END SetIV; |
PROCEDURE init; |
VAR |
i: INTEGER; |
BEGIN |
FOR i := 0 TO LEN(IVT) - 1 DO |
IVT[i] := 0 |
END |
END init; |
BEGIN |
init |
END THUMB. |
/programs/develop/oberon07/source/UTILS.ob07 |
---|
0,0 → 1,216 |
(* |
BSD 2-Clause License |
Copyright (c) 2018-2021, Anton Krotov |
All rights reserved. |
*) |
MODULE UTILS; |
IMPORT HOST; |
CONST |
slash* = HOST.slash; |
eol* = HOST.eol; |
bit_depth* = HOST.bit_depth; |
maxint* = HOST.maxint; |
minint* = HOST.minint; |
min32* = -2147483647-1; |
max32* = 2147483647; |
vMajor* = 1; |
vMinor* = 52; |
Date* = "07-may-2021"; |
FILE_EXT* = ".ob07"; |
RTL_NAME* = "RTL"; |
MAX_GLOBAL_SIZE* = 1600000000; |
VAR |
time*: INTEGER; |
maxreal*: REAL; |
target*: |
RECORD |
bit_depth*, |
maxInt*, |
minInt*, |
maxSet*, |
maxHex*: INTEGER; |
maxReal*: REAL |
END; |
bit_diff*: INTEGER; |
PROCEDURE FileRead* (F: INTEGER; VAR Buffer: ARRAY OF CHAR; bytes: INTEGER): INTEGER; |
RETURN HOST.FileRead(F, Buffer, bytes) |
END FileRead; |
PROCEDURE FileWrite* (F: INTEGER; Buffer: ARRAY OF BYTE; bytes: INTEGER): INTEGER; |
RETURN HOST.FileWrite(F, Buffer, bytes) |
END FileWrite; |
PROCEDURE FileCreate* (FName: ARRAY OF CHAR): INTEGER; |
RETURN HOST.FileCreate(FName) |
END FileCreate; |
PROCEDURE FileClose* (F: INTEGER); |
BEGIN |
HOST.FileClose(F) |
END FileClose; |
PROCEDURE FileOpen* (FName: ARRAY OF CHAR): INTEGER; |
RETURN HOST.FileOpen(FName) |
END FileOpen; |
PROCEDURE chmod* (FName: ARRAY OF CHAR); |
BEGIN |
HOST.chmod(FName) |
END chmod; |
PROCEDURE GetArg* (i: INTEGER; VAR str: ARRAY OF CHAR); |
BEGIN |
HOST.GetArg(i, str) |
END GetArg; |
PROCEDURE Exit* (code: INTEGER); |
BEGIN |
HOST.ExitProcess(code) |
END Exit; |
PROCEDURE GetTickCount* (): INTEGER; |
RETURN HOST.GetTickCount() |
END GetTickCount; |
PROCEDURE OutChar* (c: CHAR); |
BEGIN |
HOST.OutChar(c) |
END OutChar; |
PROCEDURE splitf* (x: REAL; VAR a, b: INTEGER): INTEGER; |
RETURN HOST.splitf(x, a, b) |
END splitf; |
PROCEDURE d2s* (x: REAL): INTEGER; |
RETURN HOST.d2s(x) |
END d2s; |
PROCEDURE isRelative* (path: ARRAY OF CHAR): BOOLEAN; |
RETURN HOST.isRelative(path) |
END isRelative; |
PROCEDURE GetCurrentDirectory* (VAR path: ARRAY OF CHAR); |
BEGIN |
HOST.GetCurrentDirectory(path) |
END GetCurrentDirectory; |
PROCEDURE UnixTime* (): INTEGER; |
RETURN HOST.UnixTime() |
END UnixTime; |
PROCEDURE SetBitDepth* (BitDepth: INTEGER; Double: BOOLEAN); |
BEGIN |
ASSERT((BitDepth = 16) OR (BitDepth = 32) OR (BitDepth = 64)); |
bit_diff := bit_depth - BitDepth; |
ASSERT(bit_diff >= 0); |
target.bit_depth := BitDepth; |
target.maxSet := BitDepth - 1; |
target.maxHex := BitDepth DIV 4; |
target.minInt := ASR(minint, bit_diff); |
target.maxInt := ASR(maxint, bit_diff); |
IF Double THEN |
target.maxReal := maxreal |
ELSE |
target.maxReal := 1.9; |
PACK(target.maxReal, 127) |
END |
END SetBitDepth; |
PROCEDURE Byte* (n: INTEGER; idx: INTEGER): BYTE; |
RETURN ASR(n, 8 * idx) MOD 256 |
END Byte; |
PROCEDURE Align* (VAR bytes: INTEGER; align: INTEGER): BOOLEAN; |
BEGIN |
INC(bytes, (-bytes) MOD align) |
RETURN bytes >= 0 |
END Align; |
PROCEDURE Long* (value: INTEGER): INTEGER; |
RETURN ASR(LSL(value, bit_diff), bit_diff) |
END Long; |
PROCEDURE Short* (value: INTEGER): INTEGER; |
RETURN LSR(LSL(value, bit_diff), bit_diff) |
END Short; |
PROCEDURE Log2* (x: INTEGER): INTEGER; |
VAR |
n: INTEGER; |
BEGIN |
n := 0; |
WHILE ~ODD(x) DO |
x := x DIV 2; |
INC(n) |
END; |
IF x # 1 THEN |
n := -1 |
END |
RETURN n |
END Log2; |
PROCEDURE hexdgt* (n: BYTE): BYTE; |
BEGIN |
IF n < 10 THEN |
INC(n, ORD("0")) |
ELSE |
INC(n, ORD("A") - 10) |
END |
RETURN n |
END hexdgt; |
BEGIN |
time := HOST.GetTickCount(); |
maxreal := HOST.maxreal |
END UTILS. |
/programs/develop/oberon07/source/WRITER.ob07 |
---|
0,0 → 1,104 |
(* |
BSD 2-Clause License |
Copyright (c) 2018-2021, Anton Krotov |
All rights reserved. |
*) |
MODULE WRITER; |
IMPORT FILES, ERRORS, UTILS; |
VAR |
counter*: INTEGER; |
file: FILES.FILE; |
PROCEDURE align* (n, _align: INTEGER): INTEGER; |
BEGIN |
ASSERT(UTILS.Align(n, _align)) |
RETURN n |
END align; |
PROCEDURE WriteByte* (n: BYTE); |
BEGIN |
IF FILES.WriteByte(file, n) THEN |
INC(counter) |
ELSE |
ERRORS.Error(201) |
END |
END WriteByte; |
PROCEDURE Write* (chunk: ARRAY OF BYTE; bytes: INTEGER); |
VAR |
n: INTEGER; |
BEGIN |
n := FILES.write(file, chunk, bytes); |
IF n # bytes THEN |
ERRORS.Error(201) |
END; |
INC(counter, n) |
END Write; |
PROCEDURE Write64LE* (n: INTEGER); |
VAR |
i: INTEGER; |
BEGIN |
FOR i := 0 TO 7 DO |
WriteByte(UTILS.Byte(n, i)) |
END |
END Write64LE; |
PROCEDURE Write32LE* (n: INTEGER); |
VAR |
i: INTEGER; |
BEGIN |
FOR i := 0 TO 3 DO |
WriteByte(UTILS.Byte(n, i)) |
END |
END Write32LE; |
PROCEDURE Write16LE* (n: INTEGER); |
BEGIN |
WriteByte(UTILS.Byte(n, 0)); |
WriteByte(UTILS.Byte(n, 1)) |
END Write16LE; |
PROCEDURE Padding* (FileAlignment: INTEGER); |
VAR |
i: INTEGER; |
BEGIN |
i := align(counter, FileAlignment) - counter; |
WHILE i > 0 DO |
WriteByte(0); |
DEC(i) |
END |
END Padding; |
PROCEDURE Create* (FileName: ARRAY OF CHAR); |
BEGIN |
counter := 0; |
file := FILES.create(FileName) |
END Create; |
PROCEDURE Close*; |
BEGIN |
FILES.close(file) |
END Close; |
END WRITER. |
/programs/develop/oberon07/source/X86.ob07 |
---|
0,0 → 1,2403 |
(* |
BSD 2-Clause License |
Copyright (c) 2018-2021, Anton Krotov |
All rights reserved. |
*) |
MODULE X86; |
IMPORT IL, REG, UTILS, LISTS, BIN, PE32, KOS, MSCOFF, ELF, PROG, |
CHL := CHUNKLISTS, PATHS, TARGETS, ERRORS; |
CONST |
eax = REG.R0; ecx = REG.R1; edx = REG.R2; |
al = eax; cl = ecx; dl = edx; ah = 4; |
ax = eax; cx = ecx; dx = edx; |
esp = 4; |
ebp = 5; |
MAX_FR = 7; |
sete = 94H; setne = 95H; setl = 9CH; setge = 9DH; setle = 9EH; setg = 9FH; setc = 92H; setnc = 93H; |
je = 84H; jne = 85H; jl = 8CH; jge = 8DH; jle = 8EH; jg = 8FH; jb = 82H; jnb = 83H; |
CODECHUNK = 8; |
FPR_ERR = 41; |
TYPE |
COMMAND = IL.COMMAND; |
ANYCODE = POINTER TO RECORD (LISTS.ITEM) |
offset: INTEGER |
END; |
CODE = POINTER TO RECORD (ANYCODE) |
code: ARRAY CODECHUNK OF BYTE; |
length: INTEGER |
END; |
LABEL = POINTER TO RECORD (ANYCODE) |
label: INTEGER |
END; |
JUMP = POINTER TO RECORD (ANYCODE) |
label, diff: INTEGER; |
short: BOOLEAN |
END; |
JMP = POINTER TO RECORD (JUMP) |
END; |
JCC = POINTER TO RECORD (JUMP) |
jmp: INTEGER |
END; |
CALL = POINTER TO RECORD (JUMP) |
END; |
RELOC = POINTER TO RECORD (ANYCODE) |
op, value: INTEGER |
END; |
VAR |
R: REG.REGS; |
program: BIN.PROGRAM; |
CodeList: LISTS.LIST; |
tcount: INTEGER; |
FR: ARRAY 1000 OF INTEGER; |
fname: PATHS.PATH; |
PROCEDURE OutByte* (n: BYTE); |
VAR |
c: CODE; |
last: ANYCODE; |
BEGIN |
last := CodeList.last(ANYCODE); |
IF (last IS CODE) & (last(CODE).length < CODECHUNK) THEN |
c := last(CODE); |
c.code[c.length] := n; |
INC(c.length) |
ELSE |
NEW(c); |
c.code[0] := n; |
c.length := 1; |
LISTS.push(CodeList, c) |
END |
END OutByte; |
PROCEDURE OutInt (n: INTEGER); |
BEGIN |
OutByte(n MOD 256); |
OutByte(UTILS.Byte(n, 1)); |
OutByte(UTILS.Byte(n, 2)); |
OutByte(UTILS.Byte(n, 3)) |
END OutInt; |
PROCEDURE OutByte2 (a, b: BYTE); |
BEGIN |
OutByte(a); |
OutByte(b) |
END OutByte2; |
PROCEDURE OutByte3 (a, b, c: BYTE); |
BEGIN |
OutByte(a); |
OutByte(b); |
OutByte(c) |
END OutByte3; |
PROCEDURE OutWord (n: INTEGER); |
BEGIN |
ASSERT((0 <= n) & (n <= 65535)); |
OutByte2(n MOD 256, n DIV 256) |
END OutWord; |
PROCEDURE isByte* (n: INTEGER): BOOLEAN; |
RETURN (-128 <= n) & (n <= 127) |
END isByte; |
PROCEDURE short (n: INTEGER): INTEGER; |
RETURN 2 * ORD(isByte(n)) |
END short; |
PROCEDURE long (n: INTEGER): INTEGER; |
RETURN 40H * ORD(~isByte(n)) |
END long; |
PROCEDURE OutIntByte (n: INTEGER); |
BEGIN |
IF isByte(n) THEN |
OutByte(n MOD 256) |
ELSE |
OutInt(n) |
END |
END OutIntByte; |
PROCEDURE shift* (op, reg: INTEGER); |
BEGIN |
CASE op OF |
|IL.opASR, IL.opASR1, IL.opASR2: OutByte(0F8H + reg) |
|IL.opROR, IL.opROR1, IL.opROR2: OutByte(0C8H + reg) |
|IL.opLSL, IL.opLSL1, IL.opLSL2: OutByte(0E0H + reg) |
|IL.opLSR, IL.opLSR1, IL.opLSR2: OutByte(0E8H + reg) |
END |
END shift; |
PROCEDURE oprr (op: BYTE; reg1, reg2: INTEGER); (* op reg1, reg2 *) |
BEGIN |
OutByte2(op, 0C0H + 8 * reg2 + reg1) |
END oprr; |
PROCEDURE mov (reg1, reg2: INTEGER); (* mov reg1, reg2 *) |
BEGIN |
oprr(89H, reg1, reg2) |
END mov; |
PROCEDURE xchg (reg1, reg2: INTEGER); (* xchg reg1, reg2 *) |
BEGIN |
IF eax IN {reg1, reg2} THEN |
OutByte(90H + reg1 + reg2) |
ELSE |
oprr(87H, reg1, reg2) |
END |
END xchg; |
PROCEDURE pop (reg: INTEGER); |
BEGIN |
OutByte(58H + reg) (* pop reg *) |
END pop; |
PROCEDURE push (reg: INTEGER); |
BEGIN |
OutByte(50H + reg) (* push reg *) |
END push; |
PROCEDURE xor (reg1, reg2: INTEGER); (* xor reg1, reg2 *) |
BEGIN |
oprr(31H, reg1, reg2) |
END xor; |
PROCEDURE movrc (reg, n: INTEGER); |
BEGIN |
IF n = 0 THEN |
xor(reg, reg) |
ELSE |
OutByte(0B8H + reg); (* mov reg, n *) |
OutInt(n) |
END |
END movrc; |
PROCEDURE pushc* (n: INTEGER); |
BEGIN |
OutByte(68H + short(n)); (* push n *) |
OutIntByte(n) |
END pushc; |
PROCEDURE test (reg: INTEGER); |
BEGIN |
OutByte2(85H, 0C0H + reg * 9) (* test reg, reg *) |
END test; |
PROCEDURE neg (reg: INTEGER); |
BEGIN |
OutByte2(0F7H, 0D8H + reg) (* neg reg *) |
END neg; |
PROCEDURE not (reg: INTEGER); |
BEGIN |
OutByte2(0F7H, 0D0H + reg) (* not reg *) |
END not; |
PROCEDURE add (reg1, reg2: INTEGER); (* add reg1, reg2 *) |
BEGIN |
oprr(01H, reg1, reg2) |
END add; |
PROCEDURE oprc* (op, reg, n: INTEGER); |
BEGIN |
IF (reg = eax) & ~isByte(n) THEN |
CASE op OF |
|0C0H: op := 05H (* add *) |
|0E8H: op := 2DH (* sub *) |
|0F8H: op := 3DH (* cmp *) |
|0E0H: op := 25H (* and *) |
|0C8H: op := 0DH (* or *) |
|0F0H: op := 35H (* xor *) |
END; |
OutByte(op); |
OutInt(n) |
ELSE |
OutByte2(81H + short(n), op + reg MOD 8); |
OutIntByte(n) |
END |
END oprc; |
PROCEDURE andrc (reg, n: INTEGER); (* and reg, n *) |
BEGIN |
oprc(0E0H, reg, n) |
END andrc; |
PROCEDURE orrc (reg, n: INTEGER); (* or reg, n *) |
BEGIN |
oprc(0C8H, reg, n) |
END orrc; |
PROCEDURE xorrc (reg, n: INTEGER); (* xor reg, n *) |
BEGIN |
oprc(0F0H, reg, n) |
END xorrc; |
PROCEDURE addrc (reg, n: INTEGER); (* add reg, n *) |
BEGIN |
oprc(0C0H, reg, n) |
END addrc; |
PROCEDURE subrc (reg, n: INTEGER); (* sub reg, n *) |
BEGIN |
oprc(0E8H, reg, n) |
END subrc; |
PROCEDURE cmprc (reg, n: INTEGER); (* cmp reg, n *) |
BEGIN |
IF n = 0 THEN |
test(reg) |
ELSE |
oprc(0F8H, reg, n) |
END |
END cmprc; |
PROCEDURE cmprr (reg1, reg2: INTEGER); (* cmp reg1, reg2 *) |
BEGIN |
oprr(39H, reg1, reg2) |
END cmprr; |
PROCEDURE setcc* (cc, reg: INTEGER); (* setcc reg *) |
BEGIN |
IF reg >= 8 THEN |
OutByte(41H) |
END; |
OutByte3(0FH, cc, 0C0H + reg MOD 8) |
END setcc; |
PROCEDURE ret*; |
BEGIN |
OutByte(0C3H) |
END ret; |
PROCEDURE drop; |
BEGIN |
REG.Drop(R) |
END drop; |
PROCEDURE GetAnyReg (): INTEGER; |
RETURN REG.GetAnyReg(R) |
END GetAnyReg; |
PROCEDURE cond* (op: INTEGER): INTEGER; |
VAR |
res: INTEGER; |
BEGIN |
CASE op OF |
|IL.opGT, IL.opGTC: res := jg |
|IL.opGE, IL.opGEC: res := jge |
|IL.opLT, IL.opLTC: res := jl |
|IL.opLE, IL.opLEC: res := jle |
|IL.opEQ, IL.opEQC: res := je |
|IL.opNE, IL.opNEC: res := jne |
END |
RETURN res |
END cond; |
PROCEDURE inv0* (op: INTEGER): INTEGER; |
RETURN ORD(BITS(op) / {0}) |
END inv0; |
PROCEDURE Reloc* (op, value: INTEGER); |
VAR |
reloc: RELOC; |
BEGIN |
NEW(reloc); |
reloc.op := op; |
reloc.value := value; |
LISTS.push(CodeList, reloc) |
END Reloc; |
PROCEDURE jcc* (cc, label: INTEGER); |
VAR |
j: JCC; |
BEGIN |
NEW(j); |
j.label := label; |
j.jmp := cc; |
j.short := FALSE; |
LISTS.push(CodeList, j) |
END jcc; |
PROCEDURE jmp* (label: INTEGER); |
VAR |
j: JMP; |
BEGIN |
NEW(j); |
j.label := label; |
j.short := FALSE; |
LISTS.push(CodeList, j) |
END jmp; |
PROCEDURE call* (label: INTEGER); |
VAR |
c: CALL; |
BEGIN |
NEW(c); |
c.label := label; |
c.short := TRUE; |
LISTS.push(CodeList, c) |
END call; |
PROCEDURE Pic (reg, opcode, value: INTEGER); |
BEGIN |
OutByte(0E8H); OutInt(0); (* call L |
L: *) |
pop(reg); |
OutByte2(081H, 0C0H + reg); (* add reg, ... *) |
Reloc(opcode, value) |
END Pic; |
PROCEDURE CallRTL (pic: BOOLEAN; proc: INTEGER); |
VAR |
label: INTEGER; |
reg1: INTEGER; |
BEGIN |
label := IL.codes.rtl[proc]; |
IF label < 0 THEN |
label := -label; |
IF pic THEN |
reg1 := GetAnyReg(); |
Pic(reg1, BIN.PICIMP, label); |
OutByte2(0FFH, 010H + reg1); (* call dword[reg1] *) |
drop |
ELSE |
OutByte2(0FFH, 015H); (* call dword[label] *) |
Reloc(BIN.RIMP, label) |
END |
ELSE |
call(label) |
END |
END CallRTL; |
PROCEDURE SetLabel* (label: INTEGER); |
VAR |
L: LABEL; |
BEGIN |
NEW(L); |
L.label := label; |
LISTS.push(CodeList, L) |
END SetLabel; |
PROCEDURE fixup*; |
VAR |
code: ANYCODE; |
count, i: INTEGER; |
shorted: BOOLEAN; |
jump: JUMP; |
BEGIN |
REPEAT |
shorted := FALSE; |
count := 0; |
code := CodeList.first(ANYCODE); |
WHILE code # NIL DO |
code.offset := count; |
CASE code OF |
|CODE: INC(count, code.length) |
|LABEL: BIN.SetLabel(program, code.label, count) |
|JMP: IF code.short THEN INC(count, 2) ELSE INC(count, 5) END; code.offset := count |
|JCC: IF code.short THEN INC(count, 2) ELSE INC(count, 6) END; code.offset := count |
|CALL: INC(count, 5); code.offset := count |
|RELOC: INC(count, 4) |
END; |
code := code.next(ANYCODE) |
END; |
code := CodeList.first(ANYCODE); |
WHILE code # NIL DO |
IF code IS JUMP THEN |
jump := code(JUMP); |
jump.diff := BIN.GetLabel(program, jump.label) - code.offset; |
IF ~jump.short & isByte(jump.diff) THEN |
jump.short := TRUE; |
shorted := TRUE |
END |
END; |
code := code.next(ANYCODE) |
END |
UNTIL ~shorted; |
code := CodeList.first(ANYCODE); |
WHILE code # NIL DO |
CASE code OF |
|CODE: |
FOR i := 0 TO code.length - 1 DO |
BIN.PutCode(program, code.code[i]) |
END |
|LABEL: |
|JMP: |
IF code.short THEN |
BIN.PutCode(program, 0EBH); |
BIN.PutCode(program, code.diff MOD 256) |
ELSE |
BIN.PutCode(program, 0E9H); |
BIN.PutCode32LE(program, code.diff) |
END |
|JCC: |
IF code.short THEN |
BIN.PutCode(program, code.jmp - 16); |
BIN.PutCode(program, code.diff MOD 256) |
ELSE |
BIN.PutCode(program, 0FH); |
BIN.PutCode(program, code.jmp); |
BIN.PutCode32LE(program, code.diff) |
END |
|CALL: |
BIN.PutCode(program, 0E8H); |
BIN.PutCode32LE(program, code.diff) |
|RELOC: |
BIN.PutReloc(program, code.op); |
BIN.PutCode32LE(program, code.value) |
END; |
code := code.next(ANYCODE) |
END |
END fixup; |
PROCEDURE UnOp (VAR reg: INTEGER); |
BEGIN |
REG.UnOp(R, reg) |
END UnOp; |
PROCEDURE BinOp (VAR reg1, reg2: INTEGER); |
BEGIN |
REG.BinOp(R, reg1, reg2) |
END BinOp; |
PROCEDURE PushAll (NumberOfParameters: INTEGER); |
BEGIN |
REG.PushAll(R); |
DEC(R.pushed, NumberOfParameters) |
END PushAll; |
PROCEDURE NewLabel (): INTEGER; |
BEGIN |
BIN.NewLabel(program) |
RETURN IL.NewLabel() |
END NewLabel; |
PROCEDURE GetRegA; |
BEGIN |
ASSERT(REG.GetReg(R, eax)) |
END GetRegA; |
PROCEDURE fcmp; |
BEGIN |
GetRegA; |
OutByte2(0DAH, 0E9H); (* fucompp *) |
OutByte3(09BH, 0DFH, 0E0H); (* fstsw ax *) |
OutByte(09EH); (* sahf *) |
OutByte(0B8H); OutInt(0) (* mov eax, 0 *) |
END fcmp; |
PROCEDURE movzx* (reg1, reg2, offs: INTEGER; word: BOOLEAN); (* movzx reg1, byte/word[reg2 + offs] *) |
VAR |
b: BYTE; |
BEGIN |
OutByte2(0FH, 0B6H + ORD(word)); |
IF (offs = 0) & (reg2 # ebp) THEN |
b := 0 |
ELSE |
b := 40H + long(offs) |
END; |
OutByte(b + (reg1 MOD 8) * 8 + reg2 MOD 8); |
IF reg2 = esp THEN |
OutByte(24H) |
END; |
IF b # 0 THEN |
OutIntByte(offs) |
END |
END movzx; |
PROCEDURE _movrm* (reg1, reg2, offs, size: INTEGER; mr: BOOLEAN); |
VAR |
b: BYTE; |
BEGIN |
IF size = 16 THEN |
OutByte(66H) |
END; |
IF (reg1 >= 8) OR (reg2 >= 8) OR (size = 64) THEN |
OutByte(40H + reg2 DIV 8 + 4 * (reg1 DIV 8) + 8 * ORD(size = 64)) |
END; |
OutByte(8BH - 2 * ORD(mr) - ORD(size = 8)); |
IF (offs = 0) & (reg2 # ebp) THEN |
b := 0 |
ELSE |
b := 40H + long(offs) |
END; |
OutByte(b + (reg1 MOD 8) * 8 + reg2 MOD 8); |
IF reg2 = esp THEN |
OutByte(24H) |
END; |
IF b # 0 THEN |
OutIntByte(offs) |
END |
END _movrm; |
PROCEDURE movmr (reg1, offs, reg2: INTEGER); (* mov dword[reg1+offs], reg2_8 *) |
BEGIN |
_movrm(reg2, reg1, offs, 32, TRUE) |
END movmr; |
PROCEDURE movrm (reg1, reg2, offs: INTEGER); (* mov reg1, dword[reg2 + offs] *) |
BEGIN |
_movrm(reg1, reg2, offs, 32, FALSE) |
END movrm; |
PROCEDURE movmr8* (reg1, offs, reg2: INTEGER); (* mov byte[reg1+offs], reg2_8 *) |
BEGIN |
_movrm(reg2, reg1, offs, 8, TRUE) |
END movmr8; |
PROCEDURE movrm8* (reg1, reg2, offs: INTEGER); (* mov reg1_8, byte[reg2+offs] *) |
BEGIN |
_movrm(reg1, reg2, offs, 8, FALSE) |
END movrm8; |
PROCEDURE movmr16* (reg1, offs, reg2: INTEGER); (* mov word[reg1+offs], reg2_16 *) |
BEGIN |
_movrm(reg2, reg1, offs, 16, TRUE) |
END movmr16; |
PROCEDURE movrm16* (reg1, reg2, offs: INTEGER); (* mov reg1_16, word[reg2+offs] *) |
BEGIN |
_movrm(reg1, reg2, offs, 16, FALSE) |
END movrm16; |
PROCEDURE pushm* (reg, offs: INTEGER); (* push qword[reg+offs] *) |
VAR |
b: BYTE; |
BEGIN |
IF reg >= 8 THEN |
OutByte(41H) |
END; |
OutByte(0FFH); |
IF (offs = 0) & (reg # ebp) THEN |
b := 30H |
ELSE |
b := 70H + long(offs) |
END; |
OutByte(b + reg MOD 8); |
IF reg = esp THEN |
OutByte(24H) |
END; |
IF b # 30H THEN |
OutIntByte(offs) |
END |
END pushm; |
PROCEDURE translate (pic: BOOLEAN; stroffs: INTEGER); |
VAR |
cmd, next: COMMAND; |
reg1, reg2, fr: INTEGER; |
n, a, b, label, cc: INTEGER; |
opcode, param1, param2: INTEGER; |
float: REAL; |
BEGIN |
cmd := IL.codes.commands.first(COMMAND); |
fr := -1; |
WHILE cmd # NIL DO |
param1 := cmd.param1; |
param2 := cmd.param2; |
opcode := cmd.opcode; |
CASE opcode OF |
|IL.opJMP: |
jmp(param1) |
|IL.opCALL: |
call(param1) |
|IL.opCALLI: |
IF pic THEN |
reg1 := GetAnyReg(); |
Pic(reg1, BIN.PICIMP, param1); |
OutByte2(0FFH, 010H + reg1); (* call dword[reg1] *) |
drop |
ELSE |
OutByte2(0FFH, 015H); (* call dword[L] *) |
Reloc(BIN.RIMP, param1) |
END |
|IL.opCALLP: |
UnOp(reg1); |
OutByte2(0FFH, 0D0H + reg1); (* call reg1 *) |
drop; |
ASSERT(R.top = -1) |
|IL.opPRECALL: |
PushAll(0); |
IF (param2 # 0) & (fr >= 0) THEN |
subrc(esp, 8) |
END; |
INC(FR[0]); |
FR[FR[0]] := fr + 1; |
WHILE fr >= 0 DO |
subrc(esp, 8); |
OutByte3(0DDH, 01CH, 024H); (* fstp qword[esp] *) |
DEC(fr) |
END; |
ASSERT(fr = -1) |
|IL.opALIGN16: |
ASSERT(eax IN R.regs); |
mov(eax, esp); |
andrc(esp, -16); |
n := (3 - param2 MOD 4) * 4; |
IF n > 0 THEN |
subrc(esp, n) |
END; |
push(eax) |
|IL.opRESF, IL.opRES: |
ASSERT(R.top = -1); |
ASSERT(fr = -1); |
n := FR[FR[0]]; DEC(FR[0]); |
IF opcode = IL.opRESF THEN |
INC(fr); |
IF n > 0 THEN |
OutByte3(0DDH, 5CH + long(n * 8), 24H); |
OutIntByte(n * 8); (* fstp qword[esp + n*8] *) |
DEC(fr); |
INC(n) |
END; |
IF fr + n > MAX_FR THEN |
ERRORS.ErrorMsg(fname, param1, param2, FPR_ERR) |
END |
ELSE |
GetRegA |
END; |
WHILE n > 0 DO |
OutByte3(0DDH, 004H, 024H); (* fld qword[esp] *) |
addrc(esp, 8); |
INC(fr); |
DEC(n) |
END |
|IL.opENTER: |
ASSERT(R.top = -1); |
SetLabel(param1); |
push(ebp); |
mov(ebp, esp); |
n := param2; |
IF n > 4 THEN |
movrc(ecx, n); |
pushc(0); (* L: push 0 *) |
OutByte2(0E2H, 0FCH) (* loop L *) |
ELSE |
WHILE n > 0 DO |
pushc(0); |
DEC(n) |
END |
END |
|IL.opLEAVE, IL.opLEAVER, IL.opLEAVEF: |
IF opcode = IL.opLEAVER THEN |
UnOp(reg1); |
IF reg1 # eax THEN |
mov(eax, reg1) |
END; |
drop |
END; |
ASSERT(R.top = -1); |
IF opcode = IL.opLEAVEF THEN |
DEC(fr) |
END; |
ASSERT(fr = -1); |
IF param1 > 0 THEN |
mov(esp, ebp) |
END; |
pop(ebp); |
IF param2 > 0 THEN |
OutByte(0C2H); OutWord(param2 * 4 MOD 65536) (* ret param2*4 *) |
ELSE |
ret |
END |
|IL.opPUSHC: |
pushc(param2) |
|IL.opONERR: |
pushc(param2); |
jmp(param1) |
|IL.opPARAM: |
n := param2; |
IF n = 1 THEN |
UnOp(reg1); |
push(reg1); |
drop |
ELSE |
ASSERT(R.top + 1 <= n); |
PushAll(n) |
END |
|IL.opCLEANUP: |
IF param2 # 0 THEN |
addrc(esp, param2 * 4) |
END |
|IL.opPOPSP: |
pop(esp) |
|IL.opCONST: |
movrc(GetAnyReg(), param2) |
|IL.opLABEL: |
SetLabel(param1) (* L: *) |
|IL.opNOP, IL.opAND, IL.opOR: |
|IL.opGADR: |
next := cmd.next(COMMAND); |
IF next.opcode = IL.opADDC THEN |
INC(param2, next.param2); |
cmd := next |
END; |
reg1 := GetAnyReg(); |
IF pic THEN |
Pic(reg1, BIN.PICBSS, param2) |
ELSE |
OutByte(0B8H + reg1); (* mov reg1, _bss + param2 *) |
Reloc(BIN.RBSS, param2) |
END |
|IL.opLADR: |
next := cmd.next(COMMAND); |
n := param2 * 4; |
IF next.opcode = IL.opADDC THEN |
INC(n, next.param2); |
cmd := next |
END; |
OutByte2(8DH, 45H + GetAnyReg() * 8 + long(n)); (* lea reg1, dword[ebp + n] *) |
OutIntByte(n) |
|IL.opVADR, IL.opLLOAD32: |
movrm(GetAnyReg(), ebp, param2 * 4) |
|IL.opSADR: |
reg1 := GetAnyReg(); |
IF pic THEN |
Pic(reg1, BIN.PICDATA, stroffs + param2); |
ELSE |
OutByte(0B8H + reg1); (* mov reg1, _data + stroffs + param2 *) |
Reloc(BIN.RDATA, stroffs + param2) |
END |
|IL.opSAVEC: |
UnOp(reg1); |
OutByte2(0C7H, reg1); OutInt(param2); (* mov dword[reg1], param2 *) |
drop |
|IL.opSAVE8C: |
UnOp(reg1); |
OutByte3(0C6H, reg1, param2 MOD 256); (* mov byte[reg1], param2 *) |
drop |
|IL.opSAVE16C: |
UnOp(reg1); |
OutByte3(66H, 0C7H, reg1); OutWord(param2 MOD 65536); (* mov word[reg1], param2 *) |
drop |
|IL.opVLOAD32: |
reg1 := GetAnyReg(); |
movrm(reg1, ebp, param2 * 4); |
movrm(reg1, reg1, 0) |
|IL.opGLOAD32: |
reg1 := GetAnyReg(); |
IF pic THEN |
Pic(reg1, BIN.PICBSS, param2); |
movrm(reg1, reg1, 0) |
ELSE |
OutByte2(08BH, 05H + reg1 * 8); (* mov reg1, dword[_bss + param2] *) |
Reloc(BIN.RBSS, param2) |
END |
|IL.opLOAD32: |
UnOp(reg1); |
movrm(reg1, reg1, 0) |
|IL.opVLOAD8: |
reg1 := GetAnyReg(); |
movrm(reg1, ebp, param2 * 4); |
movzx(reg1, reg1, 0, FALSE) |
|IL.opGLOAD8: |
reg1 := GetAnyReg(); |
IF pic THEN |
Pic(reg1, BIN.PICBSS, param2); |
movzx(reg1, reg1, 0, FALSE) |
ELSE |
OutByte3(00FH, 0B6H, 05H + reg1 * 8); (* movzx reg1, byte[_bss + param2] *) |
Reloc(BIN.RBSS, param2) |
END |
|IL.opLLOAD8: |
movzx(GetAnyReg(), ebp, param2 * 4, FALSE) |
|IL.opLOAD8: |
UnOp(reg1); |
movzx(reg1, reg1, 0, FALSE) |
|IL.opVLOAD16: |
reg1 := GetAnyReg(); |
movrm(reg1, ebp, param2 * 4); |
movzx(reg1, reg1, 0, TRUE) |
|IL.opGLOAD16: |
reg1 := GetAnyReg(); |
IF pic THEN |
Pic(reg1, BIN.PICBSS, param2); |
movzx(reg1, reg1, 0, TRUE) |
ELSE |
OutByte3(00FH, 0B7H, 05H + reg1 * 8); (* movzx reg1, word[_bss + param2] *) |
Reloc(BIN.RBSS, param2) |
END |
|IL.opLLOAD16: |
movzx(GetAnyReg(), ebp, param2 * 4, TRUE) |
|IL.opLOAD16: |
UnOp(reg1); |
movzx(reg1, reg1, 0, TRUE) |
|IL.opUMINUS: |
UnOp(reg1); |
neg(reg1) |
|IL.opADD: |
BinOp(reg1, reg2); |
add(reg1, reg2); |
drop |
|IL.opADDC: |
IF param2 # 0 THEN |
UnOp(reg1); |
next := cmd.next(COMMAND); |
CASE next.opcode OF |
|IL.opLOAD32: |
movrm(reg1, reg1, param2); |
cmd := next |
|IL.opLOAD16: |
movzx(reg1, reg1, param2, TRUE); |
cmd := next |
|IL.opLOAD8: |
movzx(reg1, reg1, param2, FALSE); |
cmd := next |
|IL.opLOAD32_PARAM: |
pushm(reg1, param2); |
drop; |
cmd := next |
ELSE |
IF param2 = 1 THEN |
OutByte(40H + reg1) (* inc reg1 *) |
ELSIF param2 = -1 THEN |
OutByte(48H + reg1) (* dec reg1 *) |
ELSE |
addrc(reg1, param2) |
END |
END |
END |
|IL.opSUB: |
BinOp(reg1, reg2); |
oprr(29H, reg1, reg2); (* sub reg1, reg2 *) |
drop |
|IL.opSUBR, IL.opSUBL: |
UnOp(reg1); |
IF param2 = 1 THEN |
OutByte(48H + reg1) (* dec reg1 *) |
ELSIF param2 = -1 THEN |
OutByte(40H + reg1) (* inc reg1 *) |
ELSIF param2 # 0 THEN |
subrc(reg1, param2) |
END; |
IF opcode = IL.opSUBL THEN |
neg(reg1) |
END |
|IL.opMULC: |
IF (cmd.next(COMMAND).opcode = IL.opADD) & ((param2 = 2) OR (param2 = 4) OR (param2 = 8)) THEN |
BinOp(reg1, reg2); |
OutByte3(8DH, 04H + reg1 * 8, reg1 + reg2 * 8 + 40H * UTILS.Log2(param2)); (* lea reg1, [reg1 + reg2 * param2] *) |
drop; |
cmd := cmd.next(COMMAND) |
ELSE |
UnOp(reg1); |
a := param2; |
IF a > 1 THEN |
n := UTILS.Log2(a) |
ELSIF a < -1 THEN |
n := UTILS.Log2(-a) |
ELSE |
n := -1 |
END; |
IF a = 1 THEN |
ELSIF a = -1 THEN |
neg(reg1) |
ELSIF a = 0 THEN |
xor(reg1, reg1) |
ELSE |
IF n > 0 THEN |
IF a < 0 THEN |
neg(reg1) |
END; |
IF n # 1 THEN |
OutByte3(0C1H, 0E0H + reg1, n) (* shl reg1, n *) |
ELSE |
OutByte2(0D1H, 0E0H + reg1) (* shl reg1, 1 *) |
END |
ELSE |
OutByte2(69H + short(a), 0C0H + reg1 * 9); (* imul reg1, a *) |
OutIntByte(a) |
END |
END |
END |
|IL.opMUL: |
BinOp(reg1, reg2); |
OutByte3(0FH, 0AFH, 0C0H + reg1 * 8 + reg2); (* imul reg1, reg2 *) |
drop |
|IL.opSAVE, IL.opSAVE32: |
BinOp(reg2, reg1); |
movmr(reg1, 0, reg2); |
drop; |
drop |
|IL.opSAVE8: |
BinOp(reg2, reg1); |
movmr8(reg1, 0, reg2); |
drop; |
drop |
|IL.opSAVE16: |
BinOp(reg2, reg1); |
movmr16(reg1, 0, reg2); |
drop; |
drop |
|IL.opSAVEP: |
UnOp(reg1); |
IF pic THEN |
reg2 := GetAnyReg(); |
Pic(reg2, BIN.PICCODE, param2); |
movmr(reg1, 0, reg2); |
drop |
ELSE |
OutByte2(0C7H, reg1); (* mov dword[reg1], L *) |
Reloc(BIN.RCODE, param2) |
END; |
drop |
|IL.opSAVEIP: |
UnOp(reg1); |
IF pic THEN |
reg2 := GetAnyReg(); |
Pic(reg2, BIN.PICIMP, param2); |
pushm(reg2, 0); |
OutByte2(08FH, reg1); (* pop dword[reg1] *) |
drop |
ELSE |
OutByte2(0FFH, 035H); (* push dword[L] *) |
Reloc(BIN.RIMP, param2); |
OutByte2(08FH, reg1) (* pop dword[reg1] *) |
END; |
drop |
|IL.opPUSHP: |
reg1 := GetAnyReg(); |
IF pic THEN |
Pic(reg1, BIN.PICCODE, param2) |
ELSE |
OutByte(0B8H + reg1); (* mov reg1, L *) |
Reloc(BIN.RCODE, param2) |
END |
|IL.opPUSHIP: |
reg1 := GetAnyReg(); |
IF pic THEN |
Pic(reg1, BIN.PICIMP, param2); |
movrm(reg1, reg1, 0) |
ELSE |
OutByte2(08BH, 05H + reg1 * 8); (* mov reg1, dword[L] *) |
Reloc(BIN.RIMP, param2) |
END |
|IL.opNOT: |
UnOp(reg1); |
test(reg1); |
setcc(sete, reg1); |
andrc(reg1, 1) |
|IL.opORD: |
UnOp(reg1); |
test(reg1); |
setcc(setne, reg1); |
andrc(reg1, 1) |
|IL.opSBOOL: |
BinOp(reg2, reg1); |
test(reg2); |
OutByte3(0FH, 95H, reg1); (* setne byte[reg1] *) |
drop; |
drop |
|IL.opSBOOLC: |
UnOp(reg1); |
OutByte3(0C6H, reg1, ORD(param2 # 0)); (* mov byte[reg1], 0/1 *) |
drop |
|IL.opEQ..IL.opGE, |
IL.opEQC..IL.opGEC: |
IF (IL.opEQ <= opcode) & (opcode <= IL.opGE) THEN |
BinOp(reg1, reg2); |
cmprr(reg1, reg2); |
drop |
ELSE |
UnOp(reg1); |
cmprc(reg1, param2) |
END; |
drop; |
cc := cond(opcode); |
next := cmd.next(COMMAND); |
IF next.opcode = IL.opJNZ THEN |
jcc(cc, next.param1); |
cmd := next |
ELSIF next.opcode = IL.opJZ THEN |
jcc(inv0(cc), next.param1); |
cmd := next |
ELSE |
reg1 := GetAnyReg(); |
setcc(cc + 16, reg1); |
andrc(reg1, 1) |
END |
|IL.opEQB, IL.opNEB: |
BinOp(reg1, reg2); |
drop; |
test(reg1); |
OutByte2(74H, 5); (* je @f *) |
movrc(reg1, 1); (* mov reg1, 1 |
@@: *) |
test(reg2); |
OutByte2(74H, 5); (* je @f *) |
movrc(reg2, 1); (* mov reg2, 1 |
@@: *) |
cmprr(reg1, reg2); |
IF opcode = IL.opEQB THEN |
setcc(sete, reg1) |
ELSE |
setcc(setne, reg1) |
END; |
andrc(reg1, 1) |
|IL.opDROP: |
UnOp(reg1); |
drop |
|IL.opJNZ1: |
UnOp(reg1); |
test(reg1); |
jcc(jne, param1) |
|IL.opJG: |
UnOp(reg1); |
test(reg1); |
jcc(jg, param1) |
|IL.opJNZ: |
UnOp(reg1); |
test(reg1); |
jcc(jne, param1); |
drop |
|IL.opJZ: |
UnOp(reg1); |
test(reg1); |
jcc(je, param1); |
drop |
|IL.opSWITCH: |
UnOp(reg1); |
IF param2 = 0 THEN |
reg2 := eax |
ELSE |
reg2 := ecx |
END; |
IF reg1 # reg2 THEN |
ASSERT(REG.GetReg(R, reg2)); |
ASSERT(REG.Exchange(R, reg1, reg2)); |
drop |
END; |
drop |
|IL.opENDSW: |
|IL.opCASEL: |
cmprc(eax, param1); |
jcc(jl, param2) |
|IL.opCASER: |
cmprc(eax, param1); |
jcc(jg, param2) |
|IL.opCASELR: |
cmprc(eax, param1); |
IF param2 = cmd.param3 THEN |
jcc(jne, param2) |
ELSE |
jcc(jl, param2); |
jcc(jg, cmd.param3) |
END |
|IL.opCODE: |
OutByte(param2) |
|IL.opGET, IL.opGETC: |
IF opcode = IL.opGET THEN |
BinOp(reg1, reg2) |
ELSIF opcode = IL.opGETC THEN |
UnOp(reg2); |
reg1 := GetAnyReg(); |
movrc(reg1, param1) |
END; |
drop; |
drop; |
IF param2 # 8 THEN |
_movrm(reg1, reg1, 0, param2 * 8, FALSE); |
_movrm(reg1, reg2, 0, param2 * 8, TRUE) |
ELSE |
PushAll(0); |
push(reg1); |
push(reg2); |
pushc(8); |
CallRTL(pic, IL._move) |
END |
|IL.opSAVES: |
UnOp(reg2); |
REG.PushAll_1(R); |
IF pic THEN |
reg1 := GetAnyReg(); |
Pic(reg1, BIN.PICDATA, stroffs + param2); |
push(reg1); |
drop |
ELSE |
OutByte(068H); (* push _data + stroffs + param2 *) |
Reloc(BIN.RDATA, stroffs + param2); |
END; |
push(reg2); |
drop; |
pushc(param1); |
CallRTL(pic, IL._move) |
|IL.opCHKBYTE: |
BinOp(reg1, reg2); |
cmprc(reg1, 256); |
jcc(jb, param1) |
|IL.opCHKIDX: |
UnOp(reg1); |
cmprc(reg1, param2); |
jcc(jb, param1) |
|IL.opCHKIDX2: |
BinOp(reg1, reg2); |
IF param2 # -1 THEN |
cmprr(reg2, reg1); |
jcc(jb, param1) |
END; |
INCL(R.regs, reg1); |
DEC(R.top); |
R.stk[R.top] := reg2 |
|IL.opLEN: |
n := param2; |
UnOp(reg1); |
drop; |
EXCL(R.regs, reg1); |
WHILE n > 0 DO |
UnOp(reg2); |
drop; |
DEC(n) |
END; |
INCL(R.regs, reg1); |
ASSERT(REG.GetReg(R, reg1)) |
|IL.opINCC: |
UnOp(reg1); |
IF param2 = 1 THEN |
OutByte2(0FFH, reg1) (* inc dword[reg1] *) |
ELSIF param2 = -1 THEN |
OutByte2(0FFH, reg1 + 8) (* dec dword[reg1] *) |
ELSE |
OutByte2(81H + short(param2), reg1); OutIntByte(param2) (* add dword[reg1], param2 *) |
END; |
drop |
|IL.opINC, IL.opDEC: |
BinOp(reg1, reg2); |
OutByte2(01H + 28H * ORD(opcode = IL.opDEC), reg1 * 8 + reg2); (* add/sub dword[reg2], reg1 *) |
drop; |
drop |
|IL.opINCCB, IL.opDECCB: |
UnOp(reg1); |
OutByte3(80H, 28H * ORD(opcode = IL.opDECCB) + reg1, param2 MOD 256); (* add/sub byte[reg1], n *) |
drop |
|IL.opINCB, IL.opDECB: |
BinOp(reg1, reg2); |
OutByte2(28H * ORD(opcode = IL.opDECB), reg1 * 8 + reg2); (* add/sub byte[reg2], reg1 *) |
drop; |
drop |
|IL.opMULS: |
BinOp(reg1, reg2); |
oprr(21H, reg1, reg2); (* and reg1, reg2 *) |
drop |
|IL.opMULSC: |
UnOp(reg1); |
andrc(reg1, param2) |
|IL.opDIVS: |
BinOp(reg1, reg2); |
xor(reg1, reg2); |
drop |
|IL.opDIVSC: |
UnOp(reg1); |
xorrc(reg1, param2) |
|IL.opADDS: |
BinOp(reg1, reg2); |
oprr(9H, reg1, reg2); (* or reg1, reg2 *) |
drop |
|IL.opSUBS: |
BinOp(reg1, reg2); |
not(reg2); |
oprr(21H, reg1, reg2); (* and reg1, reg2 *) |
drop |
|IL.opADDSC: |
UnOp(reg1); |
orrc(reg1, param2) |
|IL.opSUBSL: |
UnOp(reg1); |
not(reg1); |
andrc(reg1, param2) |
|IL.opSUBSR: |
UnOp(reg1); |
andrc(reg1, ORD(-BITS(param2))) |
|IL.opUMINS: |
UnOp(reg1); |
not(reg1) |
|IL.opLENGTH: |
PushAll(2); |
CallRTL(pic, IL._length); |
GetRegA |
|IL.opLENGTHW: |
PushAll(2); |
CallRTL(pic, IL._lengthw); |
GetRegA |
|IL.opCHR: |
UnOp(reg1); |
andrc(reg1, 255) |
|IL.opWCHR: |
UnOp(reg1); |
andrc(reg1, 65535) |
|IL.opASR, IL.opROR, IL.opLSL, IL.opLSR: |
UnOp(reg1); |
IF reg1 # ecx THEN |
ASSERT(REG.GetReg(R, ecx)); |
ASSERT(REG.Exchange(R, reg1, ecx)); |
drop |
END; |
BinOp(reg1, reg2); |
ASSERT(reg2 = ecx); |
OutByte(0D3H); |
shift(opcode, reg1); (* shift reg1, cl *) |
drop |
|IL.opASR1, IL.opROR1, IL.opLSL1, IL.opLSR1: |
UnOp(reg1); |
IF reg1 # ecx THEN |
ASSERT(REG.GetReg(R, ecx)); |
ASSERT(REG.Exchange(R, reg1, ecx)); |
drop |
END; |
reg1 := GetAnyReg(); |
movrc(reg1, param2); |
BinOp(reg1, reg2); |
ASSERT(reg1 = ecx); |
OutByte(0D3H); |
shift(opcode, reg2); (* shift reg2, cl *) |
drop; |
drop; |
ASSERT(REG.GetReg(R, reg2)) |
|IL.opASR2, IL.opROR2, IL.opLSL2, IL.opLSR2: |
UnOp(reg1); |
n := param2 MOD 32; |
IF n # 1 THEN |
OutByte(0C1H) |
ELSE |
OutByte(0D1H) |
END; |
shift(opcode, reg1); (* shift reg1, n *) |
IF n # 1 THEN |
OutByte(n) |
END |
|IL.opMAX, IL.opMIN: |
BinOp(reg1, reg2); |
cmprr(reg1, reg2); |
OutByte2(07DH + ORD(opcode = IL.opMIN), 2); (* jge/jle L *) |
mov(reg1, reg2); |
(* L: *) |
drop |
|IL.opMAXC, IL.opMINC: |
UnOp(reg1); |
cmprc(reg1, param2); |
label := NewLabel(); |
IF opcode = IL.opMINC THEN |
cc := jle |
ELSE |
cc := jge |
END; |
jcc(cc, label); |
movrc(reg1, param2); |
SetLabel(label) |
|IL.opIN, IL.opINR: |
IF opcode = IL.opINR THEN |
reg2 := GetAnyReg(); |
movrc(reg2, param2) |
END; |
label := NewLabel(); |
BinOp(reg1, reg2); |
cmprc(reg1, 32); |
OutByte2(72H, 4); (* jb L *) |
xor(reg1, reg1); |
jmp(label); |
(* L: *) |
OutByte3(0FH, 0A3H, 0C0H + reg2 + 8 * reg1); (* bt reg2, reg1 *) |
setcc(setc, reg1); |
andrc(reg1, 1); |
SetLabel(label); |
drop |
|IL.opINL: |
UnOp(reg1); |
OutByte3(0FH, 0BAH, 0E0H + reg1); OutByte(param2); (* bt reg1, param2 *) |
setcc(setc, reg1); |
andrc(reg1, 1) |
|IL.opRSET: |
PushAll(2); |
CallRTL(pic, IL._set); |
GetRegA |
|IL.opRSETR: |
PushAll(1); |
pushc(param2); |
CallRTL(pic, IL._set); |
GetRegA |
|IL.opRSETL: |
UnOp(reg1); |
REG.PushAll_1(R); |
pushc(param2); |
push(reg1); |
drop; |
CallRTL(pic, IL._set); |
GetRegA |
|IL.opRSET1: |
PushAll(1); |
CallRTL(pic, IL._set1); |
GetRegA |
|IL.opINCL, IL.opEXCL: |
BinOp(reg1, reg2); |
cmprc(reg1, 32); |
OutByte2(73H, 03H); (* jnb L *) |
OutByte(0FH); |
IF opcode = IL.opINCL THEN |
OutByte(0ABH) (* bts dword[reg2], reg1 *) |
ELSE |
OutByte(0B3H) (* btr dword[reg2], reg1 *) |
END; |
OutByte(reg2 + 8 * reg1); |
(* L: *) |
drop; |
drop |
|IL.opINCLC: |
UnOp(reg1); |
OutByte3(0FH, 0BAH, 28H + reg1); OutByte(param2); (* bts dword[reg1], param2 *) |
drop |
|IL.opEXCLC: |
UnOp(reg1); |
OutByte3(0FH, 0BAH, 30H + reg1); OutByte(param2); (* btr dword[reg1], param2 *) |
drop |
|IL.opDIV: |
PushAll(2); |
CallRTL(pic, IL._divmod); |
GetRegA |
|IL.opDIVR: |
n := UTILS.Log2(param2); |
IF n > 0 THEN |
UnOp(reg1); |
IF n # 1 THEN |
OutByte3(0C1H, 0F8H + reg1, n) (* sar reg1, n *) |
ELSE |
OutByte2(0D1H, 0F8H + reg1) (* sar reg1, 1 *) |
END |
ELSIF n < 0 THEN |
PushAll(1); |
pushc(param2); |
CallRTL(pic, IL._divmod); |
GetRegA |
END |
|IL.opDIVL: |
UnOp(reg1); |
REG.PushAll_1(R); |
pushc(param2); |
push(reg1); |
drop; |
CallRTL(pic, IL._divmod); |
GetRegA |
|IL.opMOD: |
PushAll(2); |
CallRTL(pic, IL._divmod); |
mov(eax, edx); |
GetRegA |
|IL.opMODR: |
n := UTILS.Log2(param2); |
IF n > 0 THEN |
UnOp(reg1); |
andrc(reg1, param2 - 1); |
ELSIF n < 0 THEN |
PushAll(1); |
pushc(param2); |
CallRTL(pic, IL._divmod); |
mov(eax, edx); |
GetRegA |
ELSE |
UnOp(reg1); |
xor(reg1, reg1) |
END |
|IL.opMODL: |
UnOp(reg1); |
REG.PushAll_1(R); |
pushc(param2); |
push(reg1); |
drop; |
CallRTL(pic, IL._divmod); |
mov(eax, edx); |
GetRegA |
|IL.opERR: |
CallRTL(pic, IL._error) |
|IL.opABS: |
UnOp(reg1); |
test(reg1); |
OutByte2(07DH, 002H); (* jge L *) |
neg(reg1) (* neg reg1 |
L: *) |
|IL.opCOPY: |
PushAll(2); |
pushc(param2); |
CallRTL(pic, IL._move) |
|IL.opMOVE: |
PushAll(3); |
CallRTL(pic, IL._move) |
|IL.opCOPYA: |
PushAll(4); |
pushc(param2); |
CallRTL(pic, IL._arrcpy); |
GetRegA |
|IL.opCOPYS: |
PushAll(4); |
pushc(param2); |
CallRTL(pic, IL._strcpy) |
|IL.opROT: |
PushAll(0); |
push(esp); |
pushc(param2); |
CallRTL(pic, IL._rot) |
|IL.opNEW: |
PushAll(1); |
n := param2 + 8; |
ASSERT(UTILS.Align(n, 32)); |
pushc(n); |
pushc(param1); |
CallRTL(pic, IL._new) |
|IL.opDISP: |
PushAll(1); |
CallRTL(pic, IL._dispose) |
|IL.opEQS .. IL.opGES: |
PushAll(4); |
pushc(opcode - IL.opEQS); |
CallRTL(pic, IL._strcmp); |
GetRegA |
|IL.opEQSW .. IL.opGESW: |
PushAll(4); |
pushc(opcode - IL.opEQSW); |
CallRTL(pic, IL._strcmpw); |
GetRegA |
|IL.opEQP, IL.opNEP, IL.opEQIP, IL.opNEIP: |
UnOp(reg1); |
CASE opcode OF |
|IL.opEQP, IL.opNEP: |
IF pic THEN |
reg2 := GetAnyReg(); |
Pic(reg2, BIN.PICCODE, param1); |
cmprr(reg1, reg2); |
drop |
ELSE |
OutByte2(081H, 0F8H + reg1); (* cmp reg1, L *) |
Reloc(BIN.RCODE, param1) |
END |
|IL.opEQIP, IL.opNEIP: |
IF pic THEN |
reg2 := GetAnyReg(); |
Pic(reg2, BIN.PICIMP, param1); |
OutByte2(03BH, reg1 * 8 + reg2); (* cmp reg1, dword [reg2] *) |
drop |
ELSE |
OutByte2(3BH, 05H + reg1 * 8); (* cmp reg1, dword[L] *) |
Reloc(BIN.RIMP, param1) |
END |
END; |
drop; |
reg1 := GetAnyReg(); |
CASE opcode OF |
|IL.opEQP, IL.opEQIP: setcc(sete, reg1) |
|IL.opNEP, IL.opNEIP: setcc(setne, reg1) |
END; |
andrc(reg1, 1) |
|IL.opPUSHT: |
UnOp(reg1); |
movrm(GetAnyReg(), reg1, -4) |
|IL.opISREC: |
PushAll(2); |
pushc(param2 * tcount); |
CallRTL(pic, IL._isrec); |
GetRegA |
|IL.opIS: |
PushAll(1); |
pushc(param2 * tcount); |
CallRTL(pic, IL._is); |
GetRegA |
|IL.opTYPEGR: |
PushAll(1); |
pushc(param2 * tcount); |
CallRTL(pic, IL._guardrec); |
GetRegA |
|IL.opTYPEGP: |
UnOp(reg1); |
PushAll(0); |
push(reg1); |
pushc(param2 * tcount); |
CallRTL(pic, IL._guard); |
GetRegA |
|IL.opTYPEGD: |
UnOp(reg1); |
PushAll(0); |
pushm(reg1, -4); |
pushc(param2 * tcount); |
CallRTL(pic, IL._guardrec); |
GetRegA |
|IL.opCASET: |
push(ecx); |
push(ecx); |
pushc(param2 * tcount); |
CallRTL(pic, IL._guardrec); |
pop(ecx); |
test(eax); |
jcc(jne, param1) |
|IL.opPACK: |
BinOp(reg1, reg2); |
push(reg2); |
OutByte3(0DBH, 004H, 024H); (* fild dword[esp] *) |
OutByte2(0DDH, reg1); (* fld qword[reg1] *) |
OutByte2(0D9H, 0FDH); (* fscale *) |
OutByte2(0DDH, 018H + reg1); (* fstp qword[reg1] *) |
OutByte3(0DBH, 01CH, 024H); (* fistp dword[esp] *) |
pop(reg2); |
drop; |
drop |
|IL.opPACKC: |
UnOp(reg1); |
pushc(param2); |
OutByte3(0DBH, 004H, 024H); (* fild dword[esp] *) |
OutByte2(0DDH, reg1); (* fld qword[reg1] *) |
OutByte2(0D9H, 0FDH); (* fscale *) |
OutByte2(0DDH, 018H + reg1); (* fstp qword[reg1] *) |
OutByte3(0DBH, 01CH, 024H); (* fistp dword[esp] *) |
pop(reg1); |
drop |
|IL.opUNPK: |
BinOp(reg1, reg2); |
OutByte2(0DDH, reg1); (* fld qword[reg1] *) |
OutByte2(0D9H, 0F4H); (* fxtract *) |
OutByte2(0DDH, 018H + reg1); (* fstp qword[reg1] *) |
OutByte2(0DBH, 018H + reg2); (* fistp dword[reg2] *) |
drop; |
drop |
|IL.opPUSHF: |
ASSERT(fr >= 0); |
DEC(fr); |
subrc(esp, 8); |
OutByte3(0DDH, 01CH, 024H) (* fstp qword[esp] *) |
|IL.opLOADF: |
INC(fr); |
IF fr > MAX_FR THEN |
ERRORS.ErrorMsg(fname, param1, param2, FPR_ERR) |
END; |
UnOp(reg1); |
OutByte2(0DDH, reg1); (* fld qword[reg1] *) |
drop |
|IL.opCONSTF: |
INC(fr); |
IF fr > MAX_FR THEN |
ERRORS.ErrorMsg(fname, param1, param2, FPR_ERR) |
END; |
float := cmd.float; |
IF float = 0.0 THEN |
OutByte2(0D9H, 0EEH) (* fldz *) |
ELSIF float = 1.0 THEN |
OutByte2(0D9H, 0E8H) (* fld1 *) |
ELSIF float = -1.0 THEN |
OutByte2(0D9H, 0E8H); (* fld1 *) |
OutByte2(0D9H, 0E0H) (* fchs *) |
ELSE |
n := UTILS.splitf(float, a, b); |
pushc(b); |
pushc(a); |
OutByte3(0DDH, 004H, 024H); (* fld qword[esp] *) |
addrc(esp, 8) |
END |
|IL.opSAVEF, IL.opSAVEFI: |
ASSERT(fr >= 0); |
DEC(fr); |
UnOp(reg1); |
OutByte2(0DDH, 018H + reg1); (* fstp qword[reg1] *) |
drop |
|IL.opADDF: |
ASSERT(fr >= 1); |
DEC(fr); |
OutByte2(0DEH, 0C1H) (* faddp st1, st *) |
|IL.opSUBF: |
ASSERT(fr >= 1); |
DEC(fr); |
OutByte2(0DEH, 0E9H) (* fsubp st1, st *) |
|IL.opSUBFI: |
ASSERT(fr >= 1); |
DEC(fr); |
OutByte2(0DEH, 0E1H) (* fsubrp st1, st *) |
|IL.opMULF: |
ASSERT(fr >= 1); |
DEC(fr); |
OutByte2(0DEH, 0C9H) (* fmulp st1, st *) |
|IL.opDIVF: |
ASSERT(fr >= 1); |
DEC(fr); |
OutByte2(0DEH, 0F9H) (* fdivp st1, st *) |
|IL.opDIVFI: |
ASSERT(fr >= 1); |
DEC(fr); |
OutByte2(0DEH, 0F1H) (* fdivrp st1, st *) |
|IL.opUMINF: |
ASSERT(fr >= 0); |
OutByte2(0D9H, 0E0H) (* fchs *) |
|IL.opFABS: |
ASSERT(fr >= 0); |
OutByte2(0D9H, 0E1H) (* fabs *) |
|IL.opFLT: |
INC(fr); |
IF fr > MAX_FR THEN |
ERRORS.ErrorMsg(fname, param1, param2, FPR_ERR) |
END; |
UnOp(reg1); |
push(reg1); |
OutByte3(0DBH, 004H, 024H); (* fild dword[esp] *) |
pop(reg1); |
drop |
|IL.opFLOOR: |
ASSERT(fr >= 0); |
DEC(fr); |
subrc(esp, 8); |
OutByte2(09BH, 0D9H); OutByte3(07CH, 024H, 004H); (* fstcw word[esp+4] *) |
OutByte2(09BH, 0D9H); OutByte3(07CH, 024H, 006H); (* fstcw word[esp+6] *) |
OutByte2(066H, 081H); OutByte3(064H, 024H, 004H); OutWord(0F3FFH); (* and word[esp+4], 1111001111111111b *) |
OutByte2(066H, 081H); OutByte3(04CH, 024H, 004H); OutWord(00400H); (* or word[esp+4], 0000010000000000b *) |
OutByte2(0D9H, 06CH); OutByte2(024H, 004H); (* fldcw word[esp+4] *) |
OutByte2(0D9H, 0FCH); (* frndint *) |
OutByte3(0DBH, 01CH, 024H); (* fistp dword[esp] *) |
pop(GetAnyReg()); |
OutByte2(0D9H, 06CH); OutByte2(024H, 002H); (* fldcw word[esp+2] *) |
addrc(esp, 4) |
|IL.opEQF: |
ASSERT(fr >= 1); |
DEC(fr, 2); |
fcmp; |
OutByte2(07AH, 003H); (* jp L *) |
setcc(sete, al) |
(* L: *) |
|IL.opNEF: |
ASSERT(fr >= 1); |
DEC(fr, 2); |
fcmp; |
OutByte2(07AH, 003H); (* jp L *) |
setcc(setne, al) |
(* L: *) |
|IL.opLTF: |
ASSERT(fr >= 1); |
DEC(fr, 2); |
fcmp; |
OutByte2(07AH, 00EH); (* jp L *) |
setcc(setc, al); |
setcc(sete, ah); |
test(eax); |
setcc(sete, al); |
andrc(eax, 1) |
(* L: *) |
|IL.opGTF: |
ASSERT(fr >= 1); |
DEC(fr, 2); |
fcmp; |
OutByte2(07AH, 00FH); (* jp L *) |
setcc(setc, al); |
setcc(sete, ah); |
cmprc(eax, 1); |
setcc(sete, al); |
andrc(eax, 1) |
(* L: *) |
|IL.opLEF: |
ASSERT(fr >= 1); |
DEC(fr, 2); |
fcmp; |
OutByte2(07AH, 003H); (* jp L *) |
setcc(setnc, al) |
(* L: *) |
|IL.opGEF: |
ASSERT(fr >= 1); |
DEC(fr, 2); |
fcmp; |
OutByte2(07AH, 010H); (* jp L *) |
setcc(setc, al); |
setcc(sete, ah); |
OutByte2(000H, 0E0H); (* add al, ah *) |
OutByte2(03CH, 001H); (* cmp al, 1 *) |
setcc(sete, al); |
andrc(eax, 1) |
(* L: *) |
|IL.opINF: |
INC(fr); |
IF fr > MAX_FR THEN |
ERRORS.ErrorMsg(fname, param1, param2, FPR_ERR) |
END; |
pushc(7FF00000H); |
pushc(0); |
OutByte3(0DDH, 004H, 024H); (* fld qword[esp] *) |
addrc(esp, 8) |
|IL.opLADR_UNPK: |
n := param2 * 4; |
reg1 := GetAnyReg(); |
OutByte2(8DH, 45H + reg1 * 8 + long(n)); (* lea reg1, dword[ebp + n] *) |
OutIntByte(n); |
BinOp(reg1, reg2); |
OutByte2(0DDH, reg1); (* fld qword[reg1] *) |
OutByte2(0D9H, 0F4H); (* fxtract *) |
OutByte2(0DDH, 018H + reg1); (* fstp qword[reg1] *) |
OutByte2(0DBH, 018H + reg2); (* fistp dword[reg2] *) |
drop; |
drop |
|IL.opSADR_PARAM: |
IF pic THEN |
reg1 := GetAnyReg(); |
Pic(reg1, BIN.PICDATA, stroffs + param2); |
push(reg1); |
drop |
ELSE |
OutByte(068H); (* push _data + stroffs + param2 *) |
Reloc(BIN.RDATA, stroffs + param2) |
END |
|IL.opVADR_PARAM, IL.opLLOAD32_PARAM: |
pushm(ebp, param2 * 4) |
|IL.opCONST_PARAM: |
pushc(param2) |
|IL.opGLOAD32_PARAM: |
IF pic THEN |
reg1 := GetAnyReg(); |
Pic(reg1, BIN.PICBSS, param2); |
pushm(reg1, 0); |
drop |
ELSE |
OutByte2(0FFH, 035H); (* push dword[_bss + param2] *) |
Reloc(BIN.RBSS, param2) |
END |
|IL.opLOAD32_PARAM: |
UnOp(reg1); |
pushm(reg1, 0); |
drop |
|IL.opGADR_SAVEC: |
IF pic THEN |
reg1 := GetAnyReg(); |
Pic(reg1, BIN.PICBSS, param1); |
OutByte2(0C7H, reg1); (* mov dword[reg1], param2 *) |
OutInt(param2); |
drop |
ELSE |
OutByte2(0C7H, 05H); (* mov dword[_bss + param1], param2 *) |
Reloc(BIN.RBSS, param1); |
OutInt(param2) |
END |
|IL.opLADR_SAVEC: |
n := param1 * 4; |
OutByte2(0C7H, 45H + long(n)); (* mov dword[ebp + n], param2 *) |
OutIntByte(n); |
OutInt(param2) |
|IL.opLADR_SAVE: |
UnOp(reg1); |
movmr(ebp, param2 * 4, reg1); |
drop |
|IL.opLADR_INCC: |
n := param1 * 4; |
IF ABS(param2) = 1 THEN |
OutByte2(0FFH, 45H + 8 * ORD(param2 = -1) + long(n)); (* inc/dec dword[ebp + n] *) |
OutIntByte(n) |
ELSE |
OutByte2(81H + short(param2), 45H + long(n)); (* add dword[ebp + n], param2 *) |
OutIntByte(n); |
OutIntByte(param2) |
END |
|IL.opLADR_INCCB, IL.opLADR_DECCB: |
n := param1 * 4; |
IF param2 = 1 THEN |
OutByte2(0FEH, 45H + 8 * ORD(opcode = IL.opLADR_DECCB) + long(n)); (* inc/dec byte[ebp + n] *) |
OutIntByte(n) |
ELSE |
OutByte2(80H, 45H + 28H * ORD(opcode = IL.opLADR_DECCB) + long(n)); (* add/sub byte[ebp + n], param2 *) |
OutIntByte(n); |
OutByte(param2 MOD 256) |
END |
|IL.opLADR_INC, IL.opLADR_DEC: |
n := param2 * 4; |
UnOp(reg1); |
OutByte2(01H + 28H * ORD(opcode = IL.opLADR_DEC), 45H + long(n) + reg1 * 8); (* add/sub dword[ebp + n], reg1 *) |
OutIntByte(n); |
drop |
|IL.opLADR_INCB, IL.opLADR_DECB: |
n := param2 * 4; |
UnOp(reg1); |
OutByte2(28H * ORD(opcode = IL.opLADR_DECB), 45H + long(n) + reg1 * 8); (* add/sub byte[ebp + n], reg1 *) |
OutIntByte(n); |
drop |
|IL.opLADR_INCL, IL.opLADR_EXCL: |
n := param2 * 4; |
UnOp(reg1); |
cmprc(reg1, 32); |
label := NewLabel(); |
jcc(jnb, label); |
OutByte3(0FH, 0ABH + 8 * ORD(opcode = IL.opLADR_EXCL), 45H + long(n) + reg1 * 8); (* bts(r) dword[ebp + n], reg1 *) |
OutIntByte(n); |
SetLabel(label); |
drop |
|IL.opLADR_INCLC, IL.opLADR_EXCLC: |
n := param1 * 4; |
OutByte3(0FH, 0BAH, 6DH + long(n) + 8 * ORD(opcode = IL.opLADR_EXCLC)); (* bts(r) dword[ebp + n], param2 *) |
OutIntByte(n); |
OutByte(param2) |
|IL.opFNAME: |
fname := cmd(IL.FNAMECMD).fname |
END; |
cmd := cmd.next(COMMAND) |
END; |
ASSERT(R.pushed = 0); |
ASSERT(R.top = -1); |
ASSERT(fr = -1) |
END translate; |
PROCEDURE prolog (pic: BOOLEAN; target, stack, dllinit, dllret: INTEGER); |
VAR |
reg1, entry, L, dcount: INTEGER; |
BEGIN |
entry := NewLabel(); |
SetLabel(entry); |
dcount := CHL.Length(IL.codes.data); |
IF target = TARGETS.Win32DLL THEN |
push(ebp); |
mov(ebp, esp); |
pushm(ebp, 16); |
pushm(ebp, 12); |
pushm(ebp, 8); |
CallRTL(pic, IL._dllentry); |
test(eax); |
jcc(je, dllret); |
pushc(0) |
ELSIF target = TARGETS.KolibriOSDLL THEN |
SetLabel(dllinit); |
OutByte(68H); (* push IMPORT *) |
Reloc(BIN.IMPTAB, 0) |
ELSIF target = TARGETS.KolibriOS THEN |
reg1 := GetAnyReg(); |
Pic(reg1, BIN.IMPTAB, 0); |
push(reg1); (* push IMPORT *) |
drop |
ELSIF target = TARGETS.Linux32 THEN |
push(esp) |
ELSE |
pushc(0) |
END; |
IF pic THEN |
reg1 := GetAnyReg(); |
Pic(reg1, BIN.PICCODE, entry); |
push(reg1); (* push CODE *) |
Pic(reg1, BIN.PICDATA, 0); |
push(reg1); (* push _data *) |
pushc(tcount); |
Pic(reg1, BIN.PICDATA, tcount * 4 + dcount); |
push(reg1); (* push _data + tcount * 4 + dcount *) |
drop |
ELSE |
OutByte(68H); (* push CODE *) |
Reloc(BIN.RCODE, entry); |
OutByte(68H); (* push _data *) |
Reloc(BIN.RDATA, 0); |
pushc(tcount); |
OutByte(68H); (* push _data + tcount * 4 + dcount *) |
Reloc(BIN.RDATA, tcount * 4 + dcount) |
END; |
CallRTL(pic, IL._init); |
IF target IN {TARGETS.Win32C, TARGETS.Win32GUI, TARGETS.Linux32} THEN |
L := NewLabel(); |
pushc(0); |
push(esp); |
pushc(1024 * 1024 * stack); |
pushc(0); |
CallRTL(pic, IL._new); |
pop(eax); |
test(eax); |
jcc(je, L); |
addrc(eax, 1024 * 1024 * stack - 4); |
mov(esp, eax); |
SetLabel(L) |
END |
END prolog; |
PROCEDURE epilog (pic: BOOLEAN; modname: ARRAY OF CHAR; target, stack, ver, dllinit, dllret, sofinit: INTEGER); |
VAR |
exp: IL.EXPORT_PROC; |
path, name, ext: PATHS.PATH; |
dcount, i: INTEGER; |
PROCEDURE _import (imp: LISTS.LIST); |
VAR |
lib: IL.IMPORT_LIB; |
proc: IL.IMPORT_PROC; |
BEGIN |
lib := imp.first(IL.IMPORT_LIB); |
WHILE lib # NIL DO |
BIN.Import(program, lib.name, 0); |
proc := lib.procs.first(IL.IMPORT_PROC); |
WHILE proc # NIL DO |
BIN.Import(program, proc.name, proc.label); |
proc := proc.next(IL.IMPORT_PROC) |
END; |
lib := lib.next(IL.IMPORT_LIB) |
END |
END _import; |
BEGIN |
IF target IN {TARGETS.Win32C, TARGETS.Win32GUI, TARGETS.KolibriOS, TARGETS.Linux32} THEN |
pushc(0); |
CallRTL(pic, IL._exit); |
ELSIF target = TARGETS.Win32DLL THEN |
SetLabel(dllret); |
movrc(eax, 1); |
OutByte(0C9H); (* leave *) |
OutByte3(0C2H, 0CH, 0) (* ret 12 *) |
ELSIF target = TARGETS.KolibriOSDLL THEN |
movrc(eax, 1); |
ret |
ELSIF target = TARGETS.Linux32SO THEN |
ret; |
SetLabel(sofinit); |
CallRTL(pic, IL._sofinit); |
ret |
END; |
fixup; |
dcount := CHL.Length(IL.codes.data); |
FOR i := 0 TO tcount - 1 DO |
BIN.PutData32LE(program, CHL.GetInt(IL.codes.types, i)) |
END; |
FOR i := 0 TO dcount - 1 DO |
BIN.PutData(program, CHL.GetByte(IL.codes.data, i)) |
END; |
program.modname := CHL.Length(program.data); |
PATHS.split(modname, path, name, ext); |
BIN.PutDataStr(program, name); |
BIN.PutDataStr(program, ext); |
BIN.PutData(program, 0); |
IF target = TARGETS.KolibriOSDLL THEN |
BIN.Export(program, "lib_init", dllinit); |
END; |
exp := IL.codes.export.first(IL.EXPORT_PROC); |
WHILE exp # NIL DO |
BIN.Export(program, exp.name, exp.label); |
exp := exp.next(IL.EXPORT_PROC) |
END; |
_import(IL.codes._import); |
IL.set_bss(MAX(IL.codes.bss, MAX(IL.codes.dmin - CHL.Length(IL.codes.data), 4))); |
BIN.SetParams(program, IL.codes.bss, stack * (1024 * 1024), WCHR(ver DIV 65536), WCHR(ver MOD 65536)) |
END epilog; |
PROCEDURE CodeGen* (outname: ARRAY OF CHAR; target: INTEGER; options: PROG.OPTIONS); |
VAR |
dllret, dllinit, sofinit: INTEGER; |
opt: PROG.OPTIONS; |
BEGIN |
FR[0] := 0; |
tcount := CHL.Length(IL.codes.types); |
opt := options; |
CodeList := LISTS.create(NIL); |
program := BIN.create(IL.codes.lcount); |
dllinit := NewLabel(); |
dllret := NewLabel(); |
sofinit := NewLabel(); |
IF target = TARGETS.KolibriOSDLL THEN |
opt.pic := FALSE |
END; |
IF TARGETS.OS IN {TARGETS.osWIN32, TARGETS.osLINUX32} THEN |
opt.pic := TRUE |
END; |
REG.Init(R, push, pop, mov, xchg, {eax, ecx, edx}); |
prolog(opt.pic, target, opt.stack, dllinit, dllret); |
translate(opt.pic, tcount * 4); |
epilog(opt.pic, outname, target, opt.stack, opt.version, dllinit, dllret, sofinit); |
BIN.fixup(program); |
IF TARGETS.OS = TARGETS.osWIN32 THEN |
PE32.write(program, outname, target = TARGETS.Win32C, target = TARGETS.Win32DLL, FALSE) |
ELSIF target = TARGETS.KolibriOS THEN |
KOS.write(program, outname) |
ELSIF target = TARGETS.KolibriOSDLL THEN |
MSCOFF.write(program, outname, opt.version) |
ELSIF TARGETS.OS = TARGETS.osLINUX32 THEN |
ELF.write(program, outname, sofinit, target = TARGETS.Linux32SO, FALSE) |
END |
END CodeGen; |
PROCEDURE SetProgram* (prog: BIN.PROGRAM); |
BEGIN |
program := prog; |
CodeList := LISTS.create(NIL) |
END SetProgram; |
END X86. |
/programs/develop/oberon07/source/BIN.ob07 |
---|
0,0 → 1,384 |
(* |
BSD 2-Clause License |
Copyright (c) 2018-2020, Anton Krotov |
All rights reserved. |
*) |
MODULE BIN; |
IMPORT LISTS, CHL := CHUNKLISTS, ARITH, UTILS; |
CONST |
RCODE* = 0; PICCODE* = RCODE + 1; |
RDATA* = 2; PICDATA* = RDATA + 1; |
RBSS* = 4; PICBSS* = RBSS + 1; |
RIMP* = 6; PICIMP* = RIMP + 1; |
IMPTAB* = 8; |
TYPE |
RELOC* = POINTER TO RECORD (LISTS.ITEM) |
opcode*: INTEGER; |
offset*: INTEGER |
END; |
IMPRT* = POINTER TO RECORD (LISTS.ITEM) |
nameoffs*: INTEGER; |
label*: INTEGER; |
OriginalFirstThunk*, |
FirstThunk*: INTEGER |
END; |
EXPRT* = POINTER TO RECORD (LISTS.ITEM) |
nameoffs*: INTEGER; |
label*: INTEGER |
END; |
PROGRAM* = POINTER TO RECORD |
code*: CHL.BYTELIST; |
data*: CHL.BYTELIST; |
labels: CHL.INTLIST; |
bss*: INTEGER; |
stack*: INTEGER; |
vmajor*, |
vminor*: WCHAR; |
modname*: INTEGER; |
_import*: CHL.BYTELIST; |
export*: CHL.BYTELIST; |
rel_list*: LISTS.LIST; |
imp_list*: LISTS.LIST; |
exp_list*: LISTS.LIST |
END; |
PROCEDURE create* (NumberOfLabels: INTEGER): PROGRAM; |
VAR |
program: PROGRAM; |
i: INTEGER; |
BEGIN |
NEW(program); |
program.bss := 0; |
program.labels := CHL.CreateIntList(); |
FOR i := 0 TO NumberOfLabels - 1 DO |
CHL.PushInt(program.labels, 0) |
END; |
program.rel_list := LISTS.create(NIL); |
program.imp_list := LISTS.create(NIL); |
program.exp_list := LISTS.create(NIL); |
program.data := CHL.CreateByteList(); |
program.code := CHL.CreateByteList(); |
program._import := CHL.CreateByteList(); |
program.export := CHL.CreateByteList() |
RETURN program |
END create; |
PROCEDURE SetParams* (program: PROGRAM; bss, stack: INTEGER; vmajor, vminor: WCHAR); |
BEGIN |
program.bss := bss; |
program.stack := stack; |
program.vmajor := vmajor; |
program.vminor := vminor |
END SetParams; |
PROCEDURE PutReloc* (program: PROGRAM; opcode: INTEGER); |
VAR |
cmd: RELOC; |
BEGIN |
NEW(cmd); |
cmd.opcode := opcode; |
cmd.offset := CHL.Length(program.code); |
LISTS.push(program.rel_list, cmd) |
END PutReloc; |
PROCEDURE PutData* (program: PROGRAM; b: BYTE); |
BEGIN |
CHL.PushByte(program.data, b) |
END PutData; |
PROCEDURE get32le* (_array: CHL.BYTELIST; idx: INTEGER): INTEGER; |
VAR |
i: INTEGER; |
x: INTEGER; |
BEGIN |
x := 0; |
FOR i := 3 TO 0 BY -1 DO |
x := LSL(x, 8) + CHL.GetByte(_array, idx + i) |
END; |
IF UTILS.bit_depth = 64 THEN |
x := LSL(x, 16); |
x := LSL(x, 16); |
x := ASR(x, 16); |
x := ASR(x, 16) |
END |
RETURN x |
END get32le; |
PROCEDURE put32le* (_array: CHL.BYTELIST; idx: INTEGER; x: INTEGER); |
VAR |
i: INTEGER; |
BEGIN |
FOR i := 0 TO 3 DO |
CHL.SetByte(_array, idx + i, UTILS.Byte(x, i)) |
END |
END put32le; |
PROCEDURE PutData32LE* (program: PROGRAM; x: INTEGER); |
VAR |
i: INTEGER; |
BEGIN |
FOR i := 0 TO 3 DO |
CHL.PushByte(program.data, UTILS.Byte(x, i)) |
END |
END PutData32LE; |
PROCEDURE PutData64LE* (program: PROGRAM; x: INTEGER); |
VAR |
i: INTEGER; |
BEGIN |
FOR i := 0 TO 7 DO |
CHL.PushByte(program.data, UTILS.Byte(x, i)) |
END |
END PutData64LE; |
PROCEDURE PutDataStr* (program: PROGRAM; s: ARRAY OF CHAR); |
VAR |
i: INTEGER; |
BEGIN |
i := 0; |
WHILE s[i] # 0X DO |
PutData(program, ORD(s[i])); |
INC(i) |
END |
END PutDataStr; |
PROCEDURE PutCode* (program: PROGRAM; b: BYTE); |
BEGIN |
CHL.PushByte(program.code, b) |
END PutCode; |
PROCEDURE PutCode32LE* (program: PROGRAM; x: INTEGER); |
VAR |
i: INTEGER; |
BEGIN |
FOR i := 0 TO 3 DO |
CHL.PushByte(program.code, UTILS.Byte(x, i)) |
END |
END PutCode32LE; |
PROCEDURE PutCode16LE* (program: PROGRAM; x: INTEGER); |
BEGIN |
CHL.PushByte(program.code, UTILS.Byte(x, 0)); |
CHL.PushByte(program.code, UTILS.Byte(x, 1)) |
END PutCode16LE; |
PROCEDURE SetLabel* (program: PROGRAM; label, offset: INTEGER); |
BEGIN |
CHL.SetInt(program.labels, label, offset) |
END SetLabel; |
PROCEDURE Import* (program: PROGRAM; name: ARRAY OF CHAR; label: INTEGER); |
VAR |
imp: IMPRT; |
BEGIN |
CHL.PushByte(program._import, 0); |
CHL.PushByte(program._import, 0); |
IF ODD(CHL.Length(program._import)) THEN |
CHL.PushByte(program._import, 0) |
END; |
NEW(imp); |
imp.nameoffs := CHL.PushStr(program._import, name); |
imp.label := label; |
LISTS.push(program.imp_list, imp) |
END Import; |
PROCEDURE less (bytes: CHL.BYTELIST; a, b: EXPRT): BOOLEAN; |
VAR |
i, j: INTEGER; |
BEGIN |
i := a.nameoffs; |
j := b.nameoffs; |
WHILE (CHL.GetByte(bytes, i) # 0) & (CHL.GetByte(bytes, j) # 0) & |
(CHL.GetByte(bytes, i) = CHL.GetByte(bytes, j)) DO |
INC(i); |
INC(j) |
END |
RETURN CHL.GetByte(bytes, i) < CHL.GetByte(bytes, j) |
END less; |
PROCEDURE Export* (program: PROGRAM; name: ARRAY OF CHAR; label: INTEGER); |
VAR |
exp, cur: EXPRT; |
BEGIN |
NEW(exp); |
exp.label := CHL.GetInt(program.labels, label); |
exp.nameoffs := CHL.PushStr(program.export, name); |
cur := program.exp_list.first(EXPRT); |
WHILE (cur # NIL) & less(program.export, cur, exp) DO |
cur := cur.next(EXPRT) |
END; |
IF cur # NIL THEN |
IF cur.prev # NIL THEN |
LISTS.insert(program.exp_list, cur.prev, exp) |
ELSE |
LISTS.insertL(program.exp_list, cur, exp) |
END |
ELSE |
LISTS.push(program.exp_list, exp) |
END |
END Export; |
PROCEDURE GetIProc* (program: PROGRAM; n: INTEGER): IMPRT; |
VAR |
_import, res: IMPRT; |
BEGIN |
_import := program.imp_list.first(IMPRT); |
res := NIL; |
WHILE (_import # NIL) & (n >= 0) DO |
IF _import.label # 0 THEN |
res := _import; |
DEC(n) |
END; |
_import := _import.next(IMPRT) |
END; |
ASSERT(n = -1) |
RETURN res |
END GetIProc; |
PROCEDURE GetLabel* (program: PROGRAM; label: INTEGER): INTEGER; |
RETURN CHL.GetInt(program.labels, label) |
END GetLabel; |
PROCEDURE NewLabel* (program: PROGRAM); |
BEGIN |
CHL.PushInt(program.labels, 0) |
END NewLabel; |
PROCEDURE fixup* (program: PROGRAM); |
VAR |
rel: RELOC; |
imp: IMPRT; |
nproc: INTEGER; |
L: INTEGER; |
BEGIN |
nproc := 0; |
imp := program.imp_list.first(IMPRT); |
WHILE imp # NIL DO |
IF imp.label # 0 THEN |
CHL.SetInt(program.labels, imp.label, nproc); |
INC(nproc) |
END; |
imp := imp.next(IMPRT) |
END; |
rel := program.rel_list.first(RELOC); |
WHILE rel # NIL DO |
IF rel.opcode IN {RIMP, PICIMP} THEN |
L := get32le(program.code, rel.offset); |
put32le(program.code, rel.offset, GetLabel(program, L)) |
END; |
rel := rel.next(RELOC) |
END |
END fixup; |
PROCEDURE InitArray* (VAR _array: ARRAY OF BYTE; VAR idx: INTEGER; hex: ARRAY OF CHAR); |
VAR |
i, k: INTEGER; |
PROCEDURE hexdgt (dgt: CHAR): INTEGER; |
VAR |
res: INTEGER; |
BEGIN |
IF dgt < "A" THEN |
res := ORD(dgt) - ORD("0") |
ELSE |
res := ORD(dgt) - ORD("A") + 10 |
END |
RETURN res |
END hexdgt; |
BEGIN |
k := LENGTH(hex); |
ASSERT(~ODD(k)); |
k := k DIV 2; |
FOR i := 0 TO k - 1 DO |
_array[i + idx] := hexdgt(hex[2 * i]) * 16 + hexdgt(hex[2 * i + 1]) |
END; |
INC(idx, k) |
END InitArray; |
END BIN. |
/programs/develop/oberon07/source/HEX.ob07 |
---|
0,0 → 1,117 |
(* |
BSD 2-Clause License |
Copyright (c) 2020, Anton Krotov |
All rights reserved. |
*) |
MODULE HEX; |
IMPORT WRITER, CHL := CHUNKLISTS, UTILS; |
VAR |
chksum: INTEGER; |
PROCEDURE Byte (byte: BYTE); |
BEGIN |
WRITER.WriteByte(UTILS.hexdgt(byte DIV 16)); |
WRITER.WriteByte(UTILS.hexdgt(byte MOD 16)); |
INC(chksum, byte) |
END Byte; |
PROCEDURE Byte4 (a, b, c, d: BYTE); |
BEGIN |
Byte(a); |
Byte(b); |
Byte(c); |
Byte(d) |
END Byte4; |
PROCEDURE NewLine; |
BEGIN |
Byte((-chksum) MOD 256); |
chksum := 0; |
WRITER.WriteByte(0DH); |
WRITER.WriteByte(0AH) |
END NewLine; |
PROCEDURE StartCode; |
BEGIN |
WRITER.WriteByte(ORD(":")); |
chksum := 0 |
END StartCode; |
PROCEDURE Data* (mem: ARRAY OF BYTE; idx, cnt: INTEGER); |
VAR |
i, len: INTEGER; |
BEGIN |
WHILE cnt > 0 DO |
len := MIN(cnt, 16); |
StartCode; |
Byte4(len, idx DIV 256, idx MOD 256, 0); |
FOR i := 1 TO len DO |
Byte(mem[idx]); |
INC(idx) |
END; |
DEC(cnt, len); |
NewLine |
END |
END Data; |
PROCEDURE ExtLA* (LA: INTEGER); |
BEGIN |
ASSERT((0 <= LA) & (LA <= 0FFFFH)); |
StartCode; |
Byte4(2, 0, 0, 4); |
Byte(LA DIV 256); |
Byte(LA MOD 256); |
NewLine |
END ExtLA; |
PROCEDURE Data2* (mem: CHL.BYTELIST; idx, cnt, LA: INTEGER); |
VAR |
i, len, offset: INTEGER; |
BEGIN |
ExtLA(LA); |
offset := 0; |
WHILE cnt > 0 DO |
ASSERT(offset <= 65536); |
IF offset = 65536 THEN |
INC(LA); |
ExtLA(LA); |
offset := 0 |
END; |
len := MIN(cnt, 16); |
StartCode; |
Byte4(len, offset DIV 256, offset MOD 256, 0); |
FOR i := 1 TO len DO |
Byte(CHL.GetByte(mem, idx)); |
INC(idx); |
INC(offset) |
END; |
DEC(cnt, len); |
NewLine |
END |
END Data2; |
PROCEDURE End*; |
BEGIN |
StartCode; |
Byte4(0, 0, 0, 1); |
NewLine |
END End; |
END HEX. |
/programs/develop/oberon07/source/KOS.ob07 |
---|
0,0 → 1,206 |
(* |
BSD 2-Clause License |
Copyright (c) 2018-2020, Anton Krotov |
All rights reserved. |
*) |
MODULE KOS; |
IMPORT BIN, WR := WRITER, LISTS, CHL := CHUNKLISTS; |
CONST |
HEADER_SIZE = 36; |
SIZE_OF_DWORD = 4; |
TYPE |
HEADER = RECORD |
menuet01: ARRAY 9 OF CHAR; |
ver, start, size, mem, sp, param, path: INTEGER |
END; |
PROCEDURE Import* (program: BIN.PROGRAM; idata: INTEGER; VAR ImportTable: CHL.INTLIST; VAR len, libcount, size: INTEGER); |
VAR |
i: INTEGER; |
imp: BIN.IMPRT; |
BEGIN |
libcount := 0; |
imp := program.imp_list.first(BIN.IMPRT); |
WHILE imp # NIL DO |
IF imp.label = 0 THEN |
INC(libcount) |
END; |
imp := imp.next(BIN.IMPRT) |
END; |
len := libcount * 2 + 2; |
size := (LISTS.count(program.imp_list) + len + 1) * SIZE_OF_DWORD; |
ImportTable := CHL.CreateIntList(); |
FOR i := 0 TO size DIV SIZE_OF_DWORD - 1 DO |
CHL.PushInt(ImportTable, 0) |
END; |
i := 0; |
imp := program.imp_list.first(BIN.IMPRT); |
WHILE imp # NIL DO |
IF imp.label = 0 THEN |
CHL.SetInt(ImportTable, len, 0); |
INC(len); |
CHL.SetInt(ImportTable, i, idata + len * SIZE_OF_DWORD); |
INC(i); |
CHL.SetInt(ImportTable, i, imp.nameoffs + size + idata); |
INC(i) |
ELSE |
CHL.SetInt(ImportTable, len, imp.nameoffs + size + idata); |
imp.label := len * SIZE_OF_DWORD; |
INC(len) |
END; |
imp := imp.next(BIN.IMPRT) |
END; |
CHL.SetInt(ImportTable, len, 0); |
CHL.SetInt(ImportTable, i, 0); |
CHL.SetInt(ImportTable, i + 1, 0); |
INC(len); |
INC(size, CHL.Length(program._import)) |
END Import; |
PROCEDURE write* (program: BIN.PROGRAM; FileName: ARRAY OF CHAR); |
CONST |
PARAM_SIZE = 2048; |
FileAlignment = 16; |
VAR |
header: HEADER; |
base, text, data, idata, bss, offset: INTEGER; |
reloc: BIN.RELOC; |
iproc: BIN.IMPRT; |
L: INTEGER; |
delta: INTEGER; |
i: INTEGER; |
ImportTable: CHL.INTLIST; |
ILen, libcount, isize: INTEGER; |
icount, dcount, ccount: INTEGER; |
code: CHL.BYTELIST; |
BEGIN |
base := 0; |
icount := CHL.Length(program._import); |
dcount := CHL.Length(program.data); |
ccount := CHL.Length(program.code); |
text := base + HEADER_SIZE; |
data := WR.align(text + ccount, FileAlignment); |
idata := WR.align(data + dcount, FileAlignment); |
Import(program, idata, ImportTable, ILen, libcount, isize); |
bss := WR.align(idata + isize, FileAlignment); |
header.menuet01 := "MENUET01"; |
header.ver := 1; |
header.start := text; |
header.size := idata + isize - base; |
header.mem := WR.align(header.size + program.stack + program.bss + PARAM_SIZE * 2 + 4096, FileAlignment); |
header.sp := base + header.mem - PARAM_SIZE * 2; |
header.param := header.sp; |
header.path := header.param + PARAM_SIZE; |
code := program.code; |
reloc := program.rel_list.first(BIN.RELOC); |
WHILE reloc # NIL DO |
offset := reloc.offset; |
L := BIN.get32le(code, offset); |
delta := 3 - offset - text; |
CASE reloc.opcode OF |
|BIN.RIMP: |
iproc := BIN.GetIProc(program, L); |
delta := idata + iproc.label |
|BIN.RBSS: |
delta := L + bss |
|BIN.RDATA: |
delta := L + data |
|BIN.RCODE: |
delta := BIN.GetLabel(program, L) + text |
|BIN.PICDATA: |
INC(delta, L + data) |
|BIN.PICCODE: |
INC(delta, BIN.GetLabel(program, L) + text) |
|BIN.PICBSS: |
INC(delta, L + bss) |
|BIN.PICIMP: |
iproc := BIN.GetIProc(program, L); |
INC(delta, idata + iproc.label) |
|BIN.IMPTAB: |
INC(delta, idata) |
END; |
BIN.put32le(code, offset, delta); |
reloc := reloc.next(BIN.RELOC) |
END; |
WR.Create(FileName); |
FOR i := 0 TO 7 DO |
WR.WriteByte(ORD(header.menuet01[i])) |
END; |
WR.Write32LE(header.ver); |
WR.Write32LE(header.start); |
WR.Write32LE(header.size); |
WR.Write32LE(header.mem); |
WR.Write32LE(header.sp); |
WR.Write32LE(header.param); |
WR.Write32LE(header.path); |
CHL.WriteToFile(code); |
WR.Padding(FileAlignment); |
CHL.WriteToFile(program.data); |
WR.Padding(FileAlignment); |
FOR i := 0 TO ILen - 1 DO |
WR.Write32LE(CHL.GetInt(ImportTable, i)) |
END; |
CHL.WriteToFile(program._import); |
WR.Close |
END write; |
END KOS. |
/programs/develop/oberon07/source/MSCOFF.ob07 |
---|
0,0 → 1,309 |
(* |
BSD 2-Clause License |
Copyright (c) 2018-2020, Anton Krotov |
All rights reserved. |
*) |
MODULE MSCOFF; |
IMPORT BIN, PE32, KOS, WR := WRITER, UTILS, ERRORS, LISTS, CHL := CHUNKLISTS; |
CONST |
SIZE_OF_DWORD = 4; |
(* SectionHeader.Characteristics *) |
SHC_flat = 040500020H; |
SHC_data = 0C0500040H; |
SHC_bss = 0C03000C0H; |
TYPE |
FH = PE32.IMAGE_FILE_HEADER; |
SH = PE32.IMAGE_SECTION_HEADER; |
PROCEDURE WriteReloc (VirtualAddress, SymbolTableIndex, Type: INTEGER); |
BEGIN |
WR.Write32LE(VirtualAddress); |
WR.Write32LE(SymbolTableIndex); |
WR.Write16LE(Type) |
END WriteReloc; |
PROCEDURE Reloc (program: BIN.PROGRAM); |
VAR |
reloc: BIN.RELOC; |
offset: INTEGER; |
BEGIN |
reloc := program.rel_list.first(BIN.RELOC); |
WHILE reloc # NIL DO |
offset := reloc.offset; |
CASE reloc.opcode OF |
|BIN.RIMP, |
BIN.IMPTAB: WriteReloc(offset, 4, 6) |
|BIN.RBSS: WriteReloc(offset, 5, 6) |
|BIN.RDATA: WriteReloc(offset, 2, 6) |
|BIN.RCODE: WriteReloc(offset, 1, 6) |
END; |
reloc := reloc.next(BIN.RELOC) |
END; |
END Reloc; |
PROCEDURE RelocCount (program: BIN.PROGRAM): INTEGER; |
VAR |
reloc: BIN.RELOC; |
iproc: BIN.IMPRT; |
res, L: INTEGER; |
offset: INTEGER; |
code: CHL.BYTELIST; |
BEGIN |
res := 0; |
code := program.code; |
reloc := program.rel_list.first(BIN.RELOC); |
WHILE reloc # NIL DO |
INC(res); |
offset := reloc.offset; |
IF reloc.opcode = BIN.RIMP THEN |
L := BIN.get32le(code, offset); |
iproc := BIN.GetIProc(program, L); |
BIN.put32le(code, offset, iproc.label) |
END; |
IF reloc.opcode = BIN.RCODE THEN |
L := BIN.get32le(code, offset); |
BIN.put32le(code, offset, BIN.GetLabel(program, L)) |
END; |
reloc := reloc.next(BIN.RELOC) |
END |
RETURN res |
END RelocCount; |
PROCEDURE write* (program: BIN.PROGRAM; FileName: ARRAY OF CHAR; ver: INTEGER); |
VAR |
exp: BIN.EXPRT; |
n, i: INTEGER; |
szversion: PE32.NAME; |
ImportTable: CHL.INTLIST; |
ILen, LibCount, isize: INTEGER; |
ExpCount: INTEGER; |
icount, ecount, dcount, ccount: INTEGER; |
FileHeader: FH; |
flat, data, edata, idata, bss: SH; |
PROCEDURE ICount (ImportTable: CHL.INTLIST; ILen: INTEGER): INTEGER; |
VAR |
i, res: INTEGER; |
BEGIN |
res := 0; |
FOR i := 0 TO ILen - 1 DO |
IF CHL.GetInt(ImportTable, i) # 0 THEN |
INC(res) |
END |
END |
RETURN res |
END ICount; |
PROCEDURE SetNumberOfRelocations (VAR section: SH; NumberOfRelocations: INTEGER); |
BEGIN |
IF NumberOfRelocations >= 65536 THEN |
ERRORS.Error(202) |
END; |
section.NumberOfRelocations := WCHR(NumberOfRelocations) |
END SetNumberOfRelocations; |
BEGIN |
szversion := "version"; |
ASSERT(LENGTH(szversion) = 7); |
KOS.Import(program, 0, ImportTable, ILen, LibCount, isize); |
ExpCount := LISTS.count(program.exp_list); |
icount := CHL.Length(program._import); |
dcount := CHL.Length(program.data); |
ccount := CHL.Length(program.code); |
ecount := CHL.Length(program.export); |
FileHeader.Machine := 014CX; |
FileHeader.NumberOfSections := 5X; |
FileHeader.TimeDateStamp := UTILS.UnixTime(); |
(* FileHeader.PointerToSymbolTable := 0; *) |
FileHeader.NumberOfSymbols := 6; |
FileHeader.SizeOfOptionalHeader := 0X; |
FileHeader.Characteristics := 0184X; |
flat.Name := ".flat"; |
flat.VirtualSize := 0; |
flat.VirtualAddress := 0; |
flat.SizeOfRawData := ccount; |
flat.PointerToRawData := ORD(FileHeader.NumberOfSections) * PE32.SIZE_OF_IMAGE_SECTION_HEADER + PE32.SIZE_OF_IMAGE_FILE_HEADER; |
(* flat.PointerToRelocations := 0; *) |
flat.PointerToLinenumbers := 0; |
SetNumberOfRelocations(flat, RelocCount(program)); |
flat.NumberOfLinenumbers := 0X; |
flat.Characteristics := SHC_flat; |
data.Name := ".data"; |
data.VirtualSize := 0; |
data.VirtualAddress := 0; |
data.SizeOfRawData := dcount; |
data.PointerToRawData := flat.PointerToRawData + flat.SizeOfRawData; |
data.PointerToRelocations := 0; |
data.PointerToLinenumbers := 0; |
data.NumberOfRelocations := 0X; |
data.NumberOfLinenumbers := 0X; |
data.Characteristics := SHC_data; |
edata.Name := ".edata"; |
edata.VirtualSize := 0; |
edata.VirtualAddress := 0; |
edata.SizeOfRawData := ((ExpCount + 1) * 2 + 1) * SIZE_OF_DWORD + LENGTH(szversion) + 1 + ecount; |
edata.PointerToRawData := data.PointerToRawData + data.SizeOfRawData; |
(* edata.PointerToRelocations := 0; *) |
edata.PointerToLinenumbers := 0; |
SetNumberOfRelocations(edata, ExpCount * 2 + 1); |
edata.NumberOfLinenumbers := 0X; |
edata.Characteristics := SHC_data; |
idata.Name := ".idata"; |
idata.VirtualSize := 0; |
idata.VirtualAddress := 0; |
idata.SizeOfRawData := isize; |
idata.PointerToRawData := edata.PointerToRawData + edata.SizeOfRawData; |
(* idata.PointerToRelocations := 0; *) |
idata.PointerToLinenumbers := 0; |
SetNumberOfRelocations(idata, ICount(ImportTable, ILen)); |
idata.NumberOfLinenumbers := 0X; |
idata.Characteristics := SHC_data; |
bss.Name := ".bss"; |
bss.VirtualSize := 0; |
bss.VirtualAddress := 0; |
bss.SizeOfRawData := program.bss; |
bss.PointerToRawData := 0; |
bss.PointerToRelocations := 0; |
bss.PointerToLinenumbers := 0; |
bss.NumberOfRelocations := 0X; |
bss.NumberOfLinenumbers := 0X; |
bss.Characteristics := SHC_bss; |
flat.PointerToRelocations := idata.PointerToRawData + idata.SizeOfRawData; |
edata.PointerToRelocations := flat.PointerToRelocations + ORD(flat.NumberOfRelocations) * 10; |
idata.PointerToRelocations := edata.PointerToRelocations + ORD(edata.NumberOfRelocations) * 10; |
FileHeader.PointerToSymbolTable := idata.PointerToRelocations + ORD(idata.NumberOfRelocations) * 10; |
WR.Create(FileName); |
PE32.WriteFileHeader(FileHeader); |
PE32.WriteSectionHeader(flat); |
PE32.WriteSectionHeader(data); |
PE32.WriteSectionHeader(edata); |
PE32.WriteSectionHeader(idata); |
PE32.WriteSectionHeader(bss); |
CHL.WriteToFile(program.code); |
CHL.WriteToFile(program.data); |
exp := program.exp_list.first(BIN.EXPRT); |
WHILE exp # NIL DO |
WR.Write32LE(exp.nameoffs + edata.SizeOfRawData - ecount); |
WR.Write32LE(exp.label); |
exp := exp.next(BIN.EXPRT) |
END; |
WR.Write32LE(((ExpCount + 1) * 2 + 1) * SIZE_OF_DWORD); |
WR.Write32LE(ver); |
WR.Write32LE(0); |
PE32.WriteName(szversion); |
CHL.WriteToFile(program.export); |
FOR i := 0 TO ILen - 1 DO |
WR.Write32LE(CHL.GetInt(ImportTable, i)) |
END; |
CHL.WriteToFile(program._import); |
Reloc(program); |
n := 0; |
exp := program.exp_list.first(BIN.EXPRT); |
WHILE exp # NIL DO |
WriteReloc(n, 3, 6); |
INC(n, 4); |
WriteReloc(n, 1, 6); |
INC(n, 4); |
exp := exp.next(BIN.EXPRT) |
END; |
WriteReloc(n, 3, 6); |
FOR i := 0 TO LibCount * 2 - 1 DO |
WriteReloc(i * SIZE_OF_DWORD, 4, 6) |
END; |
FOR i := LibCount * 2 TO ILen - 1 DO |
IF CHL.GetInt(ImportTable, i) # 0 THEN |
WriteReloc(i * SIZE_OF_DWORD, 4, 6) |
END |
END; |
PE32.WriteName("EXPORTS"); |
WriteReloc(0, 3, 2); |
PE32.WriteName(".flat"); |
WriteReloc(0, 1, 3); |
PE32.WriteName(".data"); |
WriteReloc(0, 2, 3); |
PE32.WriteName(".edata"); |
WriteReloc(0, 3, 3); |
PE32.WriteName(".idata"); |
WriteReloc(0, 4, 3); |
PE32.WriteName(".bss"); |
WriteReloc(0, 5, 3); |
WR.Write32LE(4); |
WR.Close |
END write; |
END MSCOFF. |
/programs/develop/oberon07/source/PE32.ob07 |
---|
0,0 → 1,695 |
(* |
BSD 2-Clause License |
Copyright (c) 2018-2020, Anton Krotov |
All rights reserved. |
*) |
MODULE PE32; |
IMPORT BIN, LISTS, UTILS, WR := WRITER, CHL := CHUNKLISTS; |
CONST |
SIZE_OF_DWORD = 4; |
SIZE_OF_WORD = 2; |
SIZE_OF_IMAGE_EXPORT_DIRECTORY = 40; |
IMAGE_NUMBEROF_DIRECTORY_ENTRIES = 16; |
IMAGE_SIZEOF_SHORT_NAME = 8; |
SIZE_OF_IMAGE_FILE_HEADER* = 20; |
SIZE_OF_IMAGE_SECTION_HEADER* = 40; |
(* SectionHeader.Characteristics *) |
SHC_text = 060000020H; |
SHC_data = 040000040H; |
SHC_bss = 0C0000080H; |
SectionAlignment = 1000H; |
FileAlignment = 200H; |
TYPE |
WORD = WCHAR; |
DWORD = INTEGER; |
NAME* = ARRAY IMAGE_SIZEOF_SHORT_NAME OF CHAR; |
IMAGE_DATA_DIRECTORY = RECORD |
VirtualAddress: DWORD; |
Size: DWORD |
END; |
IMAGE_OPTIONAL_HEADER = RECORD |
Magic: WORD; |
MajorLinkerVersion: BYTE; |
MinorLinkerVersion: BYTE; |
SizeOfCode: DWORD; |
SizeOfInitializedData: DWORD; |
SizeOfUninitializedData: DWORD; |
AddressOfEntryPoint: DWORD; |
BaseOfCode: DWORD; |
BaseOfData: DWORD; |
ImageBase: DWORD; |
SectionAlignment: DWORD; |
FileAlignment: DWORD; |
MajorOperatingSystemVersion: WORD; |
MinorOperatingSystemVersion: WORD; |
MajorImageVersion: WORD; |
MinorImageVersion: WORD; |
MajorSubsystemVersion: WORD; |
MinorSubsystemVersion: WORD; |
Win32VersionValue: DWORD; |
SizeOfImage: DWORD; |
SizeOfHeaders: DWORD; |
CheckSum: DWORD; |
Subsystem: WORD; |
DllCharacteristics: WORD; |
SizeOfStackReserve: DWORD; |
SizeOfStackCommit: DWORD; |
SizeOfHeapReserve: DWORD; |
SizeOfHeapCommit: DWORD; |
LoaderFlags: DWORD; |
NumberOfRvaAndSizes: DWORD; |
DataDirectory: ARRAY IMAGE_NUMBEROF_DIRECTORY_ENTRIES OF IMAGE_DATA_DIRECTORY |
END; |
IMAGE_FILE_HEADER* = RECORD |
Machine*: WORD; |
NumberOfSections*: WORD; |
TimeDateStamp*: DWORD; |
PointerToSymbolTable*: DWORD; |
NumberOfSymbols*: DWORD; |
SizeOfOptionalHeader*: WORD; |
Characteristics*: WORD |
END; |
IMAGE_SECTION_HEADER* = RECORD |
Name*: NAME; |
VirtualSize*, |
VirtualAddress*, |
SizeOfRawData*, |
PointerToRawData*, |
PointerToRelocations*, |
PointerToLinenumbers*: DWORD; |
NumberOfRelocations*, |
NumberOfLinenumbers*: WORD; |
Characteristics*: DWORD |
END; |
IMAGE_EXPORT_DIRECTORY = RECORD |
Characteristics: DWORD; |
TimeDateStamp: DWORD; |
MajorVersion: WORD; |
MinorVersion: WORD; |
Name, |
Base, |
NumberOfFunctions, |
NumberOfNames, |
AddressOfFunctions, |
AddressOfNames, |
AddressOfNameOrdinals: DWORD |
END; |
VIRTUAL_ADDR* = RECORD |
Code*, Data*, Bss*, Import*: INTEGER |
END; |
VAR |
Signature: ARRAY 4 OF BYTE; |
FileHeader: IMAGE_FILE_HEADER; |
OptionalHeader: IMAGE_OPTIONAL_HEADER; |
msdos: ARRAY 128 OF BYTE; |
SectionHeaders: ARRAY 16 OF IMAGE_SECTION_HEADER; |
libcnt: INTEGER; |
SizeOfWord: INTEGER; |
PROCEDURE Export (program: BIN.PROGRAM; name: INTEGER; VAR ExportDir: IMAGE_EXPORT_DIRECTORY): INTEGER; |
BEGIN |
ExportDir.Characteristics := 0; |
ExportDir.TimeDateStamp := FileHeader.TimeDateStamp; |
ExportDir.MajorVersion := 0X; |
ExportDir.MinorVersion := 0X; |
ExportDir.Name := name; |
ExportDir.Base := 0; |
ExportDir.NumberOfFunctions := LISTS.count(program.exp_list); |
ExportDir.NumberOfNames := ExportDir.NumberOfFunctions; |
ExportDir.AddressOfFunctions := SIZE_OF_IMAGE_EXPORT_DIRECTORY; |
ExportDir.AddressOfNames := ExportDir.AddressOfFunctions + ExportDir.NumberOfFunctions * SIZE_OF_DWORD; |
ExportDir.AddressOfNameOrdinals := ExportDir.AddressOfNames + ExportDir.NumberOfFunctions * SIZE_OF_DWORD |
RETURN SIZE_OF_IMAGE_EXPORT_DIRECTORY + ExportDir.NumberOfFunctions * (2 * SIZE_OF_DWORD + SIZE_OF_WORD) |
END Export; |
PROCEDURE GetProcCount (lib: BIN.IMPRT): INTEGER; |
VAR |
imp: BIN.IMPRT; |
res: INTEGER; |
BEGIN |
res := 0; |
imp := lib.next(BIN.IMPRT); |
WHILE (imp # NIL) & (imp.label # 0) DO |
INC(res); |
imp := imp.next(BIN.IMPRT) |
END |
RETURN res |
END GetProcCount; |
PROCEDURE GetImportSize (imp_list: LISTS.LIST): INTEGER; |
VAR |
imp: BIN.IMPRT; |
proccnt: INTEGER; |
procoffs: INTEGER; |
OriginalCurrentThunk, |
CurrentThunk: INTEGER; |
BEGIN |
libcnt := 0; |
proccnt := 0; |
imp := imp_list.first(BIN.IMPRT); |
WHILE imp # NIL DO |
IF imp.label = 0 THEN |
INC(libcnt) |
ELSE |
INC(proccnt) |
END; |
imp := imp.next(BIN.IMPRT) |
END; |
procoffs := 0; |
imp := imp_list.first(BIN.IMPRT); |
WHILE imp # NIL DO |
IF imp.label = 0 THEN |
imp.OriginalFirstThunk := procoffs; |
imp.FirstThunk := procoffs + (GetProcCount(imp) + 1); |
OriginalCurrentThunk := imp.OriginalFirstThunk; |
CurrentThunk := imp.FirstThunk; |
INC(procoffs, (GetProcCount(imp) + 1) * 2) |
ELSE |
imp.OriginalFirstThunk := OriginalCurrentThunk; |
imp.FirstThunk := CurrentThunk; |
INC(OriginalCurrentThunk); |
INC(CurrentThunk) |
END; |
imp := imp.next(BIN.IMPRT) |
END |
RETURN (libcnt + 1) * 5 * SIZE_OF_DWORD + (proccnt + libcnt) * 2 * SizeOfWord |
END GetImportSize; |
PROCEDURE fixup* (program: BIN.PROGRAM; Address: VIRTUAL_ADDR; amd64: BOOLEAN); |
VAR |
reloc: BIN.RELOC; |
iproc: BIN.IMPRT; |
code: CHL.BYTELIST; |
L, delta, delta0, AdrImp, offset: INTEGER; |
BEGIN |
AdrImp := Address.Import + (libcnt + 1) * 5 * SIZE_OF_DWORD; |
code := program.code; |
reloc := program.rel_list.first(BIN.RELOC); |
delta0 := 3 - 7 * ORD(amd64) - Address.Code; |
WHILE reloc # NIL DO |
offset := reloc.offset; |
L := BIN.get32le(code, offset); |
delta := delta0 - offset; |
CASE reloc.opcode OF |
|BIN.PICDATA: |
INC(delta, L + Address.Data) |
|BIN.PICCODE: |
INC(delta, BIN.GetLabel(program, L) + Address.Code) |
|BIN.PICBSS: |
INC(delta, L + Address.Bss) |
|BIN.PICIMP: |
iproc := BIN.GetIProc(program, L); |
INC(delta, iproc.FirstThunk * SizeOfWord + AdrImp) |
END; |
BIN.put32le(code, offset, delta); |
reloc := reloc.next(BIN.RELOC) |
END |
END fixup; |
PROCEDURE WriteWord (w: WORD); |
BEGIN |
WR.Write16LE(ORD(w)) |
END WriteWord; |
PROCEDURE WriteName* (name: NAME); |
VAR |
i, nameLen: INTEGER; |
BEGIN |
nameLen := LENGTH(name); |
FOR i := 0 TO nameLen - 1 DO |
WR.WriteByte(ORD(name[i])) |
END; |
i := LEN(name) - nameLen; |
WHILE i > 0 DO |
WR.WriteByte(0); |
DEC(i) |
END |
END WriteName; |
PROCEDURE WriteSectionHeader* (h: IMAGE_SECTION_HEADER); |
VAR |
i, nameLen: INTEGER; |
BEGIN |
nameLen := LENGTH(h.Name); |
FOR i := 0 TO nameLen - 1 DO |
WR.WriteByte(ORD(h.Name[i])) |
END; |
i := LEN(h.Name) - nameLen; |
WHILE i > 0 DO |
WR.WriteByte(0); |
DEC(i) |
END; |
WR.Write32LE(h.VirtualSize); |
WR.Write32LE(h.VirtualAddress); |
WR.Write32LE(h.SizeOfRawData); |
WR.Write32LE(h.PointerToRawData); |
WR.Write32LE(h.PointerToRelocations); |
WR.Write32LE(h.PointerToLinenumbers); |
WriteWord(h.NumberOfRelocations); |
WriteWord(h.NumberOfLinenumbers); |
WR.Write32LE(h.Characteristics) |
END WriteSectionHeader; |
PROCEDURE WriteFileHeader* (h: IMAGE_FILE_HEADER); |
BEGIN |
WriteWord(h.Machine); |
WriteWord(h.NumberOfSections); |
WR.Write32LE(h.TimeDateStamp); |
WR.Write32LE(h.PointerToSymbolTable); |
WR.Write32LE(h.NumberOfSymbols); |
WriteWord(h.SizeOfOptionalHeader); |
WriteWord(h.Characteristics) |
END WriteFileHeader; |
PROCEDURE write* (program: BIN.PROGRAM; FileName: ARRAY OF CHAR; console, dll, amd64: BOOLEAN); |
VAR |
i, n, temp: INTEGER; |
Size: RECORD |
Code, Data, Bss, Import, Reloc, Export: INTEGER |
END; |
BaseAddress: INTEGER; |
Address: VIRTUAL_ADDR; |
_import: BIN.IMPRT; |
ImportTable: CHL.INTLIST; |
ExportDir: IMAGE_EXPORT_DIRECTORY; |
export: BIN.EXPRT; |
PROCEDURE WriteExportDir (e: IMAGE_EXPORT_DIRECTORY); |
BEGIN |
WR.Write32LE(e.Characteristics); |
WR.Write32LE(e.TimeDateStamp); |
WriteWord(e.MajorVersion); |
WriteWord(e.MinorVersion); |
WR.Write32LE(e.Name); |
WR.Write32LE(e.Base); |
WR.Write32LE(e.NumberOfFunctions); |
WR.Write32LE(e.NumberOfNames); |
WR.Write32LE(e.AddressOfFunctions); |
WR.Write32LE(e.AddressOfNames); |
WR.Write32LE(e.AddressOfNameOrdinals) |
END WriteExportDir; |
PROCEDURE WriteOptHeader (h: IMAGE_OPTIONAL_HEADER; amd64: BOOLEAN); |
VAR |
i: INTEGER; |
BEGIN |
WriteWord(h.Magic); |
WR.WriteByte(h.MajorLinkerVersion); |
WR.WriteByte(h.MinorLinkerVersion); |
WR.Write32LE(h.SizeOfCode); |
WR.Write32LE(h.SizeOfInitializedData); |
WR.Write32LE(h.SizeOfUninitializedData); |
WR.Write32LE(h.AddressOfEntryPoint); |
WR.Write32LE(h.BaseOfCode); |
IF amd64 THEN |
WR.Write64LE(h.ImageBase) |
ELSE |
WR.Write32LE(h.BaseOfData); |
WR.Write32LE(h.ImageBase) |
END; |
WR.Write32LE(h.SectionAlignment); |
WR.Write32LE(h.FileAlignment); |
WriteWord(h.MajorOperatingSystemVersion); |
WriteWord(h.MinorOperatingSystemVersion); |
WriteWord(h.MajorImageVersion); |
WriteWord(h.MinorImageVersion); |
WriteWord(h.MajorSubsystemVersion); |
WriteWord(h.MinorSubsystemVersion); |
WR.Write32LE(h.Win32VersionValue); |
WR.Write32LE(h.SizeOfImage); |
WR.Write32LE(h.SizeOfHeaders); |
WR.Write32LE(h.CheckSum); |
WriteWord(h.Subsystem); |
WriteWord(h.DllCharacteristics); |
IF amd64 THEN |
WR.Write64LE(h.SizeOfStackReserve); |
WR.Write64LE(h.SizeOfStackCommit); |
WR.Write64LE(h.SizeOfHeapReserve); |
WR.Write64LE(h.SizeOfHeapCommit) |
ELSE |
WR.Write32LE(h.SizeOfStackReserve); |
WR.Write32LE(h.SizeOfStackCommit); |
WR.Write32LE(h.SizeOfHeapReserve); |
WR.Write32LE(h.SizeOfHeapCommit) |
END; |
WR.Write32LE(h.LoaderFlags); |
WR.Write32LE(h.NumberOfRvaAndSizes); |
FOR i := 0 TO LEN(h.DataDirectory) - 1 DO |
WR.Write32LE(h.DataDirectory[i].VirtualAddress); |
WR.Write32LE(h.DataDirectory[i].Size) |
END |
END WriteOptHeader; |
PROCEDURE InitSection (VAR section: IMAGE_SECTION_HEADER; Name: NAME; VirtualSize: INTEGER; Characteristics: DWORD); |
BEGIN |
section.Name := Name; |
section.VirtualSize := VirtualSize; |
section.SizeOfRawData := WR.align(VirtualSize, FileAlignment); |
section.PointerToRelocations := 0; |
section.PointerToLinenumbers := 0; |
section.NumberOfRelocations := 0X; |
section.NumberOfLinenumbers := 0X; |
section.Characteristics := Characteristics |
END InitSection; |
BEGIN |
SizeOfWord := SIZE_OF_DWORD * (ORD(amd64) + 1); |
Size.Code := CHL.Length(program.code); |
Size.Data := CHL.Length(program.data); |
Size.Bss := program.bss; |
IF dll THEN |
BaseAddress := 10000000H |
ELSE |
BaseAddress := 400000H |
END; |
Signature[0] := 50H; |
Signature[1] := 45H; |
Signature[2] := 0; |
Signature[3] := 0; |
IF amd64 THEN |
FileHeader.Machine := 08664X |
ELSE |
FileHeader.Machine := 014CX |
END; |
FileHeader.NumberOfSections := WCHR(4 + ORD(dll)); |
FileHeader.TimeDateStamp := UTILS.UnixTime(); |
FileHeader.PointerToSymbolTable := 0H; |
FileHeader.NumberOfSymbols := 0H; |
FileHeader.SizeOfOptionalHeader := WCHR(0E0H + 10H * ORD(amd64)); |
FileHeader.Characteristics := WCHR(010EH + (20H - 100H) * ORD(amd64) + 2000H * ORD(dll)); |
OptionalHeader.Magic := WCHR(010BH + 100H * ORD(amd64)); |
OptionalHeader.MajorLinkerVersion := UTILS.vMajor; |
OptionalHeader.MinorLinkerVersion := UTILS.vMinor; |
OptionalHeader.SizeOfCode := WR.align(Size.Code, FileAlignment); |
OptionalHeader.SizeOfInitializedData := 0; |
OptionalHeader.SizeOfUninitializedData := 0; |
OptionalHeader.AddressOfEntryPoint := SectionAlignment; |
OptionalHeader.BaseOfCode := SectionAlignment; |
OptionalHeader.BaseOfData := OptionalHeader.BaseOfCode + WR.align(Size.Code, SectionAlignment); |
OptionalHeader.ImageBase := BaseAddress; |
OptionalHeader.SectionAlignment := SectionAlignment; |
OptionalHeader.FileAlignment := FileAlignment; |
OptionalHeader.MajorOperatingSystemVersion := 1X; |
OptionalHeader.MinorOperatingSystemVersion := 0X; |
OptionalHeader.MajorImageVersion := 0X; |
OptionalHeader.MinorImageVersion := 0X; |
OptionalHeader.MajorSubsystemVersion := 4X; |
OptionalHeader.MinorSubsystemVersion := 0X; |
OptionalHeader.Win32VersionValue := 0H; |
OptionalHeader.SizeOfImage := SectionAlignment; |
OptionalHeader.SizeOfHeaders := 400H; |
OptionalHeader.CheckSum := 0; |
OptionalHeader.Subsystem := WCHR((2 + ORD(console)) * ORD(~dll)); |
OptionalHeader.DllCharacteristics := 0040X; |
OptionalHeader.SizeOfStackReserve := 100000H; |
OptionalHeader.SizeOfStackCommit := 10000H; |
OptionalHeader.SizeOfHeapReserve := 100000H; |
OptionalHeader.SizeOfHeapCommit := 10000H; |
OptionalHeader.LoaderFlags := 0; |
OptionalHeader.NumberOfRvaAndSizes := IMAGE_NUMBEROF_DIRECTORY_ENTRIES; |
FOR i := 0 TO IMAGE_NUMBEROF_DIRECTORY_ENTRIES - 1 DO |
OptionalHeader.DataDirectory[i].VirtualAddress := 0; |
OptionalHeader.DataDirectory[i].Size := 0 |
END; |
InitSection(SectionHeaders[0], ".text", Size.Code, SHC_text); |
SectionHeaders[0].VirtualAddress := SectionAlignment; |
SectionHeaders[0].PointerToRawData := OptionalHeader.SizeOfHeaders; |
InitSection(SectionHeaders[1], ".data", Size.Data, SHC_data); |
SectionHeaders[1].VirtualAddress := WR.align(SectionHeaders[0].VirtualAddress + SectionHeaders[0].VirtualSize, SectionAlignment); |
SectionHeaders[1].PointerToRawData := SectionHeaders[0].PointerToRawData + SectionHeaders[0].SizeOfRawData; |
InitSection(SectionHeaders[2], ".bss", Size.Bss, SHC_bss); |
SectionHeaders[2].VirtualAddress := WR.align(SectionHeaders[1].VirtualAddress + SectionHeaders[1].VirtualSize, SectionAlignment); |
SectionHeaders[2].PointerToRawData := SectionHeaders[1].PointerToRawData + SectionHeaders[1].SizeOfRawData; |
SectionHeaders[2].SizeOfRawData := 0; |
Size.Import := GetImportSize(program.imp_list); |
InitSection(SectionHeaders[3], ".idata", Size.Import + CHL.Length(program._import), SHC_data); |
SectionHeaders[3].VirtualAddress := WR.align(SectionHeaders[2].VirtualAddress + SectionHeaders[2].VirtualSize, SectionAlignment); |
SectionHeaders[3].PointerToRawData := SectionHeaders[2].PointerToRawData + SectionHeaders[2].SizeOfRawData; |
Address.Code := SectionHeaders[0].VirtualAddress + OptionalHeader.ImageBase; |
Address.Data := SectionHeaders[1].VirtualAddress + OptionalHeader.ImageBase; |
Address.Bss := SectionHeaders[2].VirtualAddress + OptionalHeader.ImageBase; |
Address.Import := SectionHeaders[3].VirtualAddress + OptionalHeader.ImageBase; |
fixup(program, Address, amd64); |
IF dll THEN |
Size.Export := Export(program, SectionHeaders[1].VirtualAddress + program.modname, ExportDir); |
InitSection(SectionHeaders[4], ".edata", Size.Export + CHL.Length(program.export), SHC_data); |
SectionHeaders[4].VirtualAddress := WR.align(SectionHeaders[3].VirtualAddress + SectionHeaders[3].VirtualSize, SectionAlignment); |
SectionHeaders[4].PointerToRawData := SectionHeaders[3].PointerToRawData + SectionHeaders[3].SizeOfRawData; |
OptionalHeader.DataDirectory[0].VirtualAddress := SectionHeaders[4].VirtualAddress; |
OptionalHeader.DataDirectory[0].Size := SectionHeaders[4].VirtualSize |
END; |
OptionalHeader.DataDirectory[1].VirtualAddress := SectionHeaders[3].VirtualAddress; |
OptionalHeader.DataDirectory[1].Size := SectionHeaders[3].VirtualSize; |
FOR i := 1 TO ORD(FileHeader.NumberOfSections) - 1 DO |
INC(OptionalHeader.SizeOfInitializedData, SectionHeaders[i].SizeOfRawData) |
END; |
OptionalHeader.SizeOfUninitializedData := WR.align(SectionHeaders[2].VirtualSize, FileAlignment); |
FOR i := 0 TO ORD(FileHeader.NumberOfSections) - 1 DO |
INC(OptionalHeader.SizeOfImage, WR.align(SectionHeaders[i].VirtualSize, SectionAlignment)) |
END; |
n := 0; |
BIN.InitArray(msdos, n, "4D5A80000100000004001000FFFF000040010000000000004000000000000000"); |
BIN.InitArray(msdos, n, "0000000000000000000000000000000000000000000000000000000080000000"); |
BIN.InitArray(msdos, n, "0E1FBA0E00B409CD21B8014CCD21546869732070726F6772616D2063616E6E6F"); |
BIN.InitArray(msdos, n, "742062652072756E20696E20444F53206D6F64652E0D0A240000000000000000"); |
WR.Create(FileName); |
WR.Write(msdos, LEN(msdos)); |
WR.Write(Signature, LEN(Signature)); |
WriteFileHeader(FileHeader); |
WriteOptHeader(OptionalHeader, amd64); |
FOR i := 0 TO ORD(FileHeader.NumberOfSections) - 1 DO |
WriteSectionHeader(SectionHeaders[i]) |
END; |
WR.Padding(FileAlignment); |
CHL.WriteToFile(program.code); |
WR.Padding(FileAlignment); |
CHL.WriteToFile(program.data); |
WR.Padding(FileAlignment); |
n := (libcnt + 1) * 5; |
ImportTable := CHL.CreateIntList(); |
FOR i := 0 TO (Size.Import - n * SIZE_OF_DWORD) DIV SizeOfWord + n - 1 DO |
CHL.PushInt(ImportTable, 0) |
END; |
i := 0; |
_import := program.imp_list.first(BIN.IMPRT); |
WHILE _import # NIL DO |
IF _import.label = 0 THEN |
CHL.SetInt(ImportTable, i + 0, _import.OriginalFirstThunk * SizeOfWord + SectionHeaders[3].VirtualAddress + n * SIZE_OF_DWORD); |
CHL.SetInt(ImportTable, i + 1, 0); |
CHL.SetInt(ImportTable, i + 2, 0); |
CHL.SetInt(ImportTable, i + 3, _import.nameoffs + Size.Import + SectionHeaders[3].VirtualAddress); |
CHL.SetInt(ImportTable, i + 4, _import.FirstThunk * SizeOfWord + SectionHeaders[3].VirtualAddress + n * SIZE_OF_DWORD); |
INC(i, 5) |
END; |
_import := _import.next(BIN.IMPRT) |
END; |
CHL.SetInt(ImportTable, i + 0, 0); |
CHL.SetInt(ImportTable, i + 1, 0); |
CHL.SetInt(ImportTable, i + 2, 0); |
CHL.SetInt(ImportTable, i + 3, 0); |
CHL.SetInt(ImportTable, i + 4, 0); |
_import := program.imp_list.first(BIN.IMPRT); |
WHILE _import # NIL DO |
IF _import.label # 0 THEN |
temp := _import.nameoffs + Size.Import + SectionHeaders[3].VirtualAddress - 2; |
CHL.SetInt(ImportTable, _import.OriginalFirstThunk + n, temp); |
CHL.SetInt(ImportTable, _import.FirstThunk + n, temp) |
END; |
_import := _import.next(BIN.IMPRT) |
END; |
FOR i := 0 TO n - 1 DO |
WR.Write32LE(CHL.GetInt(ImportTable, i)) |
END; |
FOR i := n TO CHL.Length(ImportTable) - 1 DO |
IF amd64 THEN |
WR.Write64LE(CHL.GetInt(ImportTable, i)) |
ELSE |
WR.Write32LE(CHL.GetInt(ImportTable, i)) |
END |
END; |
CHL.WriteToFile(program._import); |
WR.Padding(FileAlignment); |
IF dll THEN |
INC(ExportDir.AddressOfFunctions, SectionHeaders[4].VirtualAddress); |
INC(ExportDir.AddressOfNames, SectionHeaders[4].VirtualAddress); |
INC(ExportDir.AddressOfNameOrdinals, SectionHeaders[4].VirtualAddress); |
WriteExportDir(ExportDir); |
export := program.exp_list.first(BIN.EXPRT); |
WHILE export # NIL DO |
WR.Write32LE(export.label + SectionHeaders[0].VirtualAddress); |
export := export.next(BIN.EXPRT) |
END; |
export := program.exp_list.first(BIN.EXPRT); |
WHILE export # NIL DO |
WR.Write32LE(export.nameoffs + Size.Export + SectionHeaders[4].VirtualAddress); |
export := export.next(BIN.EXPRT) |
END; |
FOR i := 0 TO ExportDir.NumberOfFunctions - 1 DO |
WriteWord(WCHR(i)) |
END; |
CHL.WriteToFile(program.export); |
WR.Padding(FileAlignment) |
END; |
WR.Close |
END write; |
END PE32. |
/programs/develop/oberon07/source/RVM32I.ob07 |
---|
0,0 → 1,1302 |
(* |
BSD 2-Clause License |
Copyright (c) 2020, Anton Krotov |
All rights reserved. |
*) |
MODULE RVM32I; |
IMPORT |
PROG, WR := WRITER, IL, CHL := CHUNKLISTS, REG, UTILS, STRINGS, ERRORS; |
CONST |
LTypes = 0; |
LStrings = 1; |
LGlobal = 2; |
LHeap = 3; |
LStack = 4; |
numGPRs = 3; |
R0 = 0; R1 = 1; |
BP = 3; SP = 4; |
ACC = R0; |
GPRs = {0 .. 2} + {5 .. numGPRs + 1}; |
opSTOP = 0; opRET = 1; opENTER = 2; opNEG = 3; opNOT = 4; opABS = 5; |
opXCHG = 6; opLDR8 = 7; opLDR16 = 8; opLDR32 = 9; opPUSH = 10; opPUSHC = 11; |
opPOP = 12; opJGZ = 13; opJZ = 14; opJNZ = 15; opLLA = 16; opJGA = 17; |
opJLA = 18; opJMP = 19; opCALL = 20; opCALLI = 21; |
opMOV = 22; opMUL = 24; opADD = 26; opSUB = 28; opDIV = 30; opMOD = 32; |
opSTR8 = 34; opSTR16 = 36; opSTR32 = 38; opINCL = 40; opEXCL = 42; |
opIN = 44; opAND = 46; opOR = 48; opXOR = 50; opASR = 52; opLSR = 54; |
opLSL = 56; opROR = 58; opMIN = 60; opMAX = 62; opEQ = 64; opNE = 66; |
opLT = 68; opLE = 70; opGT = 72; opGE = 74; opBT = 76; |
opMOVC = 23; opMULC = 25; opADDC = 27; opSUBC = 29; opDIVC = 31; opMODC = 33; |
opSTR8C = 35; opSTR16C = 37; opSTR32C = 39; opINCLC = 41; opEXCLC = 43; |
opINC = 45; opANDC = 47; opORC = 49; opXORC = 51; opASRC = 53; opLSRC = 55; |
opLSLC = 57; opRORC = 59; opMINC = 61; opMAXC = 63; opEQC = 65; opNEC = 67; |
opLTC = 69; opLEC = 71; opGTC = 73; opGEC = 75; opBTC = 77; |
opLEA = 78; opLABEL = 79; |
inf = 7F800000H; |
VAR |
R: REG.REGS; count: INTEGER; |
PROCEDURE OutByte (n: BYTE); |
BEGIN |
WR.WriteByte(n); |
INC(count) |
END OutByte; |
PROCEDURE OutInt (n: INTEGER); |
BEGIN |
WR.Write32LE(n); |
INC(count, 4) |
END OutInt; |
PROCEDURE Emit (op, par1, par2: INTEGER); |
BEGIN |
OutInt(op); |
OutInt(par1); |
OutInt(par2) |
END Emit; |
PROCEDURE drop; |
BEGIN |
REG.Drop(R) |
END drop; |
PROCEDURE GetAnyReg (): INTEGER; |
RETURN REG.GetAnyReg(R) |
END GetAnyReg; |
PROCEDURE GetAcc; |
BEGIN |
ASSERT(REG.GetReg(R, ACC)) |
END GetAcc; |
PROCEDURE UnOp (VAR r: INTEGER); |
BEGIN |
REG.UnOp(R, r) |
END UnOp; |
PROCEDURE BinOp (VAR r1, r2: INTEGER); |
BEGIN |
REG.BinOp(R, r1, r2) |
END BinOp; |
PROCEDURE PushAll (NumberOfParameters: INTEGER); |
BEGIN |
REG.PushAll(R); |
DEC(R.pushed, NumberOfParameters) |
END PushAll; |
PROCEDURE push (r: INTEGER); |
BEGIN |
Emit(opPUSH, r, 0) |
END push; |
PROCEDURE pop (r: INTEGER); |
BEGIN |
Emit(opPOP, r, 0) |
END pop; |
PROCEDURE mov (r1, r2: INTEGER); |
BEGIN |
Emit(opMOV, r1, r2) |
END mov; |
PROCEDURE xchg (r1, r2: INTEGER); |
BEGIN |
Emit(opXCHG, r1, r2) |
END xchg; |
PROCEDURE addrc (r, c: INTEGER); |
BEGIN |
Emit(opADDC, r, c) |
END addrc; |
PROCEDURE subrc (r, c: INTEGER); |
BEGIN |
Emit(opSUBC, r, c) |
END subrc; |
PROCEDURE movrc (r, c: INTEGER); |
BEGIN |
Emit(opMOVC, r, c) |
END movrc; |
PROCEDURE pushc (c: INTEGER); |
BEGIN |
Emit(opPUSHC, c, 0) |
END pushc; |
PROCEDURE add (r1, r2: INTEGER); |
BEGIN |
Emit(opADD, r1, r2) |
END add; |
PROCEDURE sub (r1, r2: INTEGER); |
BEGIN |
Emit(opSUB, r1, r2) |
END sub; |
PROCEDURE ldr32 (r1, r2: INTEGER); |
BEGIN |
Emit(opLDR32, r1, r2) |
END ldr32; |
PROCEDURE ldr16 (r1, r2: INTEGER); |
BEGIN |
Emit(opLDR16, r1, r2) |
END ldr16; |
PROCEDURE ldr8 (r1, r2: INTEGER); |
BEGIN |
Emit(opLDR8, r1, r2) |
END ldr8; |
PROCEDURE str32 (r1, r2: INTEGER); |
BEGIN |
Emit(opSTR32, r1, r2) |
END str32; |
PROCEDURE str16 (r1, r2: INTEGER); |
BEGIN |
Emit(opSTR16, r1, r2) |
END str16; |
PROCEDURE str8 (r1, r2: INTEGER); |
BEGIN |
Emit(opSTR8, r1, r2) |
END str8; |
PROCEDURE GlobalAdr (r, offset: INTEGER); |
BEGIN |
Emit(opLEA, r + 256 * LGlobal, offset) |
END GlobalAdr; |
PROCEDURE StrAdr (r, offset: INTEGER); |
BEGIN |
Emit(opLEA, r + 256 * LStrings, offset) |
END StrAdr; |
PROCEDURE ProcAdr (r, label: INTEGER); |
BEGIN |
Emit(opLLA, r, label) |
END ProcAdr; |
PROCEDURE jnz (r, label: INTEGER); |
BEGIN |
Emit(opJNZ, r, label) |
END jnz; |
PROCEDURE CallRTL (proc, par: INTEGER); |
BEGIN |
Emit(opCALL, IL.codes.rtl[proc], 0); |
addrc(SP, par * 4) |
END CallRTL; |
PROCEDURE translate; |
VAR |
cmd: IL.COMMAND; |
opcode, param1, param2: INTEGER; |
r1, r2, r3: INTEGER; |
BEGIN |
cmd := IL.codes.commands.first(IL.COMMAND); |
WHILE cmd # NIL DO |
param1 := cmd.param1; |
param2 := cmd.param2; |
opcode := cmd.opcode; |
CASE opcode OF |
|IL.opJMP: |
Emit(opJMP, param1, 0) |
|IL.opLABEL: |
Emit(opLABEL, param1, 0) |
|IL.opCALL: |
Emit(opCALL, param1, 0) |
|IL.opCALLP: |
UnOp(r1); |
Emit(opCALLI, r1, 0); |
drop; |
ASSERT(R.top = -1) |
|IL.opPUSHC: |
pushc(param2) |
|IL.opCLEANUP: |
IF param2 # 0 THEN |
addrc(SP, param2 * 4) |
END |
|IL.opNOP, IL.opAND, IL.opOR: |
|IL.opSADR: |
StrAdr(GetAnyReg(), param2) |
|IL.opGADR: |
GlobalAdr(GetAnyReg(), param2) |
|IL.opLADR: |
r1 := GetAnyReg(); |
mov(r1, BP); |
addrc(r1, param2 * 4) |
|IL.opPARAM: |
IF param2 = 1 THEN |
UnOp(r1); |
push(r1); |
drop |
ELSE |
ASSERT(R.top + 1 <= param2); |
PushAll(param2) |
END |
|IL.opONERR: |
pushc(param2); |
Emit(opJMP, param1, 0) |
|IL.opPRECALL: |
PushAll(0) |
|IL.opRES, IL.opRESF: |
ASSERT(R.top = -1); |
GetAcc |
|IL.opENTER: |
ASSERT(R.top = -1); |
Emit(opLABEL, param1, 0); |
Emit(opENTER, param2, 0) |
|IL.opLEAVE, IL.opLEAVER, IL.opLEAVEF: |
IF opcode # IL.opLEAVE THEN |
UnOp(r1); |
IF r1 # ACC THEN |
GetAcc; |
ASSERT(REG.Exchange(R, r1, ACC)); |
drop |
END; |
drop |
END; |
ASSERT(R.top = -1); |
IF param1 > 0 THEN |
mov(SP, BP) |
END; |
pop(BP); |
Emit(opRET, 0, 0) |
|IL.opLEAVEC: |
Emit(opRET, 0, 0) |
|IL.opCONST: |
movrc(GetAnyReg(), param2) |
|IL.opDROP: |
UnOp(r1); |
drop |
|IL.opSAVEC: |
UnOp(r1); |
Emit(opSTR32C, r1, param2); |
drop |
|IL.opSAVE8C: |
UnOp(r1); |
Emit(opSTR8C, r1, param2 MOD 256); |
drop |
|IL.opSAVE16C: |
UnOp(r1); |
Emit(opSTR16C, r1, param2 MOD 65536); |
drop |
|IL.opSAVE, IL.opSAVE32, IL.opSAVEF: |
BinOp(r2, r1); |
str32(r1, r2); |
drop; |
drop |
|IL.opSAVEFI: |
BinOp(r2, r1); |
str32(r2, r1); |
drop; |
drop |
|IL.opSAVE8: |
BinOp(r2, r1); |
str8(r1, r2); |
drop; |
drop |
|IL.opSAVE16: |
BinOp(r2, r1); |
str16(r1, r2); |
drop; |
drop |
|IL.opGLOAD32: |
r1 := GetAnyReg(); |
GlobalAdr(r1, param2); |
ldr32(r1, r1) |
|IL.opVADR, IL.opLLOAD32: |
r1 := GetAnyReg(); |
mov(r1, BP); |
addrc(r1, param2 * 4); |
ldr32(r1, r1) |
|IL.opVLOAD32: |
r1 := GetAnyReg(); |
mov(r1, BP); |
addrc(r1, param2 * 4); |
ldr32(r1, r1); |
ldr32(r1, r1) |
|IL.opGLOAD16: |
r1 := GetAnyReg(); |
GlobalAdr(r1, param2); |
ldr16(r1, r1) |
|IL.opLLOAD16: |
r1 := GetAnyReg(); |
mov(r1, BP); |
addrc(r1, param2 * 4); |
ldr16(r1, r1) |
|IL.opVLOAD16: |
r1 := GetAnyReg(); |
mov(r1, BP); |
addrc(r1, param2 * 4); |
ldr32(r1, r1); |
ldr16(r1, r1) |
|IL.opGLOAD8: |
r1 := GetAnyReg(); |
GlobalAdr(r1, param2); |
ldr8(r1, r1) |
|IL.opLLOAD8: |
r1 := GetAnyReg(); |
mov(r1, BP); |
addrc(r1, param2 * 4); |
ldr8(r1, r1) |
|IL.opVLOAD8: |
r1 := GetAnyReg(); |
mov(r1, BP); |
addrc(r1, param2 * 4); |
ldr32(r1, r1); |
ldr8(r1, r1) |
|IL.opLOAD8: |
UnOp(r1); |
ldr8(r1, r1) |
|IL.opLOAD16: |
UnOp(r1); |
ldr16(r1, r1) |
|IL.opLOAD32, IL.opLOADF: |
UnOp(r1); |
ldr32(r1, r1) |
|IL.opLOOP, IL.opENDLOOP: |
|IL.opUMINUS: |
UnOp(r1); |
Emit(opNEG, r1, 0) |
|IL.opADD: |
BinOp(r1, r2); |
add(r1, r2); |
drop |
|IL.opSUB: |
BinOp(r1, r2); |
sub(r1, r2); |
drop |
|IL.opADDC: |
UnOp(r1); |
addrc(r1, param2) |
|IL.opSUBR: |
UnOp(r1); |
subrc(r1, param2) |
|IL.opSUBL: |
UnOp(r1); |
subrc(r1, param2); |
Emit(opNEG, r1, 0) |
|IL.opMULC: |
UnOp(r1); |
Emit(opMULC, r1, param2) |
|IL.opMUL: |
BinOp(r1, r2); |
Emit(opMUL, r1, r2); |
drop |
|IL.opDIV: |
BinOp(r1, r2); |
Emit(opDIV, r1, r2); |
drop |
|IL.opMOD: |
BinOp(r1, r2); |
Emit(opMOD, r1, r2); |
drop |
|IL.opDIVR: |
UnOp(r1); |
Emit(opDIVC, r1, param2) |
|IL.opMODR: |
UnOp(r1); |
Emit(opMODC, r1, param2) |
|IL.opDIVL: |
UnOp(r1); |
r2 := GetAnyReg(); |
movrc(r2, param2); |
Emit(opDIV, r2, r1); |
mov(r1, r2); |
drop |
|IL.opMODL: |
UnOp(r1); |
r2 := GetAnyReg(); |
movrc(r2, param2); |
Emit(opMOD, r2, r1); |
mov(r1, r2); |
drop |
|IL.opEQ: |
BinOp(r1, r2); |
Emit(opEQ, r1, r2); |
drop |
|IL.opNE: |
BinOp(r1, r2); |
Emit(opNE, r1, r2); |
drop |
|IL.opLT: |
BinOp(r1, r2); |
Emit(opLT, r1, r2); |
drop |
|IL.opLE: |
BinOp(r1, r2); |
Emit(opLE, r1, r2); |
drop |
|IL.opGT: |
BinOp(r1, r2); |
Emit(opGT, r1, r2); |
drop |
|IL.opGE: |
BinOp(r1, r2); |
Emit(opGE, r1, r2); |
drop |
|IL.opEQC: |
UnOp(r1); |
Emit(opEQC, r1, param2) |
|IL.opNEC: |
UnOp(r1); |
Emit(opNEC, r1, param2) |
|IL.opLTC: |
UnOp(r1); |
Emit(opLTC, r1, param2) |
|IL.opLEC: |
UnOp(r1); |
Emit(opLEC, r1, param2) |
|IL.opGTC: |
UnOp(r1); |
Emit(opGTC, r1, param2) |
|IL.opGEC: |
UnOp(r1); |
Emit(opGEC, r1, param2) |
|IL.opJNZ1: |
UnOp(r1); |
jnz(r1, param1) |
|IL.opJG: |
UnOp(r1); |
Emit(opJGZ, r1, param1) |
|IL.opJNZ: |
UnOp(r1); |
jnz(r1, param1); |
drop |
|IL.opJZ: |
UnOp(r1); |
Emit(opJZ, r1, param1); |
drop |
|IL.opMULS: |
BinOp(r1, r2); |
Emit(opAND, r1, r2); |
drop |
|IL.opMULSC: |
UnOp(r1); |
Emit(opANDC, r1, param2) |
|IL.opDIVS: |
BinOp(r1, r2); |
Emit(opXOR, r1, r2); |
drop |
|IL.opDIVSC: |
UnOp(r1); |
Emit(opXORC, r1, param2) |
|IL.opADDS: |
BinOp(r1, r2); |
Emit(opOR, r1, r2); |
drop |
|IL.opSUBS: |
BinOp(r1, r2); |
Emit(opNOT, r2, 0); |
Emit(opAND, r1, r2); |
drop |
|IL.opADDSC: |
UnOp(r1); |
Emit(opORC, r1, param2) |
|IL.opSUBSL: |
UnOp(r1); |
Emit(opNOT, r1, 0); |
Emit(opANDC, r1, param2) |
|IL.opSUBSR: |
UnOp(r1); |
Emit(opANDC, r1, ORD(-BITS(param2))) |
|IL.opUMINS: |
UnOp(r1); |
Emit(opNOT, r1, 0) |
|IL.opASR: |
BinOp(r1, r2); |
Emit(opASR, r1, r2); |
drop |
|IL.opLSL: |
BinOp(r1, r2); |
Emit(opLSL, r1, r2); |
drop |
|IL.opROR: |
BinOp(r1, r2); |
Emit(opROR, r1, r2); |
drop |
|IL.opLSR: |
BinOp(r1, r2); |
Emit(opLSR, r1, r2); |
drop |
|IL.opASR1: |
r2 := GetAnyReg(); |
Emit(opMOVC, r2, param2); |
BinOp(r1, r2); |
Emit(opASR, r2, r1); |
mov(r1, r2); |
drop |
|IL.opLSL1: |
r2 := GetAnyReg(); |
Emit(opMOVC, r2, param2); |
BinOp(r1, r2); |
Emit(opLSL, r2, r1); |
mov(r1, r2); |
drop |
|IL.opROR1: |
r2 := GetAnyReg(); |
Emit(opMOVC, r2, param2); |
BinOp(r1, r2); |
Emit(opROR, r2, r1); |
mov(r1, r2); |
drop |
|IL.opLSR1: |
r2 := GetAnyReg(); |
Emit(opMOVC, r2, param2); |
BinOp(r1, r2); |
Emit(opLSR, r2, r1); |
mov(r1, r2); |
drop |
|IL.opASR2: |
UnOp(r1); |
Emit(opASRC, r1, param2 MOD 32) |
|IL.opLSL2: |
UnOp(r1); |
Emit(opLSLC, r1, param2 MOD 32) |
|IL.opROR2: |
UnOp(r1); |
Emit(opRORC, r1, param2 MOD 32) |
|IL.opLSR2: |
UnOp(r1); |
Emit(opLSRC, r1, param2 MOD 32) |
|IL.opCHR: |
UnOp(r1); |
Emit(opANDC, r1, 255) |
|IL.opWCHR: |
UnOp(r1); |
Emit(opANDC, r1, 65535) |
|IL.opABS: |
UnOp(r1); |
Emit(opABS, r1, 0) |
|IL.opLEN: |
UnOp(r1); |
drop; |
EXCL(R.regs, r1); |
WHILE param2 > 0 DO |
UnOp(r2); |
drop; |
DEC(param2) |
END; |
INCL(R.regs, r1); |
ASSERT(REG.GetReg(R, r1)) |
|IL.opSWITCH: |
UnOp(r1); |
IF param2 = 0 THEN |
r2 := ACC |
ELSE |
r2 := R1 |
END; |
IF r1 # r2 THEN |
ASSERT(REG.GetReg(R, r2)); |
ASSERT(REG.Exchange(R, r1, r2)); |
drop |
END; |
drop |
|IL.opENDSW: |
|IL.opCASEL: |
GetAcc; |
Emit(opJLA, param1, param2); |
drop |
|IL.opCASER: |
GetAcc; |
Emit(opJGA, param1, param2); |
drop |
|IL.opCASELR: |
GetAcc; |
Emit(opJLA, param1, param2); |
Emit(opJGA, param1, cmd.param3); |
drop |
|IL.opSBOOL: |
BinOp(r2, r1); |
Emit(opNEC, r2, 0); |
str8(r1, r2); |
drop; |
drop |
|IL.opSBOOLC: |
UnOp(r1); |
Emit(opSTR8C, r1, ORD(param2 # 0)); |
drop |
|IL.opINCC: |
UnOp(r1); |
r2 := GetAnyReg(); |
ldr32(r2, r1); |
addrc(r2, param2); |
str32(r1, r2); |
drop; |
drop |
|IL.opINCCB, IL.opDECCB: |
IF opcode = IL.opDECCB THEN |
param2 := -param2 |
END; |
UnOp(r1); |
r2 := GetAnyReg(); |
ldr8(r2, r1); |
addrc(r2, param2); |
str8(r1, r2); |
drop; |
drop |
|IL.opINCB, IL.opDECB: |
BinOp(r2, r1); |
r3 := GetAnyReg(); |
ldr8(r3, r1); |
IF opcode = IL.opINCB THEN |
add(r3, r2) |
ELSE |
sub(r3, r2) |
END; |
str8(r1, r3); |
drop; |
drop; |
drop |
|IL.opINC, IL.opDEC: |
BinOp(r2, r1); |
r3 := GetAnyReg(); |
ldr32(r3, r1); |
IF opcode = IL.opINC THEN |
add(r3, r2) |
ELSE |
sub(r3, r2) |
END; |
str32(r1, r3); |
drop; |
drop; |
drop |
|IL.opINCL, IL.opEXCL: |
BinOp(r2, r1); |
IF opcode = IL.opINCL THEN |
Emit(opINCL, r1, r2) |
ELSE |
Emit(opEXCL, r1, r2) |
END; |
drop; |
drop |
|IL.opINCLC, IL.opEXCLC: |
UnOp(r1); |
r2 := GetAnyReg(); |
ldr32(r2, r1); |
IF opcode = IL.opINCLC THEN |
Emit(opINCLC, r2, param2) |
ELSE |
Emit(opEXCLC, r2, param2) |
END; |
str32(r1, r2); |
drop; |
drop |
|IL.opEQB, IL.opNEB: |
BinOp(r1, r2); |
Emit(opNEC, r1, 0); |
Emit(opNEC, r2, 0); |
IF opcode = IL.opEQB THEN |
Emit(opEQ, r1, r2) |
ELSE |
Emit(opNE, r1, r2) |
END; |
drop |
|IL.opCHKBYTE: |
BinOp(r1, r2); |
r3 := GetAnyReg(); |
mov(r3, r1); |
Emit(opBTC, r3, 256); |
jnz(r3, param1); |
drop |
|IL.opCHKIDX: |
UnOp(r1); |
r2 := GetAnyReg(); |
mov(r2, r1); |
Emit(opBTC, r2, param2); |
jnz(r2, param1); |
drop |
|IL.opCHKIDX2: |
BinOp(r1, r2); |
IF param2 # -1 THEN |
r3 := GetAnyReg(); |
mov(r3, r2); |
Emit(opBT, r3, r1); |
jnz(r3, param1); |
drop |
END; |
INCL(R.regs, r1); |
DEC(R.top); |
R.stk[R.top] := r2 |
|IL.opEQP, IL.opNEP: |
ProcAdr(GetAnyReg(), param1); |
BinOp(r1, r2); |
IF opcode = IL.opEQP THEN |
Emit(opEQ, r1, r2) |
ELSE |
Emit(opNE, r1, r2) |
END; |
drop |
|IL.opSAVEP: |
UnOp(r1); |
r2 := GetAnyReg(); |
ProcAdr(r2, param2); |
str32(r1, r2); |
drop; |
drop |
|IL.opPUSHP: |
ProcAdr(GetAnyReg(), param2) |
|IL.opPUSHT: |
UnOp(r1); |
r2 := GetAnyReg(); |
mov(r2, r1); |
subrc(r2, 4); |
ldr32(r2, r2) |
|IL.opGET, IL.opGETC: |
IF opcode = IL.opGET THEN |
BinOp(r1, r2) |
ELSIF opcode = IL.opGETC THEN |
UnOp(r2); |
r1 := GetAnyReg(); |
movrc(r1, param1) |
END; |
drop; |
drop; |
CASE param2 OF |
|1: ldr8(r1, r1); str8(r2, r1) |
|2: ldr16(r1, r1); str16(r2, r1) |
|4: ldr32(r1, r1); str32(r2, r1) |
END |
|IL.opNOT: |
UnOp(r1); |
Emit(opEQC, r1, 0) |
|IL.opORD: |
UnOp(r1); |
Emit(opNEC, r1, 0) |
|IL.opMIN: |
BinOp(r1, r2); |
Emit(opMIN, r1, r2); |
drop |
|IL.opMAX: |
BinOp(r1, r2); |
Emit(opMAX, r1, r2); |
drop |
|IL.opMINC: |
UnOp(r1); |
Emit(opMINC, r1, param2) |
|IL.opMAXC: |
UnOp(r1); |
Emit(opMAXC, r1, param2) |
|IL.opIN: |
BinOp(r1, r2); |
Emit(opIN, r1, r2); |
drop |
|IL.opINL: |
r1 := GetAnyReg(); |
movrc(r1, param2); |
BinOp(r2, r1); |
Emit(opIN, r1, r2); |
mov(r2, r1); |
drop |
|IL.opINR: |
UnOp(r1); |
Emit(opINC, r1, param2) |
|IL.opERR: |
CallRTL(IL._error, 4) |
|IL.opEQS .. IL.opGES: |
PushAll(4); |
pushc(opcode - IL.opEQS); |
CallRTL(IL._strcmp, 5); |
GetAcc |
|IL.opEQSW .. IL.opGESW: |
PushAll(4); |
pushc(opcode - IL.opEQSW); |
CallRTL(IL._strcmpw, 5); |
GetAcc |
|IL.opCOPY: |
PushAll(2); |
pushc(param2); |
CallRTL(IL._move, 3) |
|IL.opMOVE: |
PushAll(3); |
CallRTL(IL._move, 3) |
|IL.opCOPYA: |
PushAll(4); |
pushc(param2); |
CallRTL(IL._arrcpy, 5); |
GetAcc |
|IL.opCOPYS: |
PushAll(4); |
pushc(param2); |
CallRTL(IL._strcpy, 5) |
|IL.opROT: |
PushAll(0); |
mov(ACC, SP); |
push(ACC); |
pushc(param2); |
CallRTL(IL._rot, 2) |
|IL.opLENGTH: |
PushAll(2); |
CallRTL(IL._length, 2); |
GetAcc |
|IL.opLENGTHW: |
PushAll(2); |
CallRTL(IL._lengthw, 2); |
GetAcc |
|IL.opSAVES: |
UnOp(r2); |
REG.PushAll_1(R); |
r1 := GetAnyReg(); |
StrAdr(r1, param2); |
push(r1); |
drop; |
push(r2); |
drop; |
pushc(param1); |
CallRTL(IL._move, 3) |
|IL.opRSET: |
PushAll(2); |
CallRTL(IL._set, 2); |
GetAcc |
|IL.opRSETR: |
PushAll(1); |
pushc(param2); |
CallRTL(IL._set, 2); |
GetAcc |
|IL.opRSETL: |
UnOp(r1); |
REG.PushAll_1(R); |
pushc(param2); |
push(r1); |
drop; |
CallRTL(IL._set, 2); |
GetAcc |
|IL.opRSET1: |
PushAll(1); |
CallRTL(IL._set1, 1); |
GetAcc |
|IL.opNEW: |
PushAll(1); |
INC(param2, 8); |
ASSERT(UTILS.Align(param2, 32)); |
pushc(param2); |
pushc(param1); |
CallRTL(IL._new, 3) |
|IL.opTYPEGP: |
UnOp(r1); |
PushAll(0); |
push(r1); |
pushc(param2); |
CallRTL(IL._guard, 2); |
GetAcc |
|IL.opIS: |
PushAll(1); |
pushc(param2); |
CallRTL(IL._is, 2); |
GetAcc |
|IL.opISREC: |
PushAll(2); |
pushc(param2); |
CallRTL(IL._guardrec, 3); |
GetAcc |
|IL.opTYPEGR: |
PushAll(1); |
pushc(param2); |
CallRTL(IL._guardrec, 2); |
GetAcc |
|IL.opTYPEGD: |
UnOp(r1); |
PushAll(0); |
subrc(r1, 4); |
ldr32(r1, r1); |
push(r1); |
pushc(param2); |
CallRTL(IL._guardrec, 2); |
GetAcc |
|IL.opCASET: |
push(R1); |
push(R1); |
pushc(param2); |
CallRTL(IL._guardrec, 2); |
pop(R1); |
jnz(ACC, param1) |
|IL.opCONSTF: |
movrc(GetAnyReg(), UTILS.d2s(cmd.float)) |
|IL.opMULF: |
PushAll(2); |
CallRTL(IL._fmul, 2); |
GetAcc |
|IL.opDIVF: |
PushAll(2); |
CallRTL(IL._fdiv, 2); |
GetAcc |
|IL.opDIVFI: |
PushAll(2); |
CallRTL(IL._fdivi, 2); |
GetAcc |
|IL.opADDF: |
PushAll(2); |
CallRTL(IL._fadd, 2); |
GetAcc |
|IL.opSUBFI: |
PushAll(2); |
CallRTL(IL._fsubi, 2); |
GetAcc |
|IL.opSUBF: |
PushAll(2); |
CallRTL(IL._fsub, 2); |
GetAcc |
|IL.opEQF..IL.opGEF: |
PushAll(2); |
pushc(opcode - IL.opEQF); |
CallRTL(IL._fcmp, 3); |
GetAcc |
|IL.opFLOOR: |
PushAll(1); |
CallRTL(IL._floor, 1); |
GetAcc |
|IL.opFLT: |
PushAll(1); |
CallRTL(IL._flt, 1); |
GetAcc |
|IL.opUMINF: |
UnOp(r1); |
Emit(opXORC, r1, ORD({31})) |
|IL.opFABS: |
UnOp(r1); |
Emit(opANDC, r1, ORD({0..30})) |
|IL.opINF: |
movrc(GetAnyReg(), inf) |
|IL.opPUSHF: |
UnOp(r1); |
push(r1); |
drop |
|IL.opPACK: |
PushAll(2); |
CallRTL(IL._pack, 2) |
|IL.opPACKC: |
PushAll(1); |
pushc(param2); |
CallRTL(IL._pack, 2) |
|IL.opUNPK: |
PushAll(2); |
CallRTL(IL._unpk, 2) |
|IL.opCODE: |
OutInt(param2) |
END; |
cmd := cmd.next(IL.COMMAND) |
END; |
ASSERT(R.pushed = 0); |
ASSERT(R.top = -1) |
END translate; |
PROCEDURE prolog; |
BEGIN |
Emit(opLEA, SP + LStack * 256, 0); |
Emit(opLEA, ACC + LTypes * 256, 0); |
push(ACC); |
Emit(opLEA, ACC + LHeap * 256, 0); |
push(ACC); |
pushc(CHL.Length(IL.codes.types)); |
CallRTL(IL._init, 3) |
END prolog; |
PROCEDURE epilog (ram: INTEGER); |
VAR |
tcount, dcount, i, offTypes, offStrings, szData, szGlobal, szHeapStack: INTEGER; |
BEGIN |
Emit(opSTOP, 0, 0); |
offTypes := count; |
tcount := CHL.Length(IL.codes.types); |
FOR i := 0 TO tcount - 1 DO |
OutInt(CHL.GetInt(IL.codes.types, i)) |
END; |
offStrings := count; |
dcount := CHL.Length(IL.codes.data); |
FOR i := 0 TO dcount - 1 DO |
OutByte(CHL.GetByte(IL.codes.data, i)) |
END; |
IF dcount MOD 4 # 0 THEN |
i := 4 - dcount MOD 4; |
WHILE i > 0 DO |
OutByte(0); |
DEC(i) |
END |
END; |
szData := count - offTypes; |
szGlobal := (IL.codes.bss DIV 4 + 1) * 4; |
szHeapStack := ram - szData - szGlobal; |
OutInt(offTypes); |
OutInt(offStrings); |
OutInt(szGlobal DIV 4); |
OutInt(szHeapStack DIV 4); |
FOR i := 1 TO 8 DO |
OutInt(0) |
END |
END epilog; |
PROCEDURE CodeGen* (outname: ARRAY OF CHAR; target: INTEGER; options: PROG.OPTIONS); |
CONST |
minRAM = 32*1024; |
maxRAM = 256*1024; |
VAR |
szData, szRAM: INTEGER; |
BEGIN |
szData := (CHL.Length(IL.codes.types) + CHL.Length(IL.codes.data) DIV 4 + IL.codes.bss DIV 4 + 2) * 4; |
szRAM := MIN(MAX(options.ram, minRAM), maxRAM) * 1024; |
IF szRAM - szData < 1024*1024 THEN |
ERRORS.Error(208) |
END; |
count := 0; |
WR.Create(outname); |
REG.Init(R, push, pop, mov, xchg, NIL, NIL, GPRs, {}); |
prolog; |
translate; |
epilog(szRAM); |
WR.Close |
END CodeGen; |
END RVM32I. |
/programs/develop/oberon07/source/TEXTDRV.ob07 |
---|
0,0 → 1,192 |
(* |
BSD 2-Clause License |
Copyright (c) 2018-2020, Anton Krotov |
All rights reserved. |
*) |
MODULE TEXTDRV; |
IMPORT FILES, C := COLLECTIONS; |
CONST |
CR = 0DX; LF = 0AX; |
CHUNK = 1024 * 256; |
TYPE |
TEXT* = POINTER TO RECORD (C.ITEM) |
chunk: ARRAY CHUNK OF CHAR; |
pos, size: INTEGER; |
file: FILES.FILE; |
utf8: BOOLEAN; |
CR: BOOLEAN; |
line*, col*: INTEGER; |
ifc*: INTEGER; |
elsec*: INTEGER; |
eof*: BOOLEAN; |
eol*: BOOLEAN; |
skip*: BOOLEAN; |
peak*: CHAR; |
_skip*, |
_elsif*, |
_else*: ARRAY 100 OF BOOLEAN; |
fname*: ARRAY 2048 OF CHAR |
END; |
VAR |
texts: C.COLLECTION; |
PROCEDURE load (text: TEXT); |
BEGIN |
IF ~text.eof THEN |
text.size := FILES.read(text.file, text.chunk, LEN(text.chunk)); |
text.pos := 0; |
IF text.size = 0 THEN |
text.eof := TRUE; |
text.chunk[0] := 0X |
END; |
text.peak := text.chunk[0] |
END |
END load; |
PROCEDURE next* (text: TEXT); |
VAR |
c: CHAR; |
BEGIN |
IF text.pos < text.size - 1 THEN |
INC(text.pos); |
text.peak := text.chunk[text.pos] |
ELSE |
load(text) |
END; |
IF ~text.eof THEN |
c := text.peak; |
IF c = CR THEN |
INC(text.line); |
text.col := 0; |
text.eol := TRUE; |
text.CR := TRUE |
ELSIF c = LF THEN |
IF ~text.CR THEN |
INC(text.line); |
text.col := 0; |
text.eol := TRUE |
ELSE |
text.eol := FALSE |
END; |
text.CR := FALSE |
ELSE |
text.eol := FALSE; |
IF text.utf8 THEN |
IF ORD(c) DIV 64 # 2 THEN |
INC(text.col) |
END |
ELSE |
INC(text.col) |
END; |
text.CR := FALSE |
END |
END |
END next; |
PROCEDURE init (text: TEXT); |
BEGIN |
IF (text.pos = 0) & (text.size >= 3) THEN |
IF (text.chunk[0] = 0EFX) & |
(text.chunk[1] = 0BBX) & |
(text.chunk[2] = 0BFX) THEN |
text.pos := 3; |
text.utf8 := TRUE |
END |
END; |
IF text.size = 0 THEN |
text.chunk[0] := 0X; |
text.size := 1; |
text.eof := FALSE |
END; |
text.line := 1; |
text.col := 1; |
text.peak := text.chunk[text.pos] |
END init; |
PROCEDURE close* (VAR text: TEXT); |
BEGIN |
IF text # NIL THEN |
IF text.file # NIL THEN |
FILES.close(text.file) |
END; |
C.push(texts, text); |
text := NIL |
END |
END close; |
PROCEDURE open* (name: ARRAY OF CHAR): TEXT; |
VAR |
text: TEXT; |
citem: C.ITEM; |
BEGIN |
citem := C.pop(texts); |
IF citem = NIL THEN |
NEW(text) |
ELSE |
text := citem(TEXT) |
END; |
IF text # NIL THEN |
text.chunk[0] := 0X; |
text.pos := 0; |
text.size := 0; |
text.utf8 := FALSE; |
text.CR := FALSE; |
text.line := 1; |
text.col := 1; |
text.eof := FALSE; |
text.eol := FALSE; |
text.skip := FALSE; |
text.ifc := 0; |
text.elsec := 0; |
text._skip[0] := FALSE; |
text.peak := 0X; |
text.file := FILES.open(name); |
COPY(name, text.fname); |
IF text.file # NIL THEN |
load(text); |
init(text) |
ELSE |
close(text) |
END |
END |
RETURN text |
END open; |
BEGIN |
texts := C.create() |
END TEXTDRV. |
/programs/develop/oberon07/source/AVLTREES.ob07 |
---|
0,0 → 1,197 |
(* |
BSD 2-Clause License |
Copyright (c) 2018-2019, Anton Krotov |
All rights reserved. |
*) |
MODULE AVLTREES; |
IMPORT C := COLLECTIONS; |
TYPE |
DATA* = POINTER TO RECORD (C.ITEM) END; |
NODE* = POINTER TO RECORD (C.ITEM) |
data*: DATA; |
height: INTEGER; |
left*, right*: NODE |
END; |
CMP* = PROCEDURE (a, b: DATA): INTEGER; |
DESTRUCTOR* = PROCEDURE (VAR data: DATA); |
VAR |
nodes: C.COLLECTION; |
PROCEDURE NewNode (data: DATA): NODE; |
VAR |
node: NODE; |
citem: C.ITEM; |
BEGIN |
citem := C.pop(nodes); |
IF citem = NIL THEN |
NEW(node) |
ELSE |
node := citem(NODE) |
END; |
node.data := data; |
node.left := NIL; |
node.right := NIL; |
node.height := 1 |
RETURN node |
END NewNode; |
PROCEDURE height (p: NODE): INTEGER; |
VAR |
res: INTEGER; |
BEGIN |
IF p = NIL THEN |
res := 0 |
ELSE |
res := p.height |
END |
RETURN res |
END height; |
PROCEDURE bfactor (p: NODE): INTEGER; |
RETURN height(p.right) - height(p.left) |
END bfactor; |
PROCEDURE fixheight (p: NODE); |
BEGIN |
p.height := MAX(height(p.left), height(p.right)) + 1 |
END fixheight; |
PROCEDURE rotateright (p: NODE): NODE; |
VAR |
q: NODE; |
BEGIN |
q := p.left; |
p.left := q.right; |
q.right := p; |
fixheight(p); |
fixheight(q) |
RETURN q |
END rotateright; |
PROCEDURE rotateleft (q: NODE): NODE; |
VAR |
p: NODE; |
BEGIN |
p := q.right; |
q.right := p.left; |
p.left := q; |
fixheight(q); |
fixheight(p) |
RETURN p |
END rotateleft; |
PROCEDURE balance (p: NODE): NODE; |
VAR |
res: NODE; |
BEGIN |
fixheight(p); |
IF bfactor(p) = 2 THEN |
IF bfactor(p.right) < 0 THEN |
p.right := rotateright(p.right) |
END; |
res := rotateleft(p) |
ELSIF bfactor(p) = -2 THEN |
IF bfactor(p.left) > 0 THEN |
p.left := rotateleft(p.left) |
END; |
res := rotateright(p) |
ELSE |
res := p |
END |
RETURN res |
END balance; |
PROCEDURE insert* (p: NODE; data: DATA; cmp: CMP; VAR newnode: BOOLEAN; VAR node: NODE): NODE; |
VAR |
res: NODE; |
rescmp: INTEGER; |
BEGIN |
IF p = NIL THEN |
res := NewNode(data); |
node := res; |
newnode := TRUE |
ELSE |
rescmp := cmp(data, p.data); |
IF rescmp < 0 THEN |
p.left := insert(p.left, data, cmp, newnode, node); |
res := balance(p) |
ELSIF rescmp > 0 THEN |
p.right := insert(p.right, data, cmp, newnode, node); |
res := balance(p) |
ELSE |
res := p; |
node := res; |
newnode := FALSE |
END |
END |
RETURN res |
END insert; |
PROCEDURE destroy* (VAR node: NODE; destructor: DESTRUCTOR); |
VAR |
left, right: NODE; |
BEGIN |
IF node # NIL THEN |
left := node.left; |
right := node.right; |
IF destructor # NIL THEN |
destructor(node.data) |
END; |
C.push(nodes, node); |
node := NIL; |
destroy(left, destructor); |
destroy(right, destructor) |
END |
END destroy; |
BEGIN |
nodes := C.create() |
END AVLTREES. |
/programs/develop/oberon07/source/COLLECTIONS.ob07 |
---|
0,0 → 1,59 |
(* |
BSD 2-Clause License |
Copyright (c) 2018-2019, Anton Krotov |
All rights reserved. |
*) |
MODULE COLLECTIONS; |
TYPE |
ITEM* = POINTER TO RECORD |
link: ITEM |
END; |
COLLECTION* = POINTER TO RECORD |
last: ITEM |
END; |
PROCEDURE push* (collection: COLLECTION; item: ITEM); |
BEGIN |
item.link := collection.last; |
collection.last := item |
END push; |
PROCEDURE pop* (collection: COLLECTION): ITEM; |
VAR |
item: ITEM; |
BEGIN |
item := collection.last; |
IF item # NIL THEN |
collection.last := item.link |
END |
RETURN item |
END pop; |
PROCEDURE create* (): COLLECTION; |
VAR |
collection: COLLECTION; |
BEGIN |
NEW(collection); |
collection.last := NIL |
RETURN collection |
END create; |
END COLLECTIONS. |