mirror of
https://github.com/irmen/prog8.git
synced 2024-11-22 15:33:02 +00:00
ply
This commit is contained in:
parent
6511283bb8
commit
3c70790fbf
289
il65/lexer.py
Normal file
289
il65/lexer.py
Normal file
@ -0,0 +1,289 @@
|
||||
import sys
|
||||
from .symbols import SourceRef
|
||||
import ply.lex
|
||||
|
||||
# token names
|
||||
|
||||
tokens = (
|
||||
"INTEGER",
|
||||
"FLOATINGPOINT",
|
||||
"DOTTEDNAME",
|
||||
"NAME",
|
||||
"DOT",
|
||||
"IS",
|
||||
"CLOBBEREDREGISTER",
|
||||
"REGISTER",
|
||||
"COMMENT",
|
||||
"DIRECTIVE",
|
||||
"AUGASSIGN",
|
||||
"EQUAL",
|
||||
"NOTEQUAL",
|
||||
"RARROW",
|
||||
"RETURN",
|
||||
"TILDE",
|
||||
"VARTYPE",
|
||||
"KEYWORD",
|
||||
"SUB",
|
||||
"DATATYPE",
|
||||
"CHARACTER",
|
||||
"STRING",
|
||||
"BOOLEAN",
|
||||
"GOTO",
|
||||
"INCR",
|
||||
"DECR",
|
||||
"NOT",
|
||||
"LT",
|
||||
"GT",
|
||||
"LE",
|
||||
"GE",
|
||||
"LABEL",
|
||||
"IF",
|
||||
"ADDRESSOF",
|
||||
"PRESERVEREGS",
|
||||
"INLINEASM",
|
||||
)
|
||||
|
||||
literals = ['+', '-', '*', '/', '(', ')', '[', ']', '{', '}', '.', ',', '!', '?', ':']
|
||||
|
||||
# regex rules for simple tokens
|
||||
|
||||
t_ADDRESSOF = r"\#"
|
||||
t_IS = r"="
|
||||
t_TILDE = r"~"
|
||||
t_DIRECTIVE = r"%[a-z]+"
|
||||
t_AUGASSIGN = r"\+=|-=|/=|\*=|<<=|>>=|&=|\|=|\^="
|
||||
t_DECR = r"--"
|
||||
t_INCR = r"\+\+"
|
||||
t_EQUAL = r"=="
|
||||
t_NOTEQUAL = r"!="
|
||||
t_LT = r"<"
|
||||
t_GT = r">"
|
||||
t_LE = r"<="
|
||||
t_GE = r">="
|
||||
t_IF = "if(_[a-z]+)?"
|
||||
t_RARROW = r"->"
|
||||
|
||||
# ignore inline whitespace
|
||||
t_ignore = " \t"
|
||||
t_inlineasm_ignore = " \t\r\n"
|
||||
|
||||
|
||||
# states for allowing %asm inclusion of raw assembly
|
||||
states = (
|
||||
('inlineasm', 'exclusive'),
|
||||
)
|
||||
|
||||
# reserved words
|
||||
reserved = {
|
||||
"sub": "SUB",
|
||||
"var": "VARTYPE",
|
||||
"memory": "VARTYPE",
|
||||
"const": "VARTYPE",
|
||||
"goto": "GOTO",
|
||||
"return": "RETURN",
|
||||
"true": "BOOLEAN",
|
||||
"false": "BOOLEAN",
|
||||
"not": "NOT",
|
||||
"AX": "REGISTER",
|
||||
"AY": "REGISTER",
|
||||
"XY": "REGISTER",
|
||||
"SC": "REGISTER",
|
||||
"SI": "REGISTER",
|
||||
"SZ": "REGISTER",
|
||||
"A": "REGISTER",
|
||||
"X": "REGISTER",
|
||||
"Y": "REGISTER",
|
||||
"if": "IF",
|
||||
"if_true": "IF",
|
||||
"if_not": "IF",
|
||||
"if_ne": "IF",
|
||||
"if_eq": "IF",
|
||||
"if_cc": "IF",
|
||||
"if_cs": "IF",
|
||||
"if_vc": "IF",
|
||||
"if_vs": "IF",
|
||||
"if_gt": "IF",
|
||||
"if_lt": "IF",
|
||||
"if_pos": "IF",
|
||||
"if_get": "IF",
|
||||
}
|
||||
|
||||
|
||||
# rules for tokens with some actions
|
||||
|
||||
def t_inlineasm(t):
|
||||
r"%asm\s*\{\s*"
|
||||
t.lexer.code_start = t.lexer.lexpos # Record start position
|
||||
t.lexer.level = 1 # initial brace level
|
||||
t.lexer.begin("inlineasm") # enter state 'inlineasm'
|
||||
t.lexer.lineno += 1
|
||||
|
||||
|
||||
def t_inlineasm_lbrace(t):
|
||||
r"\{"
|
||||
t.lexer.level += 1
|
||||
|
||||
|
||||
def t_inlineasm_rbrace(t):
|
||||
r"\}"
|
||||
t.lexer.level -= 1
|
||||
#if closing brace, return code fragment
|
||||
if t.lexer.level == 0:
|
||||
t.value = t.lexer.lexdata[t.lexer.code_start:t.lexer.lexpos-1]
|
||||
t.type = "INLINEASM"
|
||||
t.lexer.lineno += t.value.count("\n")
|
||||
t.lexer.begin("INITIAL") # back to normal lexing rules
|
||||
return t
|
||||
|
||||
|
||||
def t_inlineasm_comment(t):
|
||||
r";[^\n]*"
|
||||
pass
|
||||
|
||||
|
||||
def t_inlineasm_string(t):
|
||||
r"""(?x) # verbose mode
|
||||
(?<!\\) # not preceded by a backslash
|
||||
" # a literal double-quote
|
||||
.*? # 1-or-more characters
|
||||
(?<!\\) # not preceded by a backslash
|
||||
" # a literal double-quote
|
||||
|
|
||||
(?<!\\) # not preceded by a backslash
|
||||
' # a literal single quote
|
||||
.*? # 1-or-more characters
|
||||
(?<!\\) # not preceded by a backslash
|
||||
' # a literal double-quote
|
||||
"""
|
||||
pass
|
||||
|
||||
|
||||
def t_inlineasm_nonspace(t):
|
||||
r'[^\s\{\}\'\"]+'
|
||||
pass
|
||||
|
||||
|
||||
def t_inlineasm_error(t):
|
||||
# For bad characters, we just skip over it
|
||||
t.lexer.skip(1)
|
||||
|
||||
|
||||
def t_CLOBBEREDREGISTER(t):
|
||||
r"(AX|AY|XY|A|X|Y)\?"
|
||||
t.value = t.value[:-1]
|
||||
return t
|
||||
|
||||
|
||||
def t_DATATYPE(t):
|
||||
r"\.byte|\.wordarray|\.float|\.array|\.word|\.text|\.stext|\.ptext|\.pstext|\.matrix"
|
||||
t.value = t.value[1:]
|
||||
return t
|
||||
|
||||
|
||||
def t_LABEL(t):
|
||||
r"[a-zA-Z_]\w*\s*:"
|
||||
t.value = t.value[:-1].strip()
|
||||
return t
|
||||
|
||||
|
||||
def t_DOTTEDNAME(t):
|
||||
r"[a-zA-Z_]\w*(\.[a-zA-Z_]\w*)+"
|
||||
return t
|
||||
|
||||
|
||||
def t_NAME(t):
|
||||
r"[a-zA-Z_]\w*"
|
||||
t.type = reserved.get(t.value, "NAME") # check for reserved words
|
||||
return t
|
||||
|
||||
|
||||
def t_STRING(t):
|
||||
r"""(?x) # verbose mode
|
||||
(?<!\\) # not preceded by a backslash
|
||||
" # a literal double-quote
|
||||
.*? # 1-or-more characters
|
||||
(?<!\\) # not preceded by a backslash
|
||||
" # a literal double-quote
|
||||
|
|
||||
(?<!\\) # not preceded by a backslash
|
||||
' # a literal single quote
|
||||
.*? # 1-or-more characters
|
||||
(?<!\\) # not preceded by a backslash
|
||||
' # a literal double-quote
|
||||
"""
|
||||
t.value = t.value[1:-1]
|
||||
if len(t.value) == 1:
|
||||
t.type = "CHARACTER"
|
||||
if len(t.value) == 2 and t.value[0] == '\\':
|
||||
t.type = "CHARACTER"
|
||||
return t
|
||||
|
||||
|
||||
def t_FLOATINGPOINT(t):
|
||||
r"[-+]? (?: (?: \d* \. \d+ ) | (?: \d+ \.? ) )(?: [Ee] [+-]? \d+ ) ?"
|
||||
try:
|
||||
t.value = int(t.value)
|
||||
t.type = "INTEGER"
|
||||
except ValueError:
|
||||
t.value = float(t.value)
|
||||
return t
|
||||
|
||||
|
||||
def t_INTEGER(t):
|
||||
r"([-+]?\$?[a-fA-F\d]+ | [-+]?[\$%]?\d+ | [-+]?%?[01]+)(?!\.)"
|
||||
sign = 1
|
||||
if t.value[0] in "+-":
|
||||
sign = -1 if t.value[0] == "-" else 1
|
||||
t.value = t.value[1:]
|
||||
if t.value[0] == '$':
|
||||
t.value = int(t.value[1:], 16) * sign
|
||||
elif t.value[0] == '%':
|
||||
t.value = int(t.value[1:], 2) * sign
|
||||
else:
|
||||
t.value = int(t.value) * sign
|
||||
return t
|
||||
|
||||
|
||||
def t_COMMENT(t):
|
||||
r";[^\n]*"
|
||||
# don't include the \n at the end, that must be processed by t_newline
|
||||
return None # ignore comments for now
|
||||
|
||||
|
||||
def t_PRESERVEREGS(t):
|
||||
r"!\s*[AXY]{0,3}\s*"
|
||||
t.value = t.value[1:-1].strip()
|
||||
return t
|
||||
|
||||
|
||||
def t_newline(t):
|
||||
r"\n+"
|
||||
t.lexer.lineno += len(t.value)
|
||||
return None # ignore white space tokens
|
||||
|
||||
|
||||
def t_error(t):
|
||||
line, col = t.lineno, find_tok_column(t)
|
||||
sref = SourceRef("@todo-filename-f1", line, col)
|
||||
t.lexer.error_function("{}: Illegal character '{:s}'", sref, t.value[0])
|
||||
t.lexer.skip(1)
|
||||
|
||||
|
||||
def find_tok_column(token):
|
||||
""" Find the column of the token in its line."""
|
||||
last_cr = lexer.lexdata.rfind('\n', 0, token.lexpos)
|
||||
return token.lexpos - last_cr
|
||||
|
||||
|
||||
def error_function(fmtstring, *args):
|
||||
print("ERROR:", fmtstring.format(*args), file=sys.stderr)
|
||||
|
||||
|
||||
lexer = ply.lex.lex()
|
||||
lexer.error_function = error_function # can override this
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
ply.lex.runmain()
|
||||
#lexer = ply.lex.Lexer()
|
||||
#ply.lex.runmain(lexer=lexer)
|
486
il65/plyacc.py
Normal file
486
il65/plyacc.py
Normal file
@ -0,0 +1,486 @@
|
||||
from ply.yacc import yacc
|
||||
from .symbols import SourceRef, AstNode
|
||||
from .lexer import tokens, lexer, find_tok_column # get the lexer tokens. required.
|
||||
|
||||
|
||||
start = "start"
|
||||
|
||||
|
||||
class Module(AstNode):
|
||||
def __init__(self, nodes, sourceref):
|
||||
super().__init__(sourceref)
|
||||
self.nodes = nodes or []
|
||||
|
||||
|
||||
class Directive(AstNode):
|
||||
def __init__(self, name, args, sourceref):
|
||||
super().__init__(sourceref)
|
||||
self.name = name
|
||||
self.args = args or []
|
||||
|
||||
|
||||
class Block(AstNode):
|
||||
def __init__(self, name, address, scope, sourceref):
|
||||
super().__init__(sourceref)
|
||||
self.name = name
|
||||
self.address = address
|
||||
self.scope = scope
|
||||
|
||||
|
||||
class Scope(AstNode):
|
||||
def __init__(self, nodes, sourceref):
|
||||
super().__init__(sourceref)
|
||||
self.nodes = nodes
|
||||
|
||||
|
||||
class Label(AstNode):
|
||||
def __init__(self, name, sourceref):
|
||||
super().__init__(sourceref)
|
||||
self.name = name
|
||||
|
||||
|
||||
class Register(AstNode):
|
||||
def __init__(self, name, sourceref):
|
||||
super().__init__(sourceref)
|
||||
self.name = name
|
||||
|
||||
|
||||
class PreserveRegs(AstNode):
|
||||
def __init__(self, registers, sourceref):
|
||||
super().__init__(sourceref)
|
||||
self.registers = registers
|
||||
|
||||
|
||||
class Assignment(AstNode):
|
||||
def __init__(self, lhs, operator, rhs, sourceref):
|
||||
super().__init__(sourceref)
|
||||
self.lhs = lhs
|
||||
self.operator = operator
|
||||
self.rhs = rhs
|
||||
|
||||
|
||||
class SubCall(AstNode):
|
||||
def __init__(self, target, arguments, sourceref):
|
||||
super().__init__(sourceref)
|
||||
self.target = target
|
||||
self.arguments = arguments
|
||||
|
||||
|
||||
class InlineAssembly(AstNode):
|
||||
def __init__(self, assembly, sourceref):
|
||||
super().__init__(sourceref)
|
||||
self.assembly = assembly
|
||||
|
||||
|
||||
class VarDef(AstNode):
|
||||
def __init__(self, name, vartype, datatype, value, sourceref):
|
||||
super().__init__(sourceref)
|
||||
self.name = name
|
||||
self.vartype = vartype
|
||||
self.datatype = datatype
|
||||
self.value = value
|
||||
|
||||
|
||||
class Datatype(AstNode):
|
||||
def __init__(self, name, dimension, sourceref):
|
||||
super().__init__(sourceref)
|
||||
self.name = name
|
||||
self.dimension = dimension
|
||||
|
||||
|
||||
class Subroutine(AstNode):
|
||||
def __init__(self, name, paramspec, resultspec, code, sourceref):
|
||||
super().__init__(sourceref)
|
||||
self.name = name
|
||||
self.paramspec = paramspec
|
||||
self.resultspec = resultspec
|
||||
self.code = code
|
||||
|
||||
|
||||
class Goto(AstNode):
|
||||
def __init__(self, target, ifstmt, condition, sourceref):
|
||||
super().__init__(sourceref)
|
||||
self.target = target
|
||||
self.ifstmt = ifstmt
|
||||
self.condition = condition
|
||||
|
||||
|
||||
class UnaryOp(AstNode):
|
||||
def __init__(self, operator, operand, sourceref):
|
||||
super().__init__(sourceref)
|
||||
self.operator = operator
|
||||
self.operand = operand
|
||||
|
||||
|
||||
class BinaryOp(AstNode):
|
||||
def __init__(self, operator, left, right, sourceref):
|
||||
super().__init__(sourceref)
|
||||
self.operator = operator
|
||||
self.left = left
|
||||
self.right = right
|
||||
|
||||
|
||||
class Integer(AstNode):
|
||||
def __init__(self, value, sourceref):
|
||||
super().__init__(sourceref)
|
||||
self.value = value
|
||||
|
||||
|
||||
def p_start(p):
|
||||
"""start : empty
|
||||
| module_elements"""
|
||||
if p[1]:
|
||||
p[0] = Module(p[1], _token_sref(p, 1))
|
||||
|
||||
|
||||
def p_module(p):
|
||||
"""module_elements : module_elt
|
||||
| module_elements module_elt"""
|
||||
if len(p) == 2:
|
||||
p[0] = [p[1]]
|
||||
else:
|
||||
p[0] = p[1] + [p[2]]
|
||||
|
||||
|
||||
def p_module_elt(p):
|
||||
"""module_elt : directive
|
||||
| block"""
|
||||
p[0] = p[1]
|
||||
|
||||
|
||||
def p_directive(p):
|
||||
"""directive : DIRECTIVE
|
||||
| DIRECTIVE directive_args
|
||||
"""
|
||||
if len(p) == 2:
|
||||
p[0] = Directive(p[1], None, _token_sref(p, 1))
|
||||
else:
|
||||
p[0] = Directive(p[1], p[2], _token_sref(p, 1))
|
||||
|
||||
|
||||
def p_directive_args(p):
|
||||
"""directive_args : directive_arg
|
||||
| directive_args ',' directive_arg
|
||||
"""
|
||||
if len(p) == 2:
|
||||
p[0] = [p[1]]
|
||||
else:
|
||||
p[0] = p[1] + [p[3]]
|
||||
|
||||
|
||||
def p_directive_arg(p):
|
||||
"""directive_arg : NAME
|
||||
| INTEGER
|
||||
"""
|
||||
p[0] = p[1]
|
||||
|
||||
|
||||
def p_block(p):
|
||||
"""block : TILDE NAME INTEGER scope
|
||||
| TILDE NAME empty scope
|
||||
| TILDE empty empty scope"""
|
||||
p[0] = Block(p[2], p[3], p[4], _token_sref(p, 1))
|
||||
|
||||
|
||||
def p_scope(p):
|
||||
"""scope : '{' scope_elements_opt '}'"""
|
||||
p[0] = Scope(p[2], _token_sref(p, 1))
|
||||
|
||||
|
||||
def p_scope_elements_opt(p):
|
||||
"""scope_elements_opt : empty
|
||||
| scope_elements"""
|
||||
p[0] = p[1]
|
||||
|
||||
|
||||
def p_scope_elements(p):
|
||||
"""scope_elements : scope_element
|
||||
| scope_elements scope_element"""
|
||||
if len(p) == 2:
|
||||
p[0] = [p[1]]
|
||||
else:
|
||||
p[0] = p[1] + [p[2]]
|
||||
|
||||
|
||||
def p_scope_element(p):
|
||||
"""scope_element : directive
|
||||
| vardef
|
||||
| subroutine
|
||||
| label
|
||||
| inlineasm
|
||||
| statement"""
|
||||
p[0] = p[1]
|
||||
|
||||
|
||||
def p_label(p):
|
||||
"""label : LABEL"""
|
||||
p[0] = Label(p[1], _token_sref(p, 1))
|
||||
|
||||
|
||||
def p_inlineasm(p):
|
||||
"""inlineasm : INLINEASM"""
|
||||
p[0] = InlineAssembly(p[1], _token_sref(p, 1))
|
||||
|
||||
|
||||
def p_vardef(p):
|
||||
"""vardef : VARTYPE type_opt NAME IS literal_value
|
||||
| VARTYPE type_opt NAME"""
|
||||
if len(p) == 4:
|
||||
p[0] = VarDef(p[3], p[1], p[2], None, _token_sref(p, 1))
|
||||
else:
|
||||
p[0] = VarDef(p[3], p[1], p[2], p[5], _token_sref(p, 1))
|
||||
|
||||
|
||||
def p_type_opt(p):
|
||||
"""type_opt : DATATYPE
|
||||
| DATATYPE '(' dimensions ')'
|
||||
| empty"""
|
||||
if len(p) == 4:
|
||||
p[0] = Datatype(p[1], p[3], _token_sref(p, 1))
|
||||
elif p:
|
||||
p[0] = Datatype(p[1], None, _token_sref(p, 1))
|
||||
|
||||
|
||||
def p_dimensions(p):
|
||||
"""dimensions : INTEGER
|
||||
| dimensions ',' INTEGER"""
|
||||
if len(p)==2:
|
||||
p[0] = [p[1]]
|
||||
else:
|
||||
p[0] = p[1] + [p[3]]
|
||||
|
||||
|
||||
def p_literal_value(p):
|
||||
"""literal_value : INTEGER
|
||||
| FLOATINGPOINT
|
||||
| STRING
|
||||
| CHARACTER
|
||||
| BOOLEAN"""
|
||||
p[0] = p[1]
|
||||
|
||||
|
||||
def p_subroutine(p):
|
||||
"""subroutine : SUB NAME '(' sub_param_spec ')' RARROW '(' sub_result_spec ')' subroutine_body"""
|
||||
p[0] = Subroutine(p[2], p[4], p[8], p[10], _token_sref(p, 1))
|
||||
|
||||
|
||||
def p_sub_param_spec(p):
|
||||
"""sub_param_spec : empty
|
||||
| sub_param_list"""
|
||||
p[0] = p[1]
|
||||
|
||||
|
||||
def p_sub_param_list(p):
|
||||
"""sub_param_list : sub_param
|
||||
| sub_param_list ',' sub_param"""
|
||||
if len(p) == 2:
|
||||
p[0] = [p[1]]
|
||||
else:
|
||||
p[0] = p[1] + [p[2]]
|
||||
|
||||
|
||||
def p_sub_param(p):
|
||||
"""sub_param : LABEL REGISTER
|
||||
| empty REGISTER"""
|
||||
p[0] = (p[1], p[2])
|
||||
|
||||
|
||||
def p_param_name(p):
|
||||
"""param_name : NAME ':'"""
|
||||
p[0] = p[1]
|
||||
|
||||
|
||||
def p_sub_result_spec(p):
|
||||
"""sub_result_spec : empty
|
||||
| '?'
|
||||
| sub_result_list"""
|
||||
if p[1] == '?':
|
||||
p[0] = ['A', 'X', 'Y'] # '?' means: all registers clobbered
|
||||
p[0] = p[1]
|
||||
|
||||
|
||||
def p_sub_result_list(p):
|
||||
"""sub_result_list : sub_result_reg
|
||||
| sub_result_list ',' sub_result_reg"""
|
||||
if len(p) == 2:
|
||||
p[0] = [p[1]]
|
||||
else:
|
||||
p[0] = p[1] + [p[3]]
|
||||
|
||||
|
||||
def p_sub_result_reg(p):
|
||||
"""sub_result_reg : REGISTER
|
||||
| CLOBBEREDREGISTER"""
|
||||
p[0] = p[1]
|
||||
|
||||
|
||||
def p_subroutine_body(p):
|
||||
"""subroutine_body : scope
|
||||
| IS INTEGER"""
|
||||
if len(p) == 2:
|
||||
p[0] = p[1]
|
||||
else:
|
||||
p[0] = p[2]
|
||||
|
||||
|
||||
def p_statement(p):
|
||||
"""statement : assignment
|
||||
| subroutine_call
|
||||
| goto
|
||||
| conditional_goto
|
||||
| incrdecr
|
||||
| RETURN
|
||||
"""
|
||||
p[0] = p[1]
|
||||
|
||||
|
||||
def p_incrdecr(p):
|
||||
"""incrdecr : register INCR
|
||||
| register DECR
|
||||
| symbolname INCR
|
||||
| symbolname DECR"""
|
||||
p[0] = UnaryOp(p[2], p[1], _token_sref(p, 1))
|
||||
|
||||
|
||||
def p_call_subroutine(p):
|
||||
"""subroutine_call : symbolname preserveregs_opt '(' call_arguments_opt ')'"""
|
||||
p[0] = SubCall(p[1], p[3], _token_sref(p, 1))
|
||||
|
||||
|
||||
def p_preserveregs_opt(p):
|
||||
"""preserveregs_opt : empty
|
||||
| preserveregs"""
|
||||
p[0] = p[1]
|
||||
|
||||
|
||||
def p_preserveregs(p):
|
||||
"""preserveregs : PRESERVEREGS"""
|
||||
p[0] = PreserveRegs(p[1], _token_sref(p, 1))
|
||||
|
||||
|
||||
def p_call_arguments_opt(p):
|
||||
"""call_arguments_opt : empty
|
||||
| call_arguments"""
|
||||
p[0] = p[1]
|
||||
|
||||
|
||||
def p_call_arguments(p):
|
||||
"""call_arguments : call_argument
|
||||
| call_arguments ',' call_argument"""
|
||||
if len(p) == 2:
|
||||
p[0] = [p[1]]
|
||||
else:
|
||||
p[0] = p[1] + [p[3]]
|
||||
|
||||
|
||||
def p_call_argument(p):
|
||||
"""call_argument : literal_value
|
||||
| register"""
|
||||
p[0] = p[1]
|
||||
|
||||
|
||||
def p_register(p):
|
||||
"""register : REGISTER"""
|
||||
p[0] = Register(p[1], _token_sref(p, 1))
|
||||
|
||||
|
||||
def p_goto(p):
|
||||
"""goto : GOTO symbolname
|
||||
| GOTO INTEGER"""
|
||||
p[0] = Goto(p[2], None, None, _token_sref(p, 1))
|
||||
|
||||
|
||||
def p_conditional_goto(p):
|
||||
"""conditional_goto : IF GOTO symbolname"""
|
||||
# @todo support conditional expression
|
||||
p[0] = Goto(p[3], p[1], None, _token_sref(p, 1))
|
||||
|
||||
|
||||
def p_symbolname(p):
|
||||
"""symbolname : NAME
|
||||
| DOTTEDNAME"""
|
||||
p[0] = p[1]
|
||||
|
||||
|
||||
def p_assignment(p):
|
||||
"""assignment : assignment_lhs assignment_operator assignment_rhs"""
|
||||
# @todo replace lhs/rhs by expressions
|
||||
p[0] = Assignment(p[1], p[2], p[3], _token_sref(p, 1))
|
||||
|
||||
|
||||
def p_assignment_operator(p):
|
||||
"""assignment_operator : IS
|
||||
| AUGASSIGN"""
|
||||
p[0] = p[1]
|
||||
|
||||
|
||||
def p_unary_operator(p):
|
||||
"""unary_operator : '+'
|
||||
| '-'
|
||||
| NOT
|
||||
| ADDRESSOF"""
|
||||
p[0] = p[1]
|
||||
|
||||
|
||||
def p_assignment_lhs(p):
|
||||
"""assignment_lhs : register
|
||||
| symbolname
|
||||
| assignment_lhs ',' register
|
||||
| assignment_lhs ',' symbolname"""
|
||||
if len(p) == 2:
|
||||
p[0] = [p[1]]
|
||||
else:
|
||||
p[0] = p[1] + [p[2]]
|
||||
|
||||
|
||||
def p_assignment_rhs(p):
|
||||
"""assignment_rhs : literal_value
|
||||
| symbolname
|
||||
| register
|
||||
| subroutine_call"""
|
||||
p[0] = p[1]
|
||||
|
||||
|
||||
def p_term(p):
|
||||
"""term : register"""
|
||||
p[0] = p[1]
|
||||
|
||||
|
||||
def p_empty(p):
|
||||
"""empty :"""
|
||||
pass
|
||||
|
||||
|
||||
def p_error(p):
|
||||
if p:
|
||||
sref = SourceRef("@todo-filename2", p.lineno, find_tok_column(p))
|
||||
lexer.error_function("{}: before '{:.20s}' ({})", sref, str(p.value), repr(p))
|
||||
else:
|
||||
lexer.error_function("{}: at end of input", "@todo-filename3")
|
||||
|
||||
|
||||
def _token_sref(p, token_idx):
|
||||
""" Returns the coordinates for the YaccProduction object 'p' indexed
|
||||
with 'token_idx'. The coordinate includes the 'lineno' and
|
||||
'column'. Both follow the lex semantic, starting from 1.
|
||||
"""
|
||||
last_cr = p.lexer.lexdata.rfind('\n', 0, p.lexpos(token_idx))
|
||||
if last_cr < 0:
|
||||
last_cr = -1
|
||||
column = (p.lexpos(token_idx) - last_cr)
|
||||
return SourceRef("@todo-filename", p.lineno(token_idx), column)
|
||||
|
||||
|
||||
precedence = (
|
||||
('nonassoc', "COMMENT"),
|
||||
)
|
||||
|
||||
parser = yacc()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
import sys
|
||||
file=sys.stdin # open(sys.argv[1], "rU")
|
||||
result = parser.parse(input=file.read()) or Module(None, SourceRef("@todo-sfile", 1, 1))
|
||||
print("RESULT")
|
||||
print(result.nodes)
|
@ -974,7 +974,7 @@ sub print_word_decimal0 (word: XY) -> (?) {
|
||||
}
|
||||
|
||||
|
||||
sub print_word_decimal (word: XY) -> (A?, X? Y?) {
|
||||
sub print_word_decimal (word: XY) -> (A?, X?, Y?) {
|
||||
; ---- print the word in X/Y in decimal form, without left padding 0s
|
||||
%asm {
|
||||
jsr word2decimal
|
||||
|
@ -21,7 +21,7 @@
|
||||
sub sub4 (string: XY, other : A) -> (Y?) = $dd22
|
||||
|
||||
|
||||
bar
|
||||
bar:
|
||||
|
||||
goto $c000
|
||||
goto [$c000.word]
|
||||
@ -134,7 +134,7 @@ bar
|
||||
|
||||
~ main {
|
||||
|
||||
start
|
||||
start:
|
||||
foo.bar()
|
||||
return
|
||||
|
||||
|
@ -1,13 +1,14 @@
|
||||
%output prg,basic
|
||||
|
||||
%import "c64lib"
|
||||
%import c64lib
|
||||
|
||||
|
||||
~ main {
|
||||
var .word value
|
||||
memory .word memvalue = $8000
|
||||
|
||||
|
||||
start
|
||||
start:
|
||||
A = 100
|
||||
|
||||
|
||||
@ -29,7 +30,7 @@ start
|
||||
;if_cc goto $c000
|
||||
;if_cc goto [$c000.word]
|
||||
|
||||
label
|
||||
label:
|
||||
; conditional if with a single 'truth' value (register)
|
||||
if_true A goto label2
|
||||
if_not A goto label2
|
||||
@ -48,7 +49,7 @@ label
|
||||
if_zero XY goto label2
|
||||
if XY goto label2
|
||||
|
||||
label2
|
||||
label2:
|
||||
; conditional if with a single 'truth' value (variable)
|
||||
if_true value goto label3
|
||||
if_not value goto label3
|
||||
@ -59,7 +60,7 @@ label2
|
||||
if_zero memvalue goto label3
|
||||
if memvalue goto label3
|
||||
|
||||
label3
|
||||
label3:
|
||||
; conditional if with a single 'truth' value (indirect address)
|
||||
if_true [$c000] goto label4
|
||||
if_not [$c000] goto label4
|
||||
@ -72,7 +73,7 @@ label3
|
||||
if_true [A] goto label4
|
||||
if_true [Y] goto label4
|
||||
|
||||
label4
|
||||
label4:
|
||||
return
|
||||
}
|
||||
|
||||
@ -87,18 +88,18 @@ label4
|
||||
var .word wordvar = 22345
|
||||
|
||||
|
||||
start
|
||||
start:
|
||||
c64.init_system()
|
||||
|
||||
A = 0
|
||||
printloop
|
||||
printloop:
|
||||
c64scr.print_byte_decimal(A)
|
||||
c64.CHROUT('\n')
|
||||
A++
|
||||
if A <20 goto printloop
|
||||
return
|
||||
|
||||
label1
|
||||
label1:
|
||||
if_true A==123 goto label1
|
||||
if_true A == 123 goto label1
|
||||
if_true A!=0 goto label1
|
||||
@ -138,6 +139,6 @@ label1
|
||||
if_true wordvar goto label2
|
||||
|
||||
|
||||
label2
|
||||
label2:
|
||||
return
|
||||
}
|
||||
|
@ -4,7 +4,7 @@
|
||||
%zp clobber
|
||||
|
||||
|
||||
%import "c64lib"
|
||||
%import c64lib
|
||||
|
||||
~ ZP {
|
||||
; ZeroPage block definition:
|
||||
@ -72,7 +72,7 @@
|
||||
var .wordarray(10) init_wordarray = $1234
|
||||
var .wordarray(10) init_wordarrayb = true
|
||||
|
||||
var .text text = "hello"+"-null"
|
||||
var .text text = "hello-null"
|
||||
var .ptext ptext = 'hello-pascal'
|
||||
var .stext stext = 'screencodes-null'
|
||||
var .pstext pstext = "screencodes-pascal"
|
||||
|
@ -2,10 +2,10 @@
|
||||
|
||||
%output prg, basic
|
||||
|
||||
%import "c64lib"
|
||||
%import c64lib
|
||||
|
||||
~ main_testing {
|
||||
start
|
||||
start:
|
||||
var .float myfloat1 = 1234.56789
|
||||
var .float myfloat2 = 9876.54321
|
||||
var .float myfloatneg1 = -555.666
|
||||
@ -52,7 +52,7 @@ sub printflt (float: AY) -> (?) {
|
||||
}
|
||||
|
||||
|
||||
start
|
||||
start:
|
||||
; assign some float values to the memory
|
||||
AY = #flt_pi
|
||||
some_address = # flt_pi
|
||||
@ -112,7 +112,7 @@ start
|
||||
printflt(# flt_point25)
|
||||
printflt(#c64.FL_FR4)
|
||||
|
||||
reg_to_float
|
||||
reg_to_float:
|
||||
c64.CHROUT!('\n')
|
||||
|
||||
A=33
|
||||
|
@ -1,12 +1,12 @@
|
||||
%output prg,basic
|
||||
|
||||
%import "c64lib"
|
||||
%import c64lib
|
||||
|
||||
~ main {
|
||||
var .text name = "?"*80
|
||||
var .text name = "????????????????????????????????????????????????????????????????????????????????" ; 80
|
||||
var .word orig_irq
|
||||
|
||||
start
|
||||
start:
|
||||
c64.init_system()
|
||||
|
||||
orig_irq = c64.CINV
|
||||
@ -19,7 +19,7 @@ start
|
||||
c64scr.input_chars(name)
|
||||
c64.CHROUT('\n')
|
||||
|
||||
blop
|
||||
blop:
|
||||
%breakpoint ; yeah!
|
||||
|
||||
c64scr.print_string("thank you, mr or mrs: ")
|
||||
@ -33,7 +33,7 @@ blop
|
||||
return
|
||||
|
||||
|
||||
irq_handler
|
||||
irq_handler:
|
||||
%asm {
|
||||
lda c64.SFDX
|
||||
cmp #$40 ; nothing pressed?
|
||||
|
@ -1,6 +1,6 @@
|
||||
%output prg,basic
|
||||
%import "c64lib"
|
||||
%import "mathlib"
|
||||
%import c64lib
|
||||
%import mathlib
|
||||
|
||||
~ main {
|
||||
var .text name = '?' * 80
|
||||
@ -9,7 +9,7 @@
|
||||
var attempts_left = 10
|
||||
|
||||
|
||||
start
|
||||
start:
|
||||
c64.init_system()
|
||||
|
||||
A = c64.VMCSB
|
||||
@ -41,7 +41,7 @@ start
|
||||
|
||||
c64scr.print_string("I am thinking of a number from 1 to 100!You'll have to guess it!\n")
|
||||
|
||||
printloop
|
||||
printloop:
|
||||
c64scr.print_string("\nYou have ")
|
||||
c64scr.print_byte_decimal(attempts_left)
|
||||
c64scr.print_string(" guess")
|
||||
@ -51,7 +51,7 @@ printloop
|
||||
A--
|
||||
if_zero A goto ask_guess
|
||||
c64scr.print_string("es")
|
||||
ask_guess
|
||||
ask_guess:
|
||||
c64scr.print_string(" left.\nWhat is your next guess? ")
|
||||
Y = c64scr.input_chars(guess)
|
||||
c64.CHROUT('\n')
|
||||
@ -65,21 +65,21 @@ ask_guess
|
||||
c64scr.print_string("low!\n")
|
||||
goto continue
|
||||
|
||||
correct_guess
|
||||
correct_guess:
|
||||
c64scr.print_string("\nThat's my number, impressive!\n")
|
||||
goodbye()
|
||||
return
|
||||
|
||||
too_high
|
||||
too_high:
|
||||
c64scr.print_string("That is too ")
|
||||
c64scr.print_string("high!\n")
|
||||
|
||||
continue
|
||||
continue:
|
||||
attempts_left--
|
||||
if_zero attempts_left goto game_over
|
||||
goto printloop
|
||||
|
||||
game_over
|
||||
game_over:
|
||||
c64scr.print_string("\nToo bad! It was: ")
|
||||
c64scr.print_byte_decimal(secretnumber)
|
||||
c64.CHROUT('\n')
|
||||
|
@ -26,7 +26,7 @@
|
||||
var .wordarray(10) words2 = $bbcc
|
||||
|
||||
|
||||
start ;foo
|
||||
start: ;foo
|
||||
X = 55
|
||||
Y = $77
|
||||
Y = X
|
||||
@ -63,7 +63,7 @@ start ;foo
|
||||
; [646,Y] = [$d020,X]
|
||||
|
||||
|
||||
_loop block2.zpw1 ++
|
||||
_loop: block2.zpw1 ++
|
||||
A ++
|
||||
X ++
|
||||
Y ++
|
||||
@ -103,7 +103,7 @@ sub customsub (Y)->() {
|
||||
}
|
||||
|
||||
|
||||
somelabel1222
|
||||
somelabel1222:
|
||||
customsub(2)
|
||||
return
|
||||
|
||||
@ -119,7 +119,7 @@ somelabel1222
|
||||
}
|
||||
|
||||
~ block3 {
|
||||
somelabel1
|
||||
somelabel1:
|
||||
%asm {
|
||||
nop
|
||||
nop
|
||||
@ -180,7 +180,8 @@ somelabel1
|
||||
~ fidget $1000
|
||||
{
|
||||
|
||||
subroutine
|
||||
subroutine:
|
||||
|
||||
; subroutine (A, X, Y)
|
||||
;[border2] = red
|
||||
;[screen2] = white
|
||||
|
@ -7,7 +7,7 @@
|
||||
}
|
||||
|
||||
~ main {
|
||||
start
|
||||
start:
|
||||
A=0
|
||||
[$d020]=A
|
||||
X=false
|
||||
|
@ -2,7 +2,7 @@
|
||||
%output prg,basic ; create a c-64 program with basic SYS call to launch it
|
||||
|
||||
|
||||
%import "c64lib" ; searched in several locations and with .ill file extension added
|
||||
%import c64lib ; searched in several locations and with .ill file extension added
|
||||
|
||||
~ main
|
||||
{
|
||||
@ -24,7 +24,7 @@
|
||||
|
||||
var .text hello2 = "@@\f\b\n\r\t@@"
|
||||
|
||||
start
|
||||
start:
|
||||
global2.make_screen_black()
|
||||
|
||||
A='?'
|
||||
@ -66,7 +66,7 @@ start
|
||||
|
||||
~ global2 {
|
||||
|
||||
make_screen_black
|
||||
make_screen_black:
|
||||
c64.EXTCOL = c64.BGCOL0 = 0
|
||||
c64.COLOR = 3
|
||||
Y = true
|
||||
|
@ -1,6 +1,6 @@
|
||||
%output prg,basic ; create a c-64 program with basic SYS to() launch it
|
||||
|
||||
%import "c64lib.ill"
|
||||
%import c64lib.ill
|
||||
|
||||
~ main
|
||||
{
|
||||
@ -8,7 +8,7 @@
|
||||
var .ptext p_greeting = "hello world!\r12345678 is a big number.\r"
|
||||
const .word BORDER = $d020
|
||||
|
||||
start
|
||||
start:
|
||||
c64scr.print_pimmediate() ; this prints the pstring immediately following it
|
||||
%asm {
|
||||
.ptext "hello-pimmediate!{cr}"
|
||||
@ -26,7 +26,7 @@ start
|
||||
c64.CHROUT (13)
|
||||
return
|
||||
|
||||
start2
|
||||
start2:
|
||||
global2.make_screen_black()
|
||||
c64.CLEARSCR()
|
||||
c64scr.print_string(greeting)
|
||||
@ -52,7 +52,7 @@ start2
|
||||
|
||||
~ global2 {
|
||||
|
||||
make_screen_black
|
||||
make_screen_black:
|
||||
c64.EXTCOL = c64.BGCOL0 = 0
|
||||
c64.COLOR = 3
|
||||
return
|
||||
|
22
todo.ill
22
todo.ill
@ -1,6 +1,6 @@
|
||||
%output prg,basic
|
||||
%import "c64lib"
|
||||
%import "mathlib"
|
||||
%import c64lib
|
||||
%import mathlib
|
||||
|
||||
~ main {
|
||||
|
||||
@ -9,9 +9,9 @@
|
||||
var var1 =2
|
||||
var .word wvar1 = 2
|
||||
|
||||
start
|
||||
start:
|
||||
A=math.randbyte()
|
||||
A+=c64.RASTER
|
||||
A += c64.RASTER
|
||||
A-=c64.TIME_LO
|
||||
X,A=math.divmod_bytes(A, 99)
|
||||
c64scr.print_byte_decimal(A)
|
||||
@ -19,7 +19,7 @@ start
|
||||
return
|
||||
|
||||
|
||||
rndloop
|
||||
rndloop:
|
||||
XY = math.randword()
|
||||
%asm {
|
||||
txa
|
||||
@ -76,6 +76,10 @@ rndloop
|
||||
X >>= 7
|
||||
X >>= 8
|
||||
X >>= 22
|
||||
XY = 1
|
||||
AX = 2
|
||||
SC =2
|
||||
QW =3
|
||||
;XY <<= 0
|
||||
;XY <<= 1
|
||||
;XY <<= 2
|
||||
@ -114,7 +118,7 @@ rndloop
|
||||
bne -
|
||||
}
|
||||
|
||||
loop
|
||||
loop :
|
||||
A=c64.GETIN()
|
||||
if_not goto loop
|
||||
c64scr.scroll_right_full(1)
|
||||
@ -133,6 +137,12 @@ loop
|
||||
Y = $33
|
||||
|
||||
c64scr.clear_screen (81, 5)
|
||||
c64scr.clear_screen (81, 5)
|
||||
c64scr.clear_screen (81, 5)
|
||||
c64scr.clear_screen (81, 5)
|
||||
c64scr.clear_screen ! (81, 5)
|
||||
c64scr.clear_screen ! (81, 5)
|
||||
c64scr.clear_screen !(81, 5)
|
||||
c64scr.clear_screen !(81, 5)
|
||||
c64scr.clear_screen !A (81, 5)
|
||||
c64scr.clear_screen !X (81, 5)
|
||||
|
Loading…
Reference in New Issue
Block a user