Compare commits

...

2 Commits

Author SHA1 Message Date
Kyler Olsen 8890216457 Updated sls_calc module 2025-12-04 23:52:42 -07:00
Kyler Olsen d7164599f0 Fixed circular imports 2025-12-04 23:52:24 -07:00
5 changed files with 108 additions and 143 deletions

View File

@ -12,7 +12,7 @@ class HPCalculator:
def __init__(self, root): def __init__(self, root):
self.root = root self.root = root
self.root.title("HP Stack Calculator") self.root.title("HP Stack Calculator")
self.root.geometry("450x650") # self.root.geometry("450x650")
self.root.resizable(False, False) self.root.resizable(False, False)
# Initialize interpreter # Initialize interpreter
@ -24,24 +24,8 @@ class HPCalculator:
self.is_new_entry = True self.is_new_entry = True
# Set up UI # Set up UI
self.setup_styles()
self.create_widgets() self.create_widgets()
def setup_styles(self):
"""Configure custom styles for the calculator"""
style = ttk.Style()
style.theme_use('clam')
# Configure button styles
style.configure('Calc.TButton',
font=('Arial', 12, 'bold'),
padding=10)
style.configure('Display.TLabel',
font=('Courier', 14),
background='#f0f0f0',
relief='sunken',
padding=5)
def create_widgets(self): def create_widgets(self):
"""Create all calculator widgets""" """Create all calculator widgets"""
# Main container # Main container
@ -65,8 +49,7 @@ class HPCalculator:
self.stack_labels = [] self.stack_labels = []
for i in range(4): for i in range(4):
label = ttk.Label(stack_frame, label = ttk.Label(stack_frame,
text=f"T{3-i}: 0", text=f"T{3-i}: <>",
style='Display.TLabel',
anchor='e', anchor='e',
width=30) width=30)
label.grid(row=i, column=0, sticky=(tk.W, tk.E), pady=2) label.grid(row=i, column=0, sticky=(tk.W, tk.E), pady=2)
@ -79,45 +62,34 @@ class HPCalculator:
self.entry_label = ttk.Label(entry_frame, self.entry_label = ttk.Label(entry_frame,
text="0", text="0",
style='Display.TLabel',
anchor='e', anchor='e',
font=('Courier', 16, 'bold')) font=('Courier', 16))
self.entry_label.grid(row=0, column=0, sticky=(tk.W, tk.E)) self.entry_label.grid(row=0, column=0, sticky=(tk.W, tk.E))
def create_button_grid(self, parent): def create_button_grid(self, parent):
"""Create the calculator button grid""" """Create the calculator button grid"""
buttons = [ buttons = [
# Row 1: Stack operations [('', self.sqrt), ('', self.square), ('1/x', self.reciprocal), ('NULL', lambda: None)],
[('', self.sqrt), ('', self.square), ('1/x', self.reciprocal), ('÷', self.divide)], [('ENTER', lambda: self.enter(True)), ('SWAP', self.swap), ('<-', self.drop), ('NULL', lambda: None)],
# Row 2: Numbers and operations [('7', lambda: self.digit('7')), ('8', lambda: self.digit('8')), ('9', lambda: self.digit('9')), ('÷', self.divide)],
[('7', lambda: self.digit('7')), ('8', lambda: self.digit('8')), [('4', lambda: self.digit('4')), ('5', lambda: self.digit('5')), ('6', lambda: self.digit('6')), ('×', self.multiply)],
('9', lambda: self.digit('9')), ('×', self.multiply)], [('1', lambda: self.digit('1')), ('2', lambda: self.digit('2')), ('3', lambda: self.digit('3')), ('', self.subtract)],
# Row 3 [('0', lambda: self.digit('0')), ('.', self.decimal), ('±', self.negate), ('+', self.add)],
[('4', lambda: self.digit('4')), ('5', lambda: self.digit('5')),
('6', lambda: self.digit('6')), ('', self.subtract)],
# Row 4
[('1', lambda: self.digit('1')), ('2', lambda: self.digit('2')),
('3', lambda: self.digit('3')), ('+', self.add)],
# Row 5
[('0', lambda: self.digit('0')), ('.', self.decimal),
('±', self.negate), ('ENTER', self.enter)],
# Row 6: Special functions
[('SWAP', self.swap), ('DROP', self.drop),
('DUP', self.dup), ('CLR', self.clear)]
] ]
for row_idx, row in enumerate(buttons, start=2): for row_idx, row in enumerate(buttons, start=2):
for col_idx, (text, command) in enumerate(row): for col_idx, (text, command) in enumerate(row):
if text != "NULL":
btn = ttk.Button(parent, btn = ttk.Button(parent,
text=text, text=text,
command=command, command=command,
style='Calc.TButton',
width=8) width=8)
btn.grid(row=row_idx, column=col_idx, padx=2, pady=2, sticky=(tk.W, tk.E, tk.N, tk.S)) btn.grid(row=row_idx, column=col_idx, padx=2, pady=2, sticky=(tk.W, tk.E, tk.N, tk.S))
# Keyboard bindings # Keyboard bindings
self.root.bind('<Return>', lambda e: self.enter()) self.root.bind('<Delete>', lambda e: self.drop())
self.root.bind('<KP_Enter>', lambda e: self.enter()) self.root.bind('<Return>', lambda e: self.enter(True))
self.root.bind('<KP_Enter>', lambda e: self.enter(True))
for i in range(10): for i in range(10):
self.root.bind(str(i), lambda e, n=str(i): self.digit(n)) self.root.bind(str(i), lambda e, n=str(i): self.digit(n))
self.root.bind('.', lambda e: self.decimal()) self.root.bind('.', lambda e: self.decimal())
@ -125,7 +97,6 @@ class HPCalculator:
self.root.bind('-', lambda e: self.subtract()) self.root.bind('-', lambda e: self.subtract())
self.root.bind('*', lambda e: self.multiply()) self.root.bind('*', lambda e: self.multiply())
self.root.bind('/', lambda e: self.divide()) self.root.bind('/', lambda e: self.divide())
self.root.bind('<Escape>', lambda e: self.clear())
def digit(self, d): def digit(self, d):
"""Handle digit button press""" """Handle digit button press"""
@ -157,12 +128,14 @@ class HPCalculator:
self.entry_buffer = '-' + self.entry_buffer self.entry_buffer = '-' + self.entry_buffer
self.update_entry_display() self.update_entry_display()
def enter(self): def enter(self, key=False):
"""Push current entry onto stack""" """Push current entry onto stack"""
if self.entry_buffer: if self.entry_buffer:
self.execute_code(self.entry_buffer) self.execute_code(self.entry_buffer)
self.entry_buffer = "" self.entry_buffer = ""
self.is_new_entry = True self.is_new_entry = True
elif key:
self.execute_code("dup")
self.update_displays() self.update_displays()
def add(self): def add(self):
@ -219,21 +192,6 @@ class HPCalculator:
self.execute_code("drop") self.execute_code("drop")
self.update_displays() self.update_displays()
def dup(self):
"""Duplicate top stack item"""
self.enter()
self.execute_code("dup")
self.update_displays()
def clear(self):
"""Clear entry and stack"""
self.entry_buffer = ""
self.is_new_entry = True
# Clear the stack
while len(self.interp.stack) > 0:
self.interp.pop()
self.update_displays()
def execute_code(self, code): def execute_code(self, code):
"""Execute stack language code""" """Execute stack language code"""
try: try:
@ -274,7 +232,7 @@ class HPCalculator:
value_str = self.format_stack_entry(entry) value_str = self.format_stack_entry(entry)
self.stack_labels[i].config(text=f"T{level}: {value_str}") self.stack_labels[i].config(text=f"T{level}: {value_str}")
else: else:
self.stack_labels[i].config(text=f"T{level}: 0") self.stack_labels[i].config(text=f"T{level}: <>")
def format_stack_entry(self, entry): def format_stack_entry(self, entry):
"""Format a stack entry for display""" """Format a stack entry for display"""

