general update
This commit is contained in:
@@ -1,7 +1,4 @@
|
||||
import ../stdlib/io.sl
|
||||
|
||||
# Raw extern (no ABI handling)
|
||||
extern raw_extern_test
|
||||
import stdlib/io.sl
|
||||
|
||||
# C-style externs (auto ABI handling)
|
||||
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:
|
||||
self.line = 1
|
||||
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)
|
||||
|
||||
def add_tokens(self, tokens: Iterable[str]) -> None:
|
||||
@@ -336,6 +336,7 @@ class Word:
|
||||
is_extern: bool = False # New: mark as extern
|
||||
extern_inputs: int = 0
|
||||
extern_outputs: int = 0
|
||||
extern_signature: Optional[Tuple[List[str], str]] = None # (arg_types, ret_type)
|
||||
|
||||
|
||||
@dataclass
|
||||
@@ -509,6 +510,7 @@ class Parser:
|
||||
raise ParseError(f"expected '(' after extern function name '{name}'")
|
||||
|
||||
inputs = 0
|
||||
arg_types: List[str] = []
|
||||
while True:
|
||||
if self._eof():
|
||||
raise ParseError("extern unclosed '('")
|
||||
@@ -530,6 +532,7 @@ class Parser:
|
||||
|
||||
if arg_type != "void":
|
||||
inputs += 1
|
||||
arg_types.append(arg_type)
|
||||
# Optional argument name
|
||||
peek_name = self.peek_token()
|
||||
if peek_name and peek_name.lexeme not in (",", ")"):
|
||||
@@ -548,6 +551,7 @@ class Parser:
|
||||
word.is_extern = True
|
||||
word.extern_inputs = inputs
|
||||
word.extern_outputs = outputs
|
||||
word.extern_signature = (arg_types, ret_type)
|
||||
|
||||
else:
|
||||
# Raw/Legacy Parsing
|
||||
@@ -839,17 +843,29 @@ class Parser:
|
||||
else: # pragma: no cover - defensive
|
||||
raise ParseError("unknown parse context")
|
||||
|
||||
def _try_literal(self, token: Token) -> bool:
|
||||
def _try_literal(self, token: Token) -> None:
|
||||
try:
|
||||
value = int(token.lexeme, 0)
|
||||
self._append_node(Literal(value=value))
|
||||
return True
|
||||
except ValueError:
|
||||
string_value = _parse_string_literal(token)
|
||||
if string_value is None:
|
||||
return False
|
||||
pass
|
||||
|
||||
# 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))
|
||||
return True
|
||||
self._append_node(Literal(value=value))
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
def _consume(self) -> Token:
|
||||
self._ensure_tokens(self.pos)
|
||||
@@ -1359,6 +1375,14 @@ class FunctionEmitter:
|
||||
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:
|
||||
self.text.extend([
|
||||
f" ; push {label}",
|
||||
@@ -1465,6 +1489,7 @@ class Assembler:
|
||||
self.stack_bytes = 65536
|
||||
self.io_buffer_bytes = 128
|
||||
self._string_literals: Dict[str, Tuple[str, int]] = {}
|
||||
self._float_literals: Dict[float, str] = {}
|
||||
self._data_section: Optional[List[str]] = None
|
||||
|
||||
def _emit_externs(self, text: List[str]) -> None:
|
||||
@@ -1477,6 +1502,7 @@ class Assembler:
|
||||
self._emit_externs(emission.text)
|
||||
emission.text.extend(self._runtime_prelude())
|
||||
self._string_literals = {}
|
||||
self._float_literals = {}
|
||||
self._data_section = emission.data
|
||||
|
||||
valid_defs = (Definition, AsmDefinition)
|
||||
@@ -1524,6 +1550,21 @@ class Assembler:
|
||||
self._string_literals[value] = (label, len(encoded))
|
||||
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:
|
||||
label = sanitize_label(definition.name)
|
||||
text.append(f"{label}:")
|
||||
@@ -1552,6 +1593,10 @@ class Assembler:
|
||||
if isinstance(node.value, int):
|
||||
builder.push_literal(node.value)
|
||||
return
|
||||
if isinstance(node.value, float):
|
||||
label = self._intern_float_literal(node.value)
|
||||
builder.push_float(label)
|
||||
return
|
||||
if isinstance(node.value, str):
|
||||
label, length = self._intern_string_literal(node.value)
|
||||
builder.push_label(label)
|
||||
@@ -1591,24 +1636,63 @@ class Assembler:
|
||||
if getattr(word, "is_extern", False):
|
||||
inputs = getattr(word, "extern_inputs", 0)
|
||||
outputs = getattr(word, "extern_outputs", 0)
|
||||
signature = getattr(word, "extern_signature", None)
|
||||
|
||||
if inputs > 0 or outputs > 0:
|
||||
regs = ["rdi", "rsi", "rdx", "rcx", "r8", "r9"]
|
||||
if inputs > 6:
|
||||
raise CompileError(f"extern '{ref.name}' has too many inputs ({inputs} > 6)")
|
||||
|
||||
# Pop inputs in reverse register order (argN is top of stack -> last reg)
|
||||
current_regs = regs[:inputs]
|
||||
for reg in reversed(current_regs):
|
||||
builder.pop_to(reg)
|
||||
|
||||
# Align RSP and call
|
||||
xmm_regs = [f"xmm{i}" for i in range(8)]
|
||||
|
||||
arg_types = signature[0] if signature else []
|
||||
ret_type = signature[1] if signature else None
|
||||
|
||||
if len(arg_types) != inputs and signature:
|
||||
raise CompileError(f"extern '{ref.name}' mismatch: {inputs} inputs vs {len(arg_types)} types")
|
||||
|
||||
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(" mov rbp, rsp")
|
||||
builder.emit(" and rsp, -16")
|
||||
builder.emit(f" mov al, {xmm_idx}")
|
||||
builder.emit(f" call {ref.name}")
|
||||
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")
|
||||
elif outputs > 1:
|
||||
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