general update
This commit is contained in:
@@ -1,7 +1,4 @@
|
|||||||
import ../stdlib/io.sl
|
import stdlib/io.sl
|
||||||
|
|
||||||
# Raw extern (no ABI handling)
|
|
||||||
extern raw_extern_test
|
|
||||||
|
|
||||||
# C-style externs (auto ABI handling)
|
# C-style externs (auto ABI handling)
|
||||||
extern long labs(long n)
|
extern long labs(long n)
|
||||||
17
f.sl
Normal file
17
f.sl
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
import stdlib/stdlib.sl
|
||||||
|
import stdlib/io.sl
|
||||||
|
import stdlib/float.sl
|
||||||
|
|
||||||
|
extern double atan2(double y, double x)
|
||||||
|
|
||||||
|
: main
|
||||||
|
# Basic math
|
||||||
|
1.5 2.5 f+ fputln # Outputs: 4.000000
|
||||||
|
|
||||||
|
# External math library (libm)
|
||||||
|
10.0 10.0 atan2 # Result is pi/4
|
||||||
|
4.0 f* fputln # Outputs: 3.141593 (approx pi)
|
||||||
|
|
||||||
|
0
|
||||||
|
;
|
||||||
|
|
||||||
120
main.py
120
main.py
@@ -60,7 +60,7 @@ class Reader:
|
|||||||
def __init__(self) -> None:
|
def __init__(self) -> None:
|
||||||
self.line = 1
|
self.line = 1
|
||||||
self.column = 0
|
self.column = 0
|
||||||
self.custom_tokens: Set[str] = {"(", ")", "{", "}", ";", ",", "[", "]", "*"}
|
self.custom_tokens: Set[str] = {"(", ")", "{", "}", ";", ",", "[", "]"}
|
||||||
self._token_order: List[str] = sorted(self.custom_tokens, key=len, reverse=True)
|
self._token_order: List[str] = sorted(self.custom_tokens, key=len, reverse=True)
|
||||||
|
|
||||||
def add_tokens(self, tokens: Iterable[str]) -> None:
|
def add_tokens(self, tokens: Iterable[str]) -> None:
|
||||||
@@ -336,6 +336,7 @@ class Word:
|
|||||||
is_extern: bool = False # New: mark as extern
|
is_extern: bool = False # New: mark as extern
|
||||||
extern_inputs: int = 0
|
extern_inputs: int = 0
|
||||||
extern_outputs: int = 0
|
extern_outputs: int = 0
|
||||||
|
extern_signature: Optional[Tuple[List[str], str]] = None # (arg_types, ret_type)
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
@@ -509,6 +510,7 @@ class Parser:
|
|||||||
raise ParseError(f"expected '(' after extern function name '{name}'")
|
raise ParseError(f"expected '(' after extern function name '{name}'")
|
||||||
|
|
||||||
inputs = 0
|
inputs = 0
|
||||||
|
arg_types: List[str] = []
|
||||||
while True:
|
while True:
|
||||||
if self._eof():
|
if self._eof():
|
||||||
raise ParseError("extern unclosed '('")
|
raise ParseError("extern unclosed '('")
|
||||||
@@ -530,6 +532,7 @@ class Parser:
|
|||||||
|
|
||||||
if arg_type != "void":
|
if arg_type != "void":
|
||||||
inputs += 1
|
inputs += 1
|
||||||
|
arg_types.append(arg_type)
|
||||||
# Optional argument name
|
# Optional argument name
|
||||||
peek_name = self.peek_token()
|
peek_name = self.peek_token()
|
||||||
if peek_name and peek_name.lexeme not in (",", ")"):
|
if peek_name and peek_name.lexeme not in (",", ")"):
|
||||||
@@ -548,6 +551,7 @@ class Parser:
|
|||||||
word.is_extern = True
|
word.is_extern = True
|
||||||
word.extern_inputs = inputs
|
word.extern_inputs = inputs
|
||||||
word.extern_outputs = outputs
|
word.extern_outputs = outputs
|
||||||
|
word.extern_signature = (arg_types, ret_type)
|
||||||
|
|
||||||
else:
|
else:
|
||||||
# Raw/Legacy Parsing
|
# Raw/Legacy Parsing
|
||||||
@@ -839,17 +843,29 @@ class Parser:
|
|||||||
else: # pragma: no cover - defensive
|
else: # pragma: no cover - defensive
|
||||||
raise ParseError("unknown parse context")
|
raise ParseError("unknown parse context")
|
||||||
|
|
||||||
def _try_literal(self, token: Token) -> bool:
|
def _try_literal(self, token: Token) -> None:
|
||||||
try:
|
try:
|
||||||
value = int(token.lexeme, 0)
|
value = int(token.lexeme, 0)
|
||||||
|
self._append_node(Literal(value=value))
|
||||||
|
return True
|
||||||
except ValueError:
|
except ValueError:
|
||||||
string_value = _parse_string_literal(token)
|
pass
|
||||||
if string_value is None:
|
|
||||||
return False
|
# Try float
|
||||||
|
try:
|
||||||
|
if "." in token.lexeme or "e" in token.lexeme.lower():
|
||||||
|
value = float(token.lexeme)
|
||||||
|
self._append_node(Literal(value=value))
|
||||||
|
return True
|
||||||
|
except ValueError:
|
||||||
|
pass
|
||||||
|
|
||||||
|
string_value = _parse_string_literal(token)
|
||||||
|
if string_value is not None:
|
||||||
self._append_node(Literal(value=string_value))
|
self._append_node(Literal(value=string_value))
|
||||||
return True
|
return True
|
||||||
self._append_node(Literal(value=value))
|
|
||||||
return True
|
return False
|
||||||
|
|
||||||
def _consume(self) -> Token:
|
def _consume(self) -> Token:
|
||||||
self._ensure_tokens(self.pos)
|
self._ensure_tokens(self.pos)
|
||||||
@@ -1359,6 +1375,14 @@ class FunctionEmitter:
|
|||||||
f" mov qword [r12], {value}",
|
f" mov qword [r12], {value}",
|
||||||
])
|
])
|
||||||
|
|
||||||
|
def push_float(self, label: str) -> None:
|
||||||
|
self.text.extend([
|
||||||
|
f" ; push float from {label}",
|
||||||
|
" sub r12, 8",
|
||||||
|
f" mov rax, [rel {label}]",
|
||||||
|
" mov [r12], rax",
|
||||||
|
])
|
||||||
|
|
||||||
def push_label(self, label: str) -> None:
|
def push_label(self, label: str) -> None:
|
||||||
self.text.extend([
|
self.text.extend([
|
||||||
f" ; push {label}",
|
f" ; push {label}",
|
||||||
@@ -1465,6 +1489,7 @@ class Assembler:
|
|||||||
self.stack_bytes = 65536
|
self.stack_bytes = 65536
|
||||||
self.io_buffer_bytes = 128
|
self.io_buffer_bytes = 128
|
||||||
self._string_literals: Dict[str, Tuple[str, int]] = {}
|
self._string_literals: Dict[str, Tuple[str, int]] = {}
|
||||||
|
self._float_literals: Dict[float, str] = {}
|
||||||
self._data_section: Optional[List[str]] = None
|
self._data_section: Optional[List[str]] = None
|
||||||
|
|
||||||
def _emit_externs(self, text: List[str]) -> None:
|
def _emit_externs(self, text: List[str]) -> None:
|
||||||
@@ -1477,6 +1502,7 @@ class Assembler:
|
|||||||
self._emit_externs(emission.text)
|
self._emit_externs(emission.text)
|
||||||
emission.text.extend(self._runtime_prelude())
|
emission.text.extend(self._runtime_prelude())
|
||||||
self._string_literals = {}
|
self._string_literals = {}
|
||||||
|
self._float_literals = {}
|
||||||
self._data_section = emission.data
|
self._data_section = emission.data
|
||||||
|
|
||||||
valid_defs = (Definition, AsmDefinition)
|
valid_defs = (Definition, AsmDefinition)
|
||||||
@@ -1524,6 +1550,21 @@ class Assembler:
|
|||||||
self._string_literals[value] = (label, len(encoded))
|
self._string_literals[value] = (label, len(encoded))
|
||||||
return self._string_literals[value]
|
return self._string_literals[value]
|
||||||
|
|
||||||
|
def _intern_float_literal(self, value: float) -> str:
|
||||||
|
if self._data_section is None:
|
||||||
|
raise CompileError("float literal emission requested without data section")
|
||||||
|
self._ensure_data_start()
|
||||||
|
if value in self._float_literals:
|
||||||
|
return self._float_literals[value]
|
||||||
|
label = f"flt_{len(self._float_literals)}"
|
||||||
|
# Use hex representation of double precision float
|
||||||
|
import struct
|
||||||
|
hex_val = struct.pack('>d', value).hex()
|
||||||
|
# NASM expects hex starting with 0x
|
||||||
|
self._data_section.append(f"{label}: dq 0x{hex_val}")
|
||||||
|
self._float_literals[value] = label
|
||||||
|
return label
|
||||||
|
|
||||||
def _emit_definition(self, definition: Union[Definition, AsmDefinition], text: List[str]) -> None:
|
def _emit_definition(self, definition: Union[Definition, AsmDefinition], text: List[str]) -> None:
|
||||||
label = sanitize_label(definition.name)
|
label = sanitize_label(definition.name)
|
||||||
text.append(f"{label}:")
|
text.append(f"{label}:")
|
||||||
@@ -1552,6 +1593,10 @@ class Assembler:
|
|||||||
if isinstance(node.value, int):
|
if isinstance(node.value, int):
|
||||||
builder.push_literal(node.value)
|
builder.push_literal(node.value)
|
||||||
return
|
return
|
||||||
|
if isinstance(node.value, float):
|
||||||
|
label = self._intern_float_literal(node.value)
|
||||||
|
builder.push_float(label)
|
||||||
|
return
|
||||||
if isinstance(node.value, str):
|
if isinstance(node.value, str):
|
||||||
label, length = self._intern_string_literal(node.value)
|
label, length = self._intern_string_literal(node.value)
|
||||||
builder.push_label(label)
|
builder.push_label(label)
|
||||||
@@ -1591,24 +1636,63 @@ class Assembler:
|
|||||||
if getattr(word, "is_extern", False):
|
if getattr(word, "is_extern", False):
|
||||||
inputs = getattr(word, "extern_inputs", 0)
|
inputs = getattr(word, "extern_inputs", 0)
|
||||||
outputs = getattr(word, "extern_outputs", 0)
|
outputs = getattr(word, "extern_outputs", 0)
|
||||||
|
signature = getattr(word, "extern_signature", None)
|
||||||
|
|
||||||
if inputs > 0 or outputs > 0:
|
if inputs > 0 or outputs > 0:
|
||||||
regs = ["rdi", "rsi", "rdx", "rcx", "r8", "r9"]
|
regs = ["rdi", "rsi", "rdx", "rcx", "r8", "r9"]
|
||||||
if inputs > 6:
|
xmm_regs = [f"xmm{i}" for i in range(8)]
|
||||||
raise CompileError(f"extern '{ref.name}' has too many inputs ({inputs} > 6)")
|
|
||||||
|
arg_types = signature[0] if signature else []
|
||||||
# Pop inputs in reverse register order (argN is top of stack -> last reg)
|
ret_type = signature[1] if signature else None
|
||||||
current_regs = regs[:inputs]
|
|
||||||
for reg in reversed(current_regs):
|
if len(arg_types) != inputs and signature:
|
||||||
builder.pop_to(reg)
|
raise CompileError(f"extern '{ref.name}' mismatch: {inputs} inputs vs {len(arg_types)} types")
|
||||||
|
|
||||||
# Align RSP and call
|
int_idx = 0
|
||||||
|
xmm_idx = 0
|
||||||
|
|
||||||
|
mapping: List[Tuple[str, str]] = [] # (type, target_reg)
|
||||||
|
|
||||||
|
if not arg_types:
|
||||||
|
# Legacy/Raw mode: assume all ints
|
||||||
|
if inputs > 6:
|
||||||
|
raise CompileError(f"extern '{ref.name}' has too many inputs ({inputs} > 6)")
|
||||||
|
for i in range(inputs):
|
||||||
|
mapping.append(("int", regs[i]))
|
||||||
|
else:
|
||||||
|
for type_name in arg_types:
|
||||||
|
if type_name in ("float", "double"):
|
||||||
|
if xmm_idx >= 8:
|
||||||
|
raise CompileError(f"extern '{ref.name}' has too many float inputs")
|
||||||
|
mapping.append(("float", xmm_regs[xmm_idx]))
|
||||||
|
xmm_idx += 1
|
||||||
|
else:
|
||||||
|
if int_idx >= 6:
|
||||||
|
raise CompileError(f"extern '{ref.name}' has too many int inputs")
|
||||||
|
mapping.append(("int", regs[int_idx]))
|
||||||
|
int_idx += 1
|
||||||
|
|
||||||
|
for type_name, reg in reversed(mapping):
|
||||||
|
if type_name == "float":
|
||||||
|
builder.pop_to("rax")
|
||||||
|
builder.emit(f" movq {reg}, rax")
|
||||||
|
else:
|
||||||
|
builder.pop_to(reg)
|
||||||
|
|
||||||
builder.emit(" push rbp")
|
builder.emit(" push rbp")
|
||||||
builder.emit(" mov rbp, rsp")
|
builder.emit(" mov rbp, rsp")
|
||||||
builder.emit(" and rsp, -16")
|
builder.emit(" and rsp, -16")
|
||||||
|
builder.emit(f" mov al, {xmm_idx}")
|
||||||
builder.emit(f" call {ref.name}")
|
builder.emit(f" call {ref.name}")
|
||||||
builder.emit(" leave")
|
builder.emit(" leave")
|
||||||
|
|
||||||
if outputs == 1:
|
# Handle Return Value
|
||||||
|
if ret_type in ("float", "double"):
|
||||||
|
# Result in xmm0, move to stack
|
||||||
|
builder.emit(" sub r12, 8")
|
||||||
|
builder.emit(" movq rax, xmm0")
|
||||||
|
builder.emit(" mov [r12], rax")
|
||||||
|
elif outputs == 1:
|
||||||
builder.push_from("rax")
|
builder.push_from("rax")
|
||||||
elif outputs > 1:
|
elif outputs > 1:
|
||||||
raise CompileError("extern only supports 0 or 1 output")
|
raise CompileError("extern only supports 0 or 1 output")
|
||||||
|
|||||||
12
raw_lib.asm
12
raw_lib.asm
@@ -1,12 +0,0 @@
|
|||||||
|
|
||||||
global raw_add
|
|
||||||
section .text
|
|
||||||
raw_add:
|
|
||||||
; expects args on stack: [r12]=b, [r12+8]=a
|
|
||||||
; returns sum on stack
|
|
||||||
mov rax, [r12] ; b
|
|
||||||
add r12, 8
|
|
||||||
mov rbx, [r12] ; a
|
|
||||||
add rax, rbx
|
|
||||||
mov [r12], rax
|
|
||||||
ret
|
|
||||||
95
stdlib/float.sl
Normal file
95
stdlib/float.sl
Normal file
@@ -0,0 +1,95 @@
|
|||||||
|
# L2 Floating Point Library (Double Precision)
|
||||||
|
|
||||||
|
# Arithmetic
|
||||||
|
:asm f+ {
|
||||||
|
movq xmm0, [r12]
|
||||||
|
add r12, 8
|
||||||
|
movq xmm1, [r12]
|
||||||
|
addsd xmm1, xmm0
|
||||||
|
movq [r12], xmm1
|
||||||
|
} ;
|
||||||
|
|
||||||
|
:asm f- {
|
||||||
|
movq xmm0, [r12]
|
||||||
|
add r12, 8
|
||||||
|
movq xmm1, [r12]
|
||||||
|
subsd xmm1, xmm0
|
||||||
|
movq [r12], xmm1
|
||||||
|
} ;
|
||||||
|
|
||||||
|
:asm f* {
|
||||||
|
movq xmm0, [r12]
|
||||||
|
add r12, 8
|
||||||
|
movq xmm1, [r12]
|
||||||
|
mulsd xmm1, xmm0
|
||||||
|
movq [r12], xmm1
|
||||||
|
} ;
|
||||||
|
|
||||||
|
:asm f/ {
|
||||||
|
movq xmm0, [r12]
|
||||||
|
add r12, 8
|
||||||
|
movq xmm1, [r12]
|
||||||
|
divsd xmm1, xmm0
|
||||||
|
movq [r12], xmm1
|
||||||
|
} ;
|
||||||
|
|
||||||
|
:asm fneg {
|
||||||
|
movq xmm0, [r12]
|
||||||
|
mov rax, 0x8000000000000000
|
||||||
|
movq xmm1, rax
|
||||||
|
xorpd xmm0, xmm1
|
||||||
|
movq [r12], xmm0
|
||||||
|
} ;
|
||||||
|
|
||||||
|
# Comparison
|
||||||
|
:asm f== {
|
||||||
|
movq xmm0, [r12]
|
||||||
|
add r12, 8
|
||||||
|
movq xmm1, [r12]
|
||||||
|
ucomisd xmm0, xmm1
|
||||||
|
mov rax, 0
|
||||||
|
setz al
|
||||||
|
mov [r12], rax
|
||||||
|
} ;
|
||||||
|
|
||||||
|
:asm f< {
|
||||||
|
movq xmm0, [r12] ; a
|
||||||
|
add r12, 8
|
||||||
|
movq xmm1, [r12] ; b
|
||||||
|
ucomisd xmm0, xmm1
|
||||||
|
mov rax, 0
|
||||||
|
seta al ; Above (a > b) -> b < a
|
||||||
|
mov [r12], rax
|
||||||
|
} ;
|
||||||
|
|
||||||
|
:asm f> {
|
||||||
|
movq xmm0, [r12] ; a
|
||||||
|
add r12, 8
|
||||||
|
movq xmm1, [r12] ; b
|
||||||
|
ucomisd xmm1, xmm0
|
||||||
|
mov rax, 0
|
||||||
|
seta al ; b > a
|
||||||
|
mov [r12], rax
|
||||||
|
} ;
|
||||||
|
|
||||||
|
# Conversion
|
||||||
|
:asm int>float {
|
||||||
|
cvtsi2sd xmm0, [r12]
|
||||||
|
movq [r12], xmm0
|
||||||
|
} ;
|
||||||
|
|
||||||
|
:asm float>int {
|
||||||
|
cvttsd2si rax, [r12]
|
||||||
|
mov [r12], rax
|
||||||
|
} ;
|
||||||
|
|
||||||
|
# Output
|
||||||
|
extern int printf(char* fmt, double x)
|
||||||
|
|
||||||
|
: fput
|
||||||
|
"%f" drop swap printf drop
|
||||||
|
;
|
||||||
|
|
||||||
|
: fputln
|
||||||
|
"%f\n" drop swap printf drop
|
||||||
|
;
|
||||||
@@ -1,8 +0,0 @@
|
|||||||
import stdlib/io.sl
|
|
||||||
|
|
||||||
extern raw_add
|
|
||||||
|
|
||||||
: main
|
|
||||||
10 20 raw_add
|
|
||||||
puti cr
|
|
||||||
;
|
|
||||||
Reference in New Issue
Block a user