View File

@ -6,7 +6,7 @@ from typing import TYPE_CHECKING, Optional, Tuple
if TYPE_CHECKING: if TYPE_CHECKING:
from .interpreter import InterpreterState, StackEntry from .interpreter import InterpreterState, StackEntry
from .interpreter import StackType, FunctionItem from .interpreter_types import StackType
from .lexer import Token, TokenType, IntegerLiteral, IntegerBuiltInType, Identifier from .lexer import Token, TokenType, IntegerLiteral, IntegerBuiltInType, Identifier
@ -34,45 +34,45 @@ def extract_numeric_value(entry: "StackEntry") -> Optional[Tuple[float, int, int
ival = 0 ival = 0
if entry.type == StackType.I64: if entry.type == StackType.I64:
ival = int(entry.value) ival = int(entry.value) # type: ignore
fval = float(ival) fval = float(ival)
flags = NumericTypeFlags.BITS_64 | NumericTypeFlags.SIGNED flags = NumericTypeFlags.BITS_64 | NumericTypeFlags.SIGNED
elif entry.type == StackType.I32: elif entry.type == StackType.I32:
ival = int(entry.value) ival = int(entry.value) # type: ignore
fval = float(ival) fval = float(ival)
flags = NumericTypeFlags.BITS_32 | NumericTypeFlags.SIGNED flags = NumericTypeFlags.BITS_32 | NumericTypeFlags.SIGNED
elif entry.type == StackType.I16: elif entry.type == StackType.I16:
ival = int(entry.value) ival = int(entry.value) # type: ignore
fval = float(ival) fval = float(ival)
flags = NumericTypeFlags.BITS_16 | NumericTypeFlags.SIGNED flags = NumericTypeFlags.BITS_16 | NumericTypeFlags.SIGNED
elif entry.type == StackType.I8: elif entry.type == StackType.I8:
ival = int(entry.value) ival = int(entry.value) # type: ignore
fval = float(ival) fval = float(ival)
flags = NumericTypeFlags.BITS_8 | NumericTypeFlags.SIGNED flags = NumericTypeFlags.BITS_8 | NumericTypeFlags.SIGNED
elif entry.type == StackType.U64: elif entry.type == StackType.U64:
ival = int(entry.value) ival = int(entry.value) # type: ignore
fval = float(ival) fval = float(ival)
flags = NumericTypeFlags.BITS_64 flags = NumericTypeFlags.BITS_64
elif entry.type == StackType.U32: elif entry.type == StackType.U32:
ival = int(entry.value) ival = int(entry.value) # type: ignore
fval = float(ival) fval = float(ival)
flags = NumericTypeFlags.BITS_32 flags = NumericTypeFlags.BITS_32
elif entry.type == StackType.U16: elif entry.type == StackType.U16:
ival = int(entry.value) ival = int(entry.value) # type: ignore
fval = float(ival) fval = float(ival)
flags = NumericTypeFlags.BITS_16 flags = NumericTypeFlags.BITS_16
elif entry.type == StackType.U8: elif entry.type == StackType.U8:
ival = int(entry.value) ival = int(entry.value) # type: ignore
fval = float(ival) fval = float(ival)
flags = NumericTypeFlags.BITS_8 flags = NumericTypeFlags.BITS_8
elif entry.type == StackType.FLOAT: elif entry.type == StackType.FLOAT:
fval = float(entry.value) fval = float(entry.value) # type: ignore
flags = NumericTypeFlags.BITS_32 | NumericTypeFlags.FLOAT flags = NumericTypeFlags.BITS_32 | NumericTypeFlags.FLOAT
elif entry.type == StackType.DOUBLE: elif entry.type == StackType.DOUBLE:
fval = float(entry.value) fval = float(entry.value) # type: ignore
flags = NumericTypeFlags.BITS_64 | NumericTypeFlags.FLOAT flags = NumericTypeFlags.BITS_64 | NumericTypeFlags.FLOAT
elif entry.type == StackType.CHARACTER: elif entry.type == StackType.CHARACTER:
ival = int(entry.value) ival = int(entry.value) # type: ignore
fval = float(ival) fval = float(ival)
flags = NumericTypeFlags.BITS_8 flags = NumericTypeFlags.BITS_8
elif entry.type == StackType.BOOLEAN: elif entry.type == StackType.BOOLEAN:
@ -177,36 +177,36 @@ def is_truthy(entry: "StackEntry") -> bool:
return bool(entry.value) return bool(entry.value)
elif entry.type in (StackType.TOKEN_STRING, StackType.CALLABLE): elif entry.type in (StackType.TOKEN_STRING, StackType.CALLABLE):
ts = entry.value ts = entry.value
return len(ts.tokens) > 0 and ts.tokens[0].type != TokenType.EOF return len(ts.tokens) > 0 and ts.tokens[0].type != TokenType.EOF # type: ignore
return False return False
def get_scalar_value(entry: "StackEntry") -> Optional[int]: def get_scalar_value(entry: "StackEntry") -> Optional[int]:
"""Extract a scalar (non-negative integer) value from stack entry""" """Extract a scalar (non-negative integer) value from stack entry"""
if entry.type == StackType.I64: if entry.type == StackType.I64:
val = int(entry.value) val = int(entry.value) # type: ignore
if val < 0: if val < 0:
return None return None
return val return val
elif entry.type == StackType.I32: elif entry.type == StackType.I32:
val = int(entry.value) val = int(entry.value) # type: ignore
if val < 0: if val < 0:
return None return None
return val return val
elif entry.type == StackType.I16: elif entry.type == StackType.I16:
val = int(entry.value) val = int(entry.value) # type: ignore
if val < 0: if val < 0:
return None return None
return val return val
elif entry.type == StackType.I8: elif entry.type == StackType.I8:
val = int(entry.value) val = int(entry.value) # type: ignore
if val < 0: if val < 0:
return None return None
return val return val
elif entry.type in (StackType.U64, StackType.U32, StackType.U16, StackType.U8): elif entry.type in (StackType.U64, StackType.U32, StackType.U16, StackType.U8):
return int(entry.value) return int(entry.value) # type: ignore
elif entry.type == StackType.CHARACTER: elif entry.type == StackType.CHARACTER:
return int(entry.value) return int(entry.value) # type: ignore
elif entry.type == StackType.BOOLEAN: elif entry.type == StackType.BOOLEAN:
return 1 if entry.value else 0 return 1 if entry.value else 0
else: else:
@ -800,7 +800,7 @@ def builtin_dup(state: "InterpreterState") -> bool:
# Deep copy for token strings # Deep copy for token strings
if top.type in (StackType.TOKEN_STRING, StackType.CALLABLE): if top.type in (StackType.TOKEN_STRING, StackType.CALLABLE):
value_copy = top.value.deep_copy() value_copy = top.value.deep_copy() # type: ignore
else: else:
value_copy = top.value value_copy = top.value
@ -825,8 +825,8 @@ def builtin_swap(state: "InterpreterState") -> bool:
a = state.pop() a = state.pop()
b = state.pop() b = state.pop()
state.push(a) state.push(a) # type: ignore
state.push(b) state.push(b) # type: ignore
return True return True
@ -869,7 +869,7 @@ def builtin_pick(state: "InterpreterState") -> bool:
# Deep copy for token strings # Deep copy for token strings
if picked.type in (StackType.TOKEN_STRING, StackType.CALLABLE): if picked.type in (StackType.TOKEN_STRING, StackType.CALLABLE):
value_copy = picked.value.deep_copy() value_copy = picked.value.deep_copy() # type: ignore
else: else:
value_copy = picked.value value_copy = picked.value
@ -937,13 +937,13 @@ def builtin_if(state: "InterpreterState") -> bool:
condition = state.pop() condition = state.pop()
# Check that blocks are executable # Check that blocks are executable
if else_block.type not in (StackType.TOKEN_STRING, StackType.CALLABLE, StackType.IDENTIFIER): if else_block.type not in (StackType.TOKEN_STRING, StackType.CALLABLE, StackType.IDENTIFIER): # type: ignore
return False return False
if then_block.type not in (StackType.TOKEN_STRING, StackType.CALLABLE, StackType.IDENTIFIER): if then_block.type not in (StackType.TOKEN_STRING, StackType.CALLABLE, StackType.IDENTIFIER): # type: ignore
return False return False
# Evaluate condition # Evaluate condition
is_true = is_truthy(condition) is_true = is_truthy(condition) # type: ignore
# Execute appropriate block # Execute appropriate block
if is_true: if is_true:
@ -951,10 +951,10 @@ def builtin_if(state: "InterpreterState") -> bool:
else: else:
block_to_execute = else_block block_to_execute = else_block
if block_to_execute.type == StackType.IDENTIFIER: if block_to_execute.type == StackType.IDENTIFIER: # type: ignore
return state.execute_func(block_to_execute.value.name) return state.execute_func(block_to_execute.value.name) # type: ignore
else: else:
return state.execute_token_string(block_to_execute.value) return state.execute_token_string(block_to_execute.value) # type: ignore
def builtin_while(state: "InterpreterState") -> bool: def builtin_while(state: "InterpreterState") -> bool:
@ -966,18 +966,18 @@ def builtin_while(state: "InterpreterState") -> bool:
condition_block = state.pop() condition_block = state.pop()
# Check that blocks are executable # Check that blocks are executable
if body_block.type not in (StackType.TOKEN_STRING, StackType.CALLABLE, StackType.IDENTIFIER): if body_block.type not in (StackType.TOKEN_STRING, StackType.CALLABLE, StackType.IDENTIFIER): # type: ignore
return False return False
if condition_block.type not in (StackType.TOKEN_STRING, StackType.CALLABLE, StackType.IDENTIFIER): if condition_block.type not in (StackType.TOKEN_STRING, StackType.CALLABLE, StackType.IDENTIFIER): # type: ignore
return False return False
while True: while True:
# Execute condition block # Execute condition block
if condition_block.type == StackType.IDENTIFIER: if condition_block.type == StackType.IDENTIFIER: # type: ignore
if not state.execute_func(condition_block.value.name): if not state.execute_func(condition_block.value.name): # type: ignore
return False return False
else: else:
if not state.execute_token_string(condition_block.value): if not state.execute_token_string(condition_block.value): # type: ignore
return False return False
# Check result # Check result
@ -985,15 +985,15 @@ def builtin_while(state: "InterpreterState") -> bool:
return False return False
condition_result = state.pop() condition_result = state.pop()
if not is_truthy(condition_result): if not is_truthy(condition_result): # type: ignore
break break
# Execute body block # Execute body block
if body_block.type == StackType.IDENTIFIER: if body_block.type == StackType.IDENTIFIER: # type: ignore
if not state.execute_func(body_block.value.name): if not state.execute_func(body_block.value.name): # type: ignore
return False return False
else: else:
if not state.execute_token_string(body_block.value): if not state.execute_token_string(body_block.value): # type: ignore
return False return False
return True return True
@ -1009,11 +1009,11 @@ def builtin_for(state: "InterpreterState") -> bool:
start_item = state.pop() start_item = state.pop()
# Check that block is executable # Check that block is executable
if body_block.type not in (StackType.TOKEN_STRING, StackType.CALLABLE, StackType.IDENTIFIER): if body_block.type not in (StackType.TOKEN_STRING, StackType.CALLABLE, StackType.IDENTIFIER): # type: ignore
return False return False
start_val = get_scalar_value(start_item) start_val = get_scalar_value(start_item) # type: ignore
end_val = get_scalar_value(end_item) end_val = get_scalar_value(end_item) # type: ignore
if start_val is None or end_val is None: if start_val is None or end_val is None:
return False return False
@ -1028,11 +1028,11 @@ def builtin_for(state: "InterpreterState") -> bool:
return False return False
# Execute body # Execute body
if body_block.type == StackType.IDENTIFIER: if body_block.type == StackType.IDENTIFIER: # type: ignore
if not state.execute_func(body_block.value.name): if not state.execute_func(body_block.value.name): # type: ignore
return False return False
else: else:
if not state.execute_token_string(body_block.value): if not state.execute_token_string(body_block.value): # type: ignore
return False return False
return True return True
@ -1049,10 +1049,10 @@ def builtin_eval(state: "InterpreterState") -> bool:
code_target = state.pop() code_target = state.pop()
if code_target.type in (StackType.TOKEN_STRING, StackType.CALLABLE): if code_target.type in (StackType.TOKEN_STRING, StackType.CALLABLE): # type: ignore
return state.execute_token_string(code_target.value) return state.execute_token_string(code_target.value) # type: ignore
elif code_target.type == StackType.IDENTIFIER: elif code_target.type == StackType.IDENTIFIER: # type: ignore
return state.execute_func(code_target.value.name) return state.execute_func(code_target.value.name) # type: ignore
else: else:
return False return False
@ -1077,21 +1077,20 @@ def builtin_const(state: "InterpreterState") -> bool:
name_entry = state.pop() name_entry = state.pop()
value_entry = state.pop() value_entry = state.pop()
if name_entry.type != StackType.IDENTIFIER: if name_entry.type != StackType.IDENTIFIER: # type: ignore
return False return False
if value_entry.type != StackType.CALLABLE: if value_entry.type != StackType.CALLABLE: # type: ignore
return False return False
name = name_entry.value.name name = name_entry.value.name # type: ignore
# Check if function already exists # Check if function already exists
if state.get_function(name) is not None: if state.get_function(name) is not None:
return False return False
# Create function item # Create function item
func_item = FunctionItem.from_token_string(value_entry.value) state.add_function(name, value_entry.value) # type: ignore
state.add_function(name, func_item)
return True return True
@ -1122,7 +1121,7 @@ def builtin_type_of(state: "InterpreterState") -> bool:
StackType.CALLABLE: "Callable", StackType.CALLABLE: "Callable",
} }
type_name = type_names.get(item.type, "Unknown") type_name = type_names.get(item.type, "Unknown") # type: ignore
return state.push_token(Token( return state.push_token(Token(
type=TokenType.IDENTIFIER, type=TokenType.IDENTIFIER,
@ -1234,8 +1233,7 @@ def load_builtins(interpreter_state: "InterpreterState") -> bool:
# Register all builtins # Register all builtins
for name, func in builtins.items(): for name, func in builtins.items():
func_item = FunctionItem.from_builtin(func) interpreter_state.add_function(name, func)
interpreter_state.add_function(name, func_item)
# Load SLS-defined builtins # Load SLS-defined builtins
try: try:

View File

@ -11,27 +11,10 @@ from .lexer import (
IntegerBuiltInType, IntegerBuiltInType,
) )
from .interpreter_types import StackType
from .builtin import load_builtins from .builtin import load_builtins
class StackType(Enum):
IDENTIFIER = auto()
I64 = auto()
I32 = auto()
I16 = auto()
I8 = auto()
U64 = auto()
U32 = auto()
U16 = auto()
U8 = auto()
FLOAT = auto()
DOUBLE = auto()
CHARACTER = auto()
BOOLEAN = auto()
TOKEN_STRING = auto()
CALLABLE = auto()
@dataclass @dataclass
class StackEntry: class StackEntry:
type: StackType type: StackType
@ -42,6 +25,7 @@ class FunctionType(Enum):
TOKEN_STRING = auto() TOKEN_STRING = auto()
BUILTIN = auto() BUILTIN = auto()
type FunctionData = TokenString | Callable[["InterpreterState"], bool]
@dataclass @dataclass
class FunctionItem: class FunctionItem:
@ -49,6 +33,13 @@ class FunctionItem:
token_string: Optional[TokenString] = None token_string: Optional[TokenString] = None
builtin: Optional[Callable[["InterpreterState"], bool]] = None builtin: Optional[Callable[["InterpreterState"], bool]] = None
@classmethod
def from_item(cls, item: FunctionData) -> "FunctionItem":
if isinstance(item, TokenString):
return cls.from_token_string(item)
else:
return cls.from_builtin(item)
@classmethod @classmethod
def from_token_string(cls, ts: TokenString) -> "FunctionItem": def from_token_string(cls, ts: TokenString) -> "FunctionItem":
return cls(type=FunctionType.TOKEN_STRING, token_string=ts) return cls(type=FunctionType.TOKEN_STRING, token_string=ts)
@ -93,8 +84,8 @@ class InterpreterState:
# ------------------------- # -------------------------
# function table # function table
# ------------------------- # -------------------------
def add_function(self, name: str, item: FunctionItem) -> None: def add_function(self, name: str, item: FunctionData) -> None:
self.functions[name] = item self.functions[name] = FunctionItem.from_item(item)
def get_function(self, name: str) -> Optional[FunctionItem]: def get_function(self, name: str) -> Optional[FunctionItem]:
return self.functions.get(name) return self.functions.get(name)

View File

@ -0,0 +1,18 @@
from enum import Enum, auto
class StackType(Enum):
IDENTIFIER = auto()
I64 = auto()
I32 = auto()
I16 = auto()
I8 = auto()
U64 = auto()
U32 = auto()
U16 = auto()
U8 = auto()
FLOAT = auto()
DOUBLE = auto()
CHARACTER = auto()
BOOLEAN = auto()
TOKEN_STRING = auto()
CALLABLE = auto()

View File

@ -306,7 +306,7 @@ class Lexer:
# Skip comments # Skip comments
if (c == '/' and self.far_peek(1) == '/') or c == '#': if (c == '/' and self.far_peek(1) == '/') or c == '#':
while self.peek() not in ('\n', '\0'): while self.peek() not in ('\n', '\0'):
self.advance() c = self.advance()
# Skip whitespace # Skip whitespace
if c.isspace(): if c.isspace():