From 4b2a7a3cc288b725945382b913a039e2abbfb9c2 Mon Sep 17 00:00:00 2001 From: Timon Date: Sat, 3 Jan 2026 21:41:45 +0100 Subject: [PATCH] Skoraj koncano, manjka generiranje obj kode --- ass3/zbirnik/README.md | 0 ass3/zbirnik/poetry.lock | 18 ++ ass3/zbirnik/pyproject.toml | 21 ++ ass3/zbirnik/src/zbirnik/EmitCtx.py | 6 + ass3/zbirnik/src/zbirnik/__init__.py | 0 .../__pycache__/EmitCtx.cpython-310.pyc | Bin 0 -> 530 bytes .../__pycache__/__init__.cpython-310.pyc | Bin 0 -> 179 bytes .../__pycache__/adressing.cpython-310.pyc | Bin 0 -> 443 bytes ass3/zbirnik/src/zbirnik/adressing.py | 7 + ass3/zbirnik/src/zbirnik/code.py | 62 +++++ .../zbirnik/src/zbirnik/mnemoniki/__init__.py | 0 .../zbirnik/src/zbirnik/mnemoniki/mnemonic.py | 11 + .../src/zbirnik/mnemoniki/mnemonicD.py | 8 + .../src/zbirnik/mnemoniki/mnemonicDn.py | 8 + .../src/zbirnik/mnemoniki/mnemonicF1.py | 6 + .../src/zbirnik/mnemoniki/mnemonicF2.py | 9 + .../src/zbirnik/mnemoniki/mnemonicF2n.py | 8 + .../src/zbirnik/mnemoniki/mnemonicF2r.py | 9 + .../src/zbirnik/mnemoniki/mnemonicF2rn.py | 8 + .../src/zbirnik/mnemoniki/mnemonicF2rr.py | 9 + .../src/zbirnik/mnemoniki/mnemonicF3.py | 8 + .../src/zbirnik/mnemoniki/mnemonicF3m.py | 9 + .../src/zbirnik/mnemoniki/mnemonicF4m.py | 10 + .../src/zbirnik/mnemoniki/mnemonicSd.py | 7 + .../src/zbirnik/mnemoniki/mnemonicSn.py | 8 + .../src/zbirnik/mnemoniki/mnemoniki_tabela.py | 70 ++++++ ass3/zbirnik/src/zbirnik/parser.out | 219 ++++++++++++++++++ ass3/zbirnik/src/zbirnik/parser.py | 92 ++++++++ ass3/zbirnik/src/zbirnik/parserctx.py | 62 +++++ ass3/zbirnik/src/zbirnik/parsetab.py | 42 ++++ ass3/zbirnik/src/zbirnik/test_emit.py | 72 ++++++ ass3/zbirnik/src/zbirnik/ukazi/__init__.py | 0 .../__pycache__/__init__.cpython-310.pyc | Bin 0 -> 185 bytes .../ukazi/__pycache__/f1.cpython-310.pyc | Bin 0 -> 902 bytes .../ukazi/__pycache__/f2.cpython-310.pyc | Bin 0 -> 1133 bytes .../ukazi/__pycache__/f3.cpython-310.pyc | Bin 0 -> 1775 bytes .../ukazi/__pycache__/f4.cpython-310.pyc | Bin 0 -> 1623 bytes .../ukazi/__pycache__/node.cpython-310.pyc | Bin 0 -> 710 bytes ass3/zbirnik/src/zbirnik/ukazi/comment.py | 8 + ass3/zbirnik/src/zbirnik/ukazi/directive.py | 29 +++ ass3/zbirnik/src/zbirnik/ukazi/f1.py | 13 ++ ass3/zbirnik/src/zbirnik/ukazi/f2.py | 30 +++ ass3/zbirnik/src/zbirnik/ukazi/f3.py | 62 +++++ ass3/zbirnik/src/zbirnik/ukazi/f4.py | 51 ++++ ass3/zbirnik/src/zbirnik/ukazi/node.py | 9 + ass3/zbirnik/src/zbirnik/ukazi/storage.py | 43 ++++ ass3/zbirnik/tests/__init__.py | 0 47 files changed, 1034 insertions(+) create mode 100644 ass3/zbirnik/README.md create mode 100644 ass3/zbirnik/poetry.lock create mode 100644 ass3/zbirnik/pyproject.toml create mode 100644 ass3/zbirnik/src/zbirnik/EmitCtx.py create mode 100644 ass3/zbirnik/src/zbirnik/__init__.py create mode 100644 ass3/zbirnik/src/zbirnik/__pycache__/EmitCtx.cpython-310.pyc create mode 100644 ass3/zbirnik/src/zbirnik/__pycache__/__init__.cpython-310.pyc create mode 100644 ass3/zbirnik/src/zbirnik/__pycache__/adressing.cpython-310.pyc create mode 100644 ass3/zbirnik/src/zbirnik/adressing.py create mode 100644 ass3/zbirnik/src/zbirnik/code.py create mode 100644 ass3/zbirnik/src/zbirnik/mnemoniki/__init__.py create mode 100644 ass3/zbirnik/src/zbirnik/mnemoniki/mnemonic.py create mode 100644 ass3/zbirnik/src/zbirnik/mnemoniki/mnemonicD.py create mode 100644 ass3/zbirnik/src/zbirnik/mnemoniki/mnemonicDn.py create mode 100644 ass3/zbirnik/src/zbirnik/mnemoniki/mnemonicF1.py create mode 100644 ass3/zbirnik/src/zbirnik/mnemoniki/mnemonicF2.py create mode 100644 ass3/zbirnik/src/zbirnik/mnemoniki/mnemonicF2n.py create mode 100644 ass3/zbirnik/src/zbirnik/mnemoniki/mnemonicF2r.py create mode 100644 ass3/zbirnik/src/zbirnik/mnemoniki/mnemonicF2rn.py create mode 100644 ass3/zbirnik/src/zbirnik/mnemoniki/mnemonicF2rr.py create mode 100644 ass3/zbirnik/src/zbirnik/mnemoniki/mnemonicF3.py create mode 100644 ass3/zbirnik/src/zbirnik/mnemoniki/mnemonicF3m.py create mode 100644 ass3/zbirnik/src/zbirnik/mnemoniki/mnemonicF4m.py create mode 100644 ass3/zbirnik/src/zbirnik/mnemoniki/mnemonicSd.py create mode 100644 ass3/zbirnik/src/zbirnik/mnemoniki/mnemonicSn.py create mode 100644 ass3/zbirnik/src/zbirnik/mnemoniki/mnemoniki_tabela.py create mode 100644 ass3/zbirnik/src/zbirnik/parser.out create mode 100644 ass3/zbirnik/src/zbirnik/parser.py create mode 100644 ass3/zbirnik/src/zbirnik/parserctx.py create mode 100644 ass3/zbirnik/src/zbirnik/parsetab.py create mode 100644 ass3/zbirnik/src/zbirnik/test_emit.py create mode 100644 ass3/zbirnik/src/zbirnik/ukazi/__init__.py create mode 100644 ass3/zbirnik/src/zbirnik/ukazi/__pycache__/__init__.cpython-310.pyc create mode 100644 ass3/zbirnik/src/zbirnik/ukazi/__pycache__/f1.cpython-310.pyc create mode 100644 ass3/zbirnik/src/zbirnik/ukazi/__pycache__/f2.cpython-310.pyc create mode 100644 ass3/zbirnik/src/zbirnik/ukazi/__pycache__/f3.cpython-310.pyc create mode 100644 ass3/zbirnik/src/zbirnik/ukazi/__pycache__/f4.cpython-310.pyc create mode 100644 ass3/zbirnik/src/zbirnik/ukazi/__pycache__/node.cpython-310.pyc create mode 100644 ass3/zbirnik/src/zbirnik/ukazi/comment.py create mode 100644 ass3/zbirnik/src/zbirnik/ukazi/directive.py create mode 100644 ass3/zbirnik/src/zbirnik/ukazi/f1.py create mode 100644 ass3/zbirnik/src/zbirnik/ukazi/f2.py create mode 100644 ass3/zbirnik/src/zbirnik/ukazi/f3.py create mode 100644 ass3/zbirnik/src/zbirnik/ukazi/f4.py create mode 100644 ass3/zbirnik/src/zbirnik/ukazi/node.py create mode 100644 ass3/zbirnik/src/zbirnik/ukazi/storage.py create mode 100644 ass3/zbirnik/tests/__init__.py diff --git a/ass3/zbirnik/README.md b/ass3/zbirnik/README.md new file mode 100644 index 0000000..e69de29 diff --git a/ass3/zbirnik/poetry.lock b/ass3/zbirnik/poetry.lock new file mode 100644 index 0000000..85cbe76 --- /dev/null +++ b/ass3/zbirnik/poetry.lock @@ -0,0 +1,18 @@ +# This file is automatically @generated by Poetry 2.2.1 and should not be changed by hand. + +[[package]] +name = "ply" +version = "3.11" +description = "Python Lex & Yacc" +optional = false +python-versions = "*" +groups = ["main"] +files = [ + {file = "ply-3.11-py2.py3-none-any.whl", hash = "sha256:096f9b8350b65ebd2fd1346b12452efe5b9607f7482813ffca50c22722a807ce"}, + {file = "ply-3.11.tar.gz", hash = "sha256:00c7c1aaa88358b9c765b6d3000c6eec0ba42abca5351b095321aef446081da3"}, +] + +[metadata] +lock-version = "2.1" +python-versions = ">=3.10" +content-hash = "aeee2cd18440094d85604201949f31ea16b086488be3992891c1777b5c89b058" diff --git a/ass3/zbirnik/pyproject.toml b/ass3/zbirnik/pyproject.toml new file mode 100644 index 0000000..3969b75 --- /dev/null +++ b/ass3/zbirnik/pyproject.toml @@ -0,0 +1,21 @@ +[project] +name = "zbirnik" +version = "0.1.0" +description = "" +authors = [ + { name = "Timon", email = "timonbub@gmail.com" } +] +readme = "README.md" +requires-python = ">=3.10" +dependencies = [ + "ply>=3.11,<4.0" +] + +[tool.poetry] +packages = [ + { include = "zbirnik", from = "src" } +] + +[build-system] +requires = ["poetry-core>=2.0.0,<3.0.0"] +build-backend = "poetry.core.masonry.api" diff --git a/ass3/zbirnik/src/zbirnik/EmitCtx.py b/ass3/zbirnik/src/zbirnik/EmitCtx.py new file mode 100644 index 0000000..35bf24f --- /dev/null +++ b/ass3/zbirnik/src/zbirnik/EmitCtx.py @@ -0,0 +1,6 @@ +class EmitContext: + def __init__(self, opcodes, registers, symtab): + self.opcodes = opcodes + self.registers = registers + self.symtab = symtab + self.base = None diff --git a/ass3/zbirnik/src/zbirnik/__init__.py b/ass3/zbirnik/src/zbirnik/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/ass3/zbirnik/src/zbirnik/__pycache__/EmitCtx.cpython-310.pyc b/ass3/zbirnik/src/zbirnik/__pycache__/EmitCtx.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..91fac21d7cfa8b2aebc0b5fe06b3b109141109d2 GIT binary patch literal 530 zcmY*Uy-ve05Vn)3O-s8}9T~cIpdPv+RH^)kfr6+Q$YLe2fzTulJ{PrBHu^F=1@DoS zw_xI&s;HcG-`&}F-}zJBZkwRptR9mujNi66G#85rI`j~(h#-P)(LbDk2xm@)ZjAT; z%)x4c4t)ek0xC%02r8T{30&dgj8`39WQm!o+{l%QJ?z_?%`L$c9gY!7S`to52a%R8 zq9X{RD+m(N8FDpM5i22~YH9hLfRP%i2COp^MwJ(ZAhE{-nLcSttgRqz*L)J)#PIXL zUQ{Moq*Mf;a&|6ZVN}7!qd_W7o-78J_t$KGcgvtqC-32_WFf$qZK6cuD+3+><+Uuc z8Wrox=RC<1!@1oGK0<@q)25sLf%?(D%}T+UJj^8LRh#oniDhc@4(D&nFx|cA7BbZz mKLE?FDS~yd;(XGf_04R!iwE6SwYDRbf4W<8R?pdw_Q)^Bb9ICO literal 0 HcmV?d00001 diff --git a/ass3/zbirnik/src/zbirnik/__pycache__/__init__.cpython-310.pyc b/ass3/zbirnik/src/zbirnik/__pycache__/__init__.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..a2a1a1b3e284a4c10cbbd9f75075df7514bbf33b GIT binary patch literal 179 zcmd1j<>g`kf|Fs6nIQTxh(HF6K#l_t7qb9~6oz01O-8?!3`HPe1o10OKO;XkRX-^| zKdHDlKTqE!wK%&Zzd+wuPa!9@Brh{t!7a#BKRCc&zqlY@w=6L$RX?$~*jT?RDYFPD nt6yA{3}?s3XXa&=#K-FuRNmsS$<0qG%}KQb*;mX2Bv=>#sZ=Z7 literal 0 HcmV?d00001 diff --git a/ass3/zbirnik/src/zbirnik/__pycache__/adressing.cpython-310.pyc b/ass3/zbirnik/src/zbirnik/__pycache__/adressing.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..a67d4073051461433281b8c8f4154ef5daebf24e GIT binary patch literal 443 zcmYjNu};G<5Vf5&gwje3%%}rP25O|P2(_XCMIxnYDCDh5*NEcg0=k_e#t8n zzre&fm7pix^Syhg)A`AEyNMv!#bdUG_sf#~aDnt8^%($19OtOO2`)%NFuFyYaA%9S zBk;ya9PUn0(D;T)6cFQvWmOnAt=4j3Tl;~5^da>rfItc6C?Uexpv0}QQKQE(EF{Js zaIRv>#V9y1K4WEC2*ym4u|o1Hw{?rL*DB3-igIA9@upEcz6;G^6vyE(8q7lDN26gh z39o0LNFBjU4L=X`Sr&rMrJQRmOF9&Kxt1&1>vnRnF0*ClW)jiq_@3&OJbz1H1WmQ> z(T{niK&4tO{_2z~p>w RzubNE%DSfQ!ee|wegSFzWN`oh literal 0 HcmV?d00001 diff --git a/ass3/zbirnik/src/zbirnik/adressing.py b/ass3/zbirnik/src/zbirnik/adressing.py new file mode 100644 index 0000000..cf00b06 --- /dev/null +++ b/ass3/zbirnik/src/zbirnik/adressing.py @@ -0,0 +1,7 @@ +# addressing.py +from enum import Enum, auto + +class AddrMode(Enum): + SIMPLE = auto() + IMMEDIATE = auto() + INDIRECT = auto() diff --git a/ass3/zbirnik/src/zbirnik/code.py b/ass3/zbirnik/src/zbirnik/code.py new file mode 100644 index 0000000..b3e9fdc --- /dev/null +++ b/ass3/zbirnik/src/zbirnik/code.py @@ -0,0 +1,62 @@ +from zbirnik.ukazi.node import Node + +class Code: + + REGISTERS = {'A': 0, 'X': 1, 'L': 2, 'B': 3, 'S': 4, 'T': 5, 'F': 6 } + + def __init__(self, name: str | None = None): + self.name = name + self.nodes = [] + self.locctr = 0 + self.symtab = {} + self.start_adress = 0 + self.entry_point = 0 + self.program_length = 0 + self.obj = "" + + def add(self, node: Node): + self.nodes.append(node) + + def pass1(self): + locctr = 0 + self.start_address = 0 + self.entry_point = None + + for node in self.nodes: + + # START + if node.__class__.__name__ == "directive" and node.name == "START": + self.start_address = node.value + locctr = self.start_address + self.name = node.label + node.address = locctr + continue + + # naslov node-a + node.address = locctr + + # label → SYMTAB + if node.label: + if node.label in self.symtab: + raise ValueError(f"Duplicate symbol: {node.label}") + self.symtab[node.label] = locctr + + # END + if node.__class__.__name__ == "directive" and node.name == "END": + if node.value is not None: + self.entry_point = node.value + break + + locctr += node.size() + + self.locctr = locctr + self.program_length = locctr - self.start_address + + def pass2(self, ctx): + output = bytearray() + for node in self.nodes: + chunk = node.emit(ctx) + if chunk: + output.extend(chunk) + + return bytes(output) diff --git a/ass3/zbirnik/src/zbirnik/mnemoniki/__init__.py b/ass3/zbirnik/src/zbirnik/mnemoniki/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/ass3/zbirnik/src/zbirnik/mnemoniki/mnemonic.py b/ass3/zbirnik/src/zbirnik/mnemoniki/mnemonic.py new file mode 100644 index 0000000..a2c8002 --- /dev/null +++ b/ass3/zbirnik/src/zbirnik/mnemoniki/mnemonic.py @@ -0,0 +1,11 @@ +from abc import ABC, abstractmethod + +class Mnemonic(ABC): + def __init__(self, name: str, opcode: int | None = None, description: str = ""): + self.name = name + self.opcode = opcode + self.description = description + + @abstractmethod + def parse(self, parser): + pass diff --git a/ass3/zbirnik/src/zbirnik/mnemoniki/mnemonicD.py b/ass3/zbirnik/src/zbirnik/mnemoniki/mnemonicD.py new file mode 100644 index 0000000..fbe3ffd --- /dev/null +++ b/ass3/zbirnik/src/zbirnik/mnemoniki/mnemonicD.py @@ -0,0 +1,8 @@ +from zbirnik.ukazi.directive import directive +from mnemonic import Mnemonic +from zbirnik.parserctx import ParserContext + +class MnemonicD(Mnemonic): + def parse(self, parser: ParserContext): + return directive(direktiva=self.name, label=parser.label, + operand=None) diff --git a/ass3/zbirnik/src/zbirnik/mnemoniki/mnemonicDn.py b/ass3/zbirnik/src/zbirnik/mnemoniki/mnemonicDn.py new file mode 100644 index 0000000..2e37658 --- /dev/null +++ b/ass3/zbirnik/src/zbirnik/mnemoniki/mnemonicDn.py @@ -0,0 +1,8 @@ +from zbirnik.ukazi.directive import directive +from mnemonic import Mnemonic +from zbirnik.parserctx import ParserContext + +class MnemonicDn(Mnemonic): + def parse(self, parser: ParserContext): + return directive(direktiva=self.name, label=parser.label, + operand=parser.read_num_sym()) diff --git a/ass3/zbirnik/src/zbirnik/mnemoniki/mnemonicF1.py b/ass3/zbirnik/src/zbirnik/mnemoniki/mnemonicF1.py new file mode 100644 index 0000000..2e10727 --- /dev/null +++ b/ass3/zbirnik/src/zbirnik/mnemoniki/mnemonicF1.py @@ -0,0 +1,6 @@ +from mnemonic import Mnemonic +from zbirnik.ukazi.f1 import f1 + +class MnemonicF1(Mnemonic): + def parse(self, parser): + return f1(label=parser.label, mnemonic=self.name) diff --git a/ass3/zbirnik/src/zbirnik/mnemoniki/mnemonicF2.py b/ass3/zbirnik/src/zbirnik/mnemoniki/mnemonicF2.py new file mode 100644 index 0000000..464ac67 --- /dev/null +++ b/ass3/zbirnik/src/zbirnik/mnemoniki/mnemonicF2.py @@ -0,0 +1,9 @@ +from zbirnik.mnemoniki.mnemonic import Mnemonic +from zbirnik.ukazi.f2 import f2 +from zbirnik.parserctx import ParserContext + + +class mnemonicF2(Mnemonic): + def parse(self, parser: ParserContext): + return f2(r1=parser.read_reg(), r2=parser.read_reg(), + mnemonic=self.name, label=parser.label) \ No newline at end of file diff --git a/ass3/zbirnik/src/zbirnik/mnemoniki/mnemonicF2n.py b/ass3/zbirnik/src/zbirnik/mnemoniki/mnemonicF2n.py new file mode 100644 index 0000000..35e2a97 --- /dev/null +++ b/ass3/zbirnik/src/zbirnik/mnemoniki/mnemonicF2n.py @@ -0,0 +1,8 @@ +from zbirnik.mnemoniki.mnemonic import Mnemonic +from zbirnik.ukazi.f2 import f2 +from zbirnik.parserctx import ParserContext + +class MnemonicF2n(Mnemonic): + def parse(self, parser: ParserContext): + return f2(r1=parser.read_reg(), r2 = None, + mnemonic=self.name, label=parser.label) diff --git a/ass3/zbirnik/src/zbirnik/mnemoniki/mnemonicF2r.py b/ass3/zbirnik/src/zbirnik/mnemoniki/mnemonicF2r.py new file mode 100644 index 0000000..0c325b3 --- /dev/null +++ b/ass3/zbirnik/src/zbirnik/mnemoniki/mnemonicF2r.py @@ -0,0 +1,9 @@ +from zbirnik.mnemoniki.mnemonic import Mnemonic +from zbirnik.ukazi.f2 import f2 +from zbirnik.parserctx import ParserContext + + +class MnemonicF2r(Mnemonic): + def parse(self, parser: ParserContext): + return f2(r1=parser.read_reg(), r2=None, + mnemonic=self.name, label=parser.label) diff --git a/ass3/zbirnik/src/zbirnik/mnemoniki/mnemonicF2rn.py b/ass3/zbirnik/src/zbirnik/mnemoniki/mnemonicF2rn.py new file mode 100644 index 0000000..30b6402 --- /dev/null +++ b/ass3/zbirnik/src/zbirnik/mnemoniki/mnemonicF2rn.py @@ -0,0 +1,8 @@ +from zbirnik.mnemoniki.mnemonic import Mnemonic +from zbirnik.ukazi.f2 import f2 +from zbirnik.parserctx import ParserContext + +class MnemonicF2rn(Mnemonic): + def parse(self, parser: ParserContext): + return f2(r1=parser.read_reg(), r2=parser.read_num_sym()-1, + mnemonic=self.name, label=parser.label) diff --git a/ass3/zbirnik/src/zbirnik/mnemoniki/mnemonicF2rr.py b/ass3/zbirnik/src/zbirnik/mnemoniki/mnemonicF2rr.py new file mode 100644 index 0000000..d6f1415 --- /dev/null +++ b/ass3/zbirnik/src/zbirnik/mnemoniki/mnemonicF2rr.py @@ -0,0 +1,9 @@ +from zbirnik.mnemoniki.mnemonic import Mnemonic +from zbirnik.ukazi.f2 import f2 +from zbirnik.parserctx import ParserContext + + +class MnemonicF2rr(Mnemonic): + def parse(self, parser: ParserContext): + return f2(r1=parser.read_reg(), r2=parser.read_reg(), + mnemonic=self.name, label=parser.label) diff --git a/ass3/zbirnik/src/zbirnik/mnemoniki/mnemonicF3.py b/ass3/zbirnik/src/zbirnik/mnemoniki/mnemonicF3.py new file mode 100644 index 0000000..58212ec --- /dev/null +++ b/ass3/zbirnik/src/zbirnik/mnemoniki/mnemonicF3.py @@ -0,0 +1,8 @@ +from zbirnik.mnemoniki.mnemonic import Mnemonic +from zbirnik.ukazi.f3 import f3 +from zbirnik.parserctx import ParserContext + +class MnemonicF3(Mnemonic): + def parse(self, parser: ParserContext): + return f3(operand=None, adr_mode=None, index=None, + mnemonic=self.name, label=parser.label) diff --git a/ass3/zbirnik/src/zbirnik/mnemoniki/mnemonicF3m.py b/ass3/zbirnik/src/zbirnik/mnemoniki/mnemonicF3m.py new file mode 100644 index 0000000..caf7f33 --- /dev/null +++ b/ass3/zbirnik/src/zbirnik/mnemoniki/mnemonicF3m.py @@ -0,0 +1,9 @@ +from zbirnik.mnemoniki.mnemonic import Mnemonic +from zbirnik.ukazi.f3 import f3 +from zbirnik.parserctx import ParserContext + +class MnemonicF3m(Mnemonic): + def parse(self, parser: ParserContext): + addr_mode, value, indexed = parser.read_addressed_operand() + return f3(operand=value, mnemonic=self.name, label=parser.label, + adr_mode=addr_mode, index=indexed) diff --git a/ass3/zbirnik/src/zbirnik/mnemoniki/mnemonicF4m.py b/ass3/zbirnik/src/zbirnik/mnemoniki/mnemonicF4m.py new file mode 100644 index 0000000..93ca7ea --- /dev/null +++ b/ass3/zbirnik/src/zbirnik/mnemoniki/mnemonicF4m.py @@ -0,0 +1,10 @@ +from zbirnik.mnemoniki.mnemonic import Mnemonic +from zbirnik.ukazi.f4 import f4 +from zbirnik.parserctx import ParserContext + +class MnemonicF4m(Mnemonic): + def parse(self, parser: ParserContext): + addr_mode, value, indexed = parser.read_addressed_operand() + return f4(operand=value, mnemonic=self.name, label=parser.label, + adr_mode=addr_mode, index=indexed) + diff --git a/ass3/zbirnik/src/zbirnik/mnemoniki/mnemonicSd.py b/ass3/zbirnik/src/zbirnik/mnemoniki/mnemonicSd.py new file mode 100644 index 0000000..d582b96 --- /dev/null +++ b/ass3/zbirnik/src/zbirnik/mnemoniki/mnemonicSd.py @@ -0,0 +1,7 @@ +from zbirnik.mnemoniki.mnemonic import Mnemonic +from zbirnik.ukazi.storage import storage +from zbirnik.parserctx import ParserContext + +class MnemonicSd(Mnemonic): + def parse(self, parser: ParserContext): + return storage(label=parser.label, name=self.name, val=parser.read_num_sym()) diff --git a/ass3/zbirnik/src/zbirnik/mnemoniki/mnemonicSn.py b/ass3/zbirnik/src/zbirnik/mnemoniki/mnemonicSn.py new file mode 100644 index 0000000..ab19eea --- /dev/null +++ b/ass3/zbirnik/src/zbirnik/mnemoniki/mnemonicSn.py @@ -0,0 +1,8 @@ +from zbirnik.mnemoniki.mnemonic import Mnemonic +from zbirnik.ukazi.storage import storage +from zbirnik.parserctx import ParserContext + + +class MnemonicSn(Mnemonic): + def parse(self, parser: ParserContext): + return storage(label=parser.label, name=self.name, val=parser.read_num_sym()) diff --git a/ass3/zbirnik/src/zbirnik/mnemoniki/mnemoniki_tabela.py b/ass3/zbirnik/src/zbirnik/mnemoniki/mnemoniki_tabela.py new file mode 100644 index 0000000..a1d4312 --- /dev/null +++ b/ass3/zbirnik/src/zbirnik/mnemoniki/mnemoniki_tabela.py @@ -0,0 +1,70 @@ +from mnemoniki import ( + mnemonicD, mnemonicDn, + mnemonicF1, mnemonicF2n, mnemonicF2r, mnemonicF2rn, mnemonicF2rr, + mnemonicF3, mnemonicF3m, mnemonicF4m, + mnemonicSd, mnemonicSn +) + +# Centralna tabela mnemonikov +MNEMONICS = { + # Direktive (brez operandov) + 'NOBASE': mnemonicD('NOBASE'), + 'LTORG': mnemonicD('LTORG'), + # Direktive (en operand) + 'START': mnemonicDn('START'), + 'END': mnemonicDn('END'), + 'BASE': mnemonicDn('BASE'), + # Format 1 (brez operandov) + 'FIX': mnemonicF1('FIX', opcode=0xC4), + 'FLOAT': mnemonicF1('FLOAT', opcode=0xC0), + 'HIO': mnemonicF1('HIO', opcode=0xF4), + 'NORM': mnemonicF1('NORM', opcode=0xC8), + 'SIO': mnemonicF1('SIO', opcode=0xF0), + 'TIO': mnemonicF1('TIO', opcode=0xF8), + # Format 2 + # F2 – en številčni operand + 'SVC': mnemonicF2n('SVC', opcode=0xB0), + # F2 – en register + 'CLEAR': mnemonicF2r('CLEAR', opcode=0xB4), + 'TIXR': mnemonicF2r('TIXR', opcode=0xB8), + # F2 – register + število + 'SHIFTL': mnemonicF2rn('SHIFTL', opcode=0xA4), + 'SHIFTR': mnemonicF2rn('SHIFTR', opcode=0xA8), + # F2 – dva registra + 'ADDR': mnemonicF2rr('ADDR', opcode=0x90), + 'SUBR': mnemonicF2rr('SUBR', opcode=0x94), + 'MULR': mnemonicF2rr('MULR', opcode=0x98), + 'DIVR': mnemonicF2rr('DIVR', opcode=0x9C), + 'COMPR': mnemonicF2rr('COMPR', opcode=0xA0), + # Format 3 + 'RSUB': mnemonicF3('RSUB', opcode=0x4C), + 'LDA': mnemonicF3m('LDA', opcode=0x00), + 'LDX': mnemonicF3m('LDX', opcode=0x04), + 'LDL': mnemonicF3m('LDL', opcode=0x08), + 'STA': mnemonicF3m('STA', opcode=0x0C), + 'STX': mnemonicF3m('STX', opcode=0x10), + 'STL': mnemonicF3m('STL', opcode=0x14), + 'ADD': mnemonicF3m('ADD', opcode=0x18), + 'SUB': mnemonicF3m('SUB', opcode=0x1C), + 'MUL': mnemonicF3m('MUL', opcode=0x20), + 'DIV': mnemonicF3m('DIV', opcode=0x24), + 'COMP': mnemonicF3m('COMP', opcode=0x28), + 'J': mnemonicF3m('J', opcode=0x3C), + 'JEQ': mnemonicF3m('JEQ', opcode=0x30), + 'JGT': mnemonicF3m('JGT', opcode=0x34), + 'JLT': mnemonicF3m('JLT', opcode=0x38), + 'JSUB': mnemonicF3m('JSUB', opcode=0x48), + 'TD': mnemonicF3m('TD', opcode=0xE0), + 'RD': mnemonicF3m('RD', opcode=0xD8), + 'WD': mnemonicF3m('WD', opcode=0xDC), + # Format 4 (razširjeni) + '+LDA': mnemonicF4m('+LDA', opcode=0x00), + '+JSUB': mnemonicF4m('+JSUB', opcode=0x48), + # Pomnilniške direktive + # podatki + 'BYTE': mnemonicSd('BYTE'), + 'WORD': mnemonicSd('WORD'), + # rezervacija + 'RESB': mnemonicSn('RESB'), + 'RESW': mnemonicSn('RESW'), +} diff --git a/ass3/zbirnik/src/zbirnik/parser.out b/ass3/zbirnik/src/zbirnik/parser.out new file mode 100644 index 0000000..90bdd00 --- /dev/null +++ b/ass3/zbirnik/src/zbirnik/parser.out @@ -0,0 +1,219 @@ +Created by PLY version 3.11 (http://www.dabeaz.com/ply) + +Grammar + +Rule 0 S' -> start +Rule 1 start -> LABEL command +Rule 2 start -> command +Rule 3 command -> MNEMONIC +Rule 4 command -> MNEMONIC args +Rule 5 args -> operand +Rule 6 args -> operand COMMA operand +Rule 7 operand -> REGISTER +Rule 8 operand -> AT address +Rule 9 operand -> HASH address +Rule 10 operand -> address +Rule 11 address -> NUMBER +Rule 12 address -> SYMBOL + +Terminals, with rules where they appear + +AT : 8 +COMMA : 6 +HASH : 9 +LABEL : 1 +MNEMONIC : 3 4 +NUMBER : 11 +REGISTER : 7 +SYMBOL : 12 +error : + +Nonterminals, with rules where they appear + +address : 8 9 10 +args : 4 +command : 1 2 +operand : 5 6 6 +start : 0 + +Parsing method: LALR + +state 0 + + (0) S' -> . start + (1) start -> . LABEL command + (2) start -> . command + (3) command -> . MNEMONIC + (4) command -> . MNEMONIC args + + LABEL shift and go to state 2 + MNEMONIC shift and go to state 4 + + start shift and go to state 1 + command shift and go to state 3 + +state 1 + + (0) S' -> start . + + + +state 2 + + (1) start -> LABEL . command + (3) command -> . MNEMONIC + (4) command -> . MNEMONIC args + + MNEMONIC shift and go to state 4 + + command shift and go to state 5 + +state 3 + + (2) start -> command . + + $end reduce using rule 2 (start -> command .) + + +state 4 + + (3) command -> MNEMONIC . + (4) command -> MNEMONIC . args + (5) args -> . operand + (6) args -> . operand COMMA operand + (7) operand -> . REGISTER + (8) operand -> . AT address + (9) operand -> . HASH address + (10) operand -> . address + (11) address -> . NUMBER + (12) address -> . SYMBOL + + $end reduce using rule 3 (command -> MNEMONIC .) + REGISTER shift and go to state 8 + AT shift and go to state 9 + HASH shift and go to state 11 + NUMBER shift and go to state 12 + SYMBOL shift and go to state 13 + + args shift and go to state 6 + operand shift and go to state 7 + address shift and go to state 10 + +state 5 + + (1) start -> LABEL command . + + $end reduce using rule 1 (start -> LABEL command .) + + +state 6 + + (4) command -> MNEMONIC args . + + $end reduce using rule 4 (command -> MNEMONIC args .) + + +state 7 + + (5) args -> operand . + (6) args -> operand . COMMA operand + + $end reduce using rule 5 (args -> operand .) + COMMA shift and go to state 14 + + +state 8 + + (7) operand -> REGISTER . + + COMMA reduce using rule 7 (operand -> REGISTER .) + $end reduce using rule 7 (operand -> REGISTER .) + + +state 9 + + (8) operand -> AT . address + (11) address -> . NUMBER + (12) address -> . SYMBOL + + NUMBER shift and go to state 12 + SYMBOL shift and go to state 13 + + address shift and go to state 15 + +state 10 + + (10) operand -> address . + + COMMA reduce using rule 10 (operand -> address .) + $end reduce using rule 10 (operand -> address .) + + +state 11 + + (9) operand -> HASH . address + (11) address -> . NUMBER + (12) address -> . SYMBOL + + NUMBER shift and go to state 12 + SYMBOL shift and go to state 13 + + address shift and go to state 16 + +state 12 + + (11) address -> NUMBER . + + COMMA reduce using rule 11 (address -> NUMBER .) + $end reduce using rule 11 (address -> NUMBER .) + + +state 13 + + (12) address -> SYMBOL . + + COMMA reduce using rule 12 (address -> SYMBOL .) + $end reduce using rule 12 (address -> SYMBOL .) + + +state 14 + + (6) args -> operand COMMA . operand + (7) operand -> . REGISTER + (8) operand -> . AT address + (9) operand -> . HASH address + (10) operand -> . address + (11) address -> . NUMBER + (12) address -> . SYMBOL + + REGISTER shift and go to state 8 + AT shift and go to state 9 + HASH shift and go to state 11 + NUMBER shift and go to state 12 + SYMBOL shift and go to state 13 + + operand shift and go to state 17 + address shift and go to state 10 + +state 15 + + (8) operand -> AT address . + + COMMA reduce using rule 8 (operand -> AT address .) + $end reduce using rule 8 (operand -> AT address .) + + +state 16 + + (9) operand -> HASH address . + + COMMA reduce using rule 9 (operand -> HASH address .) + $end reduce using rule 9 (operand -> HASH address .) + + +state 17 + + (6) args -> operand COMMA operand . + + $end reduce using rule 6 (args -> operand COMMA operand .) + diff --git a/ass3/zbirnik/src/zbirnik/parser.py b/ass3/zbirnik/src/zbirnik/parser.py new file mode 100644 index 0000000..4aa211b --- /dev/null +++ b/ass3/zbirnik/src/zbirnik/parser.py @@ -0,0 +1,92 @@ +import ply.lex +import ply.yacc +import sys + +# Lexer. +tokens = ( + 'AT', + 'COMMA', + 'HASH', + 'LABEL', + 'REGISTER', + 'MNEMONIC', + 'SYMBOL', + 'NUMBER', + 'COMMENT', +) + +t_AT = r'@' +t_COMMA = r',' +t_HASH = r'\#' +t_LABEL = r'^[a-z_0-9]+' +t_REGISTER = r'\b[ABFLSTX]\b' +t_MNEMONIC = r'\b[A-Z]+\b' +t_SYMBOL = r'[a-z_0-9]+' + +def t_NUMBER(t): + r'-?\d+' + t.value = int(t.value) + return t + +def t_COMMENT(t): + r'\..*' + t.value = t.value[1:].strip() + return t + +t_ignore = ' \t\n' + +def t_error(t): + print(f'illegal character {t}') + t.lexer.skip(1) + +lexer = ply.lex.lex() + +# Parser. +def p_start(p): + r'''start : LABEL command + | COMMENT + | command''' + if len(p) == 2: + if isinstance(p[1], str): + p[0] = ('COMMENT', p[1]) + else: + p[0] = (None, p[1]) + else: + p[0] = tuple(p[1:]) + +def p_command(p): + r'''command : MNEMONIC + | MNEMONIC args''' + p[0] = p[1:] + +def p_args(p): + r'''args : operand + | operand COMMA operand''' + match len(p): + case 2: p[0] = (p[1],) + case 4: p[0] = (p[1], p[3]) + +def p_operand(p): + r'''operand : REGISTER + | AT address + | HASH address + | address''' + p[0] = p[1:] + +def p_address(p): + r'''address : NUMBER + | SYMBOL''' + p[0] = p[1] + +def p_error(p): + if p: + print('Syntax error at token', p) + parser.errok() + else: + print('Syntax error at EOF') + +if __name__ == '__main__': + import sys + parser = ply.yacc.yacc() + for line in sys.stdin: + print(parser.parse(line)) diff --git a/ass3/zbirnik/src/zbirnik/parserctx.py b/ass3/zbirnik/src/zbirnik/parserctx.py new file mode 100644 index 0000000..8baf37e --- /dev/null +++ b/ass3/zbirnik/src/zbirnik/parserctx.py @@ -0,0 +1,62 @@ +class ParserContext: + + def __init__(self, parsed): + """ + parsed je rezultat PLY parserja, npr.: + ('loop', ('LDA', (('#', 5),))) + (None, ('FIX',)) + ('COMMENT', 'to je komentar') + """ + if isinstance(parsed, tuple) and parsed[0] == 'COMMENT': + self.label = None + self.mnemonic = 'COMMENT' + self.operands = [] + self.comment = parsed[1] + return + + self.label, command = parsed + self.mnemonic = command[0] + self.operands = list(command[1]) if len(command) > 1 else [] + self.comment = None + + def has_operand(self) -> bool: + return len(self.operands) > 0 + + def next_op(self): + if not self.operands: + raise ValueError("Manjka operand") + return self.operands.pop(0) + + def read_reg(self) -> str: + op = self.next_op() + return op[0] + + def read_num_sym(self): + op = self.next_op() + if (len(op) == 1): + return op[0] + return op[1] + + def read_addressed_operand(self): + + from adressing import AddrMode + + indexed = False + addr_mode = AddrMode.SIMPLE + + op = self.next_operand() + + # immediate / indirect + if len(op) == 2: + prefix, value = op + addr_mode = {'#': AddrMode.IMMEDIATE, '@': AddrMode.INDIRECT}[prefix] + else: + value = op[0] + + #indeksiranje + if self.operands and self.operands[0] == ('X',): + self.operands.pop(0) + indexed = True + + return addr_mode, value, indexed + diff --git a/ass3/zbirnik/src/zbirnik/parsetab.py b/ass3/zbirnik/src/zbirnik/parsetab.py new file mode 100644 index 0000000..3538469 --- /dev/null +++ b/ass3/zbirnik/src/zbirnik/parsetab.py @@ -0,0 +1,42 @@ + +# parsetab.py +# This file is automatically generated. Do not edit. +# pylint: disable=W,C,R +_tabversion = '3.10' + +_lr_method = 'LALR' + +_lr_signature = 'AT COMMA HASH LABEL MNEMONIC NUMBER REGISTER SYMBOLstart : LABEL command\n | commandcommand : MNEMONIC\n | MNEMONIC argsargs : operand\n | operand COMMA operandoperand : REGISTER\n | AT address\n | HASH address\n | addressaddress : NUMBER\n | SYMBOL' + +_lr_action_items = {'LABEL':([0,],[2,]),'MNEMONIC':([0,2,],[4,4,]),'$end':([1,3,4,5,6,7,8,10,12,13,15,16,17,],[0,-2,-3,-1,-4,-5,-7,-10,-11,-12,-8,-9,-6,]),'REGISTER':([4,14,],[8,8,]),'AT':([4,14,],[9,9,]),'HASH':([4,14,],[11,11,]),'NUMBER':([4,9,11,14,],[12,12,12,12,]),'SYMBOL':([4,9,11,14,],[13,13,13,13,]),'COMMA':([7,8,10,12,13,15,16,],[14,-7,-10,-11,-12,-8,-9,]),} + +_lr_action = {} +for _k, _v in _lr_action_items.items(): + for _x,_y in zip(_v[0],_v[1]): + if not _x in _lr_action: _lr_action[_x] = {} + _lr_action[_x][_k] = _y +del _lr_action_items + +_lr_goto_items = {'start':([0,],[1,]),'command':([0,2,],[3,5,]),'args':([4,],[6,]),'operand':([4,14,],[7,17,]),'address':([4,9,11,14,],[10,15,16,10,]),} + +_lr_goto = {} +for _k, _v in _lr_goto_items.items(): + for _x, _y in zip(_v[0], _v[1]): + if not _x in _lr_goto: _lr_goto[_x] = {} + _lr_goto[_x][_k] = _y +del _lr_goto_items +_lr_productions = [ + ("S' -> start","S'",1,None,None,None), + ('start -> LABEL command','start',2,'p_start','parser.py',41), + ('start -> command','start',1,'p_start','parser.py',42), + ('command -> MNEMONIC','command',1,'p_command','parser.py',48), + ('command -> MNEMONIC args','command',2,'p_command','parser.py',49), + ('args -> operand','args',1,'p_args','parser.py',53), + ('args -> operand COMMA operand','args',3,'p_args','parser.py',54), + ('operand -> REGISTER','operand',1,'p_operand','parser.py',60), + ('operand -> AT address','operand',2,'p_operand','parser.py',61), + ('operand -> HASH address','operand',2,'p_operand','parser.py',62), + ('operand -> address','operand',1,'p_operand','parser.py',63), + ('address -> NUMBER','address',1,'p_address','parser.py',67), + ('address -> SYMBOL','address',1,'p_address','parser.py',68), +] diff --git a/ass3/zbirnik/src/zbirnik/test_emit.py b/ass3/zbirnik/src/zbirnik/test_emit.py new file mode 100644 index 0000000..f81e021 --- /dev/null +++ b/ass3/zbirnik/src/zbirnik/test_emit.py @@ -0,0 +1,72 @@ +OPCODES = { + "FIX": 0xC4, + "ADDR": 0x90, + "LDA": 0x00, + "STA": 0x0C, + "JSUB": 0x48, +} + +REGISTERS = { + "A": 0, + "X": 1, + "L": 2, + "B": 3, + "S": 4, + "T": 5, + "F": 6, +} + +from zbirnik.ukazi.f1 import f1 +from zbirnik.EmitCtx import EmitContext + +ctx = EmitContext(OPCODES, REGISTERS, {}) + +node = f1("FIX", None) +result = node.emit(ctx) + +print(result.hex()) + +from zbirnik.ukazi.f2 import f2 + +node = f2("A", "X", "ADDR") +print(node.emit(ctx).hex()) + +from zbirnik.ukazi.f3 import f3 +from zbirnik.adressing import AddrMode + +#IMMEDIATE +node = f3( + operand=5, + mnemonic="LDA", + label=None, + index=False, + adr_mode=AddrMode.IMMEDIATE +) +node.address = 0x1000 +print(node.emit(ctx).hex()) + +#PC RELATIVE +ctx.symtab["NUM"] = 0x1003 + +node = f3( + operand="NUM", + mnemonic="LDA", + label=None, + index=False, + adr_mode=AddrMode.SIMPLE +) +node.address = 0x1000 +print(node.emit(ctx).hex()) + +from zbirnik.ukazi.f4 import f4 +#F4 +ctx.symtab["SUBR"] = 0x12345 +node = f4( + operand="SUBR", + mnemonic="JSUB", + label=None, + index=False, + adr_mode=AddrMode.SIMPLE +) +print(node.emit(ctx).hex()) + diff --git a/ass3/zbirnik/src/zbirnik/ukazi/__init__.py b/ass3/zbirnik/src/zbirnik/ukazi/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/ass3/zbirnik/src/zbirnik/ukazi/__pycache__/__init__.cpython-310.pyc b/ass3/zbirnik/src/zbirnik/ukazi/__pycache__/__init__.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..ea620068fe726763ffcb8e0fc0789b5f3c8724a3 GIT binary patch literal 185 zcmd1j<>g`k0*A`TOc4DTL?8o3AjbiSi&=m~3PUi1CZpdyU!ZTSr;w9cl9!pS;1=Ym9~|JXUtEx{Tb7uWs-IX~Y^-0ElvxCn t)h{kehOW&#o{3;>)`E$9FM literal 0 HcmV?d00001 diff --git a/ass3/zbirnik/src/zbirnik/ukazi/__pycache__/f1.cpython-310.pyc b/ass3/zbirnik/src/zbirnik/ukazi/__pycache__/f1.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..95d18a09af2fca029a67d189e9733dcc67fa037f GIT binary patch literal 902 zcmZWnON$dh5U!q{NhYsl6%hmvx#nPoWv?Q#isB`T0l~R6lj$Cv%{;Q*6LDiaC9r=( zkNHb|^|XJ%lT|ZG2w2cXef_Af>Z>jXgD#-We|%1-4B!ueQ*#l##ASx)BuJJ)&O*lE zEl5Z5El94|hKG)Hr!eyF@fM7jbtk1%F@aNS?SZ+%KtaeP;KQDD6vs4NvMWg3J4l#x zrMDe~u52kUab#QiTQ_XUj_htBY~O(kp^tQZ>m(Nw+sO-+7iE#g*2|)q%3^-PO7UTt z#|YMJ4FW2*fnUzr`Hj6un8J=tM%?<8s>x)Q3#F|uL|UYk5P0Ysl_i=K(H^=TvmGJg zEHXxj9sK)(&;F0qW%*ep$ literal 0 HcmV?d00001 diff --git a/ass3/zbirnik/src/zbirnik/ukazi/__pycache__/f2.cpython-310.pyc b/ass3/zbirnik/src/zbirnik/ukazi/__pycache__/f2.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..13390d0fa571c222886985099bac96d0eda18500 GIT binary patch literal 1133 zcmZ8g&2G~`5T4z&9XCx%1qg`?syJaGYBjy03KaxGNC8m^iCk8RcLPoxJM21$2ItgD zyapWmN_*whCqUxF%qE41v37Q5_S>KNW?XfRiB}^$h|T#CY|N+T_#QOD4@_0T30$&%5*lK|&~6i< za-p5iv~jVNd70NzCZP+gF2?`iObfx6%xy`T6+>&KyoBHH(vQ_tr=zMGSzDFqGi^`n zYL*`E?-jZ(^V7ZOZ(pV-Z(gT%Rz3PWoahv{9;S;?Zg4fVCi`p8Plt;<9ryNUXNEYY zXWAH5#OT{)i)~!Iex-|yuIHxA7$UBPY#L8-SlX``lFIv6*c4!PP$kT4U)w%lZlH?^ z=L=1jT0#bF(ZZ`JmXUugL>DpckFU{a*aRAwu)DD2HS#_Yb#TtjEsTfcVO*40iHTT} zjugzn+*52Bl)D}udHlmQK0lRiu{J_sC9nm+G;}zwX#I9A% zGHg@3DrP&kd1>omnQ31?Cv0upmeC(_TWe!|-Ca03tF=uc&xI3N{l!JAW02MZ`FU92 z-1D=C_EuC8fos0>G_Skp+B>K^tiyL$#M?Y#9Y$6MKhGiI3>7iiq7EyEQ!S-yOF6C7 zydb+H<)`_uSgja3&R5@wysXVla_^yX-F4e#x+tXFcu$8QR7CUlXQ2CHc))g|UE!ns mM7W#lp4<0*wqGJ=# zT_Z^)Kx!Px%K3fy#{ImOfx>XXkroXJ;mBHa!C0=f$h|cZZNakhuME zAa-HtM*sv7G$B(uq7-qKu&Fh&DEW#AOYjRKxTNRShzt9O^qdt~kRCOBmXJ{G z@I>Q+k7~jf%?mPe-x5wnbqJ|#*kpTXYS~PxFcrp~rgEC4ab)Z`74nU7L!p8xglOy} z9Lpqvl-zuXTh-DZ0Fsk)@+&Ru-yj_YEl9u$2GA-jfV|)UZ9$I6B^~x0W9vB_Yuq4+ z(>MR=-Y3g?;TH7=Wa)ubLpV!c)C-S8F`ZH+g$FQ6 z86~NGEl=MAKP^G#RQ&?BfUm7@tbP;?u=+W*DS=phj1~Mgz}`EEF66JBw+p9e742i|93O9UxcVDX-eW6#Saq+& z)omPEC1Y`akiHI+Sad_^b*Xin9(S>yN~^WaT~Ln6pI2A$71Vuv)h1-|a6i_wB#h)# zrg=A;!@-VSL%JxhZJO4QVt2V z3AFkQnayf2MKVcXyp^GspoJ>fsTds*t5-@YAS7&lV~f&y20i* j8`lCD&+DQppSLu;bFr%m-n{=i`mNHT< z5<_}f0_5PYg1lQ$kAf7r>Iaslsw z=!c*L5i}(;I-(RYOWDjBIh1@ygd^N*B3wzYoRKTMW76YGSV4N!xWimX82u+gs3X7= zbgVzE)kMDmAjyadGGc-XCY@7v>Ig@AlJCRjAg=U;2ZET(hG!qVS{2N7V!cVXl_xbj{cJU%)$Rno%@KW38j;9l3ec|0$oz{y5LaTIX5+ zK2`lHP84|iT1`IS`B}V3`qQ1Q z^Gk)-g86BrNa%BlZ$K9s=4C(sCxDWkl9HU#k4Xj97j%zQ4$N5r^f_bd zzF@CeHgm*=Mfx9hT!FS0%DZPDCaftTSW5F{j z8Wj+*@MFgS{aAjLd1|;t855=my|$M`?aPB>==la9f7jn64Bm+ zovN^Gi4M%VaF#Y;96Lq3F5koXdu)m2R`)Gd>ljVeuy`=Y-o|Mn zHe+Z*sdbW_Y$CnwDjTvynk|uxOH0eUi11#PSn(wibono+UI)8p0&8_mU1Y7ot}y&~ zaP<89L(?1_9UUGFp1eFX{$O}8cyajjr3qfe>0BNvl`G436C{v@F5+w=E!mBeWQF1S za#qA+a3&ZPeO=}!$8LcKXGc>8A9~pXK=-AM6L#5$GtWIQ6yS}N1 z?Rwa$Nr&fJF;C8t;sH$cm!LxG(~t!;1iGX6Y=d>EYu}Ke?;*pO4Q3gNYkMJfbr#QL z6qz8xKgT>p97fU4^Ejy6GRie^N!G$r}%(5Ok&DgQa(?@cv&%Jf160Q*X)1inALZ%^wwid?zt_eMEwpg int: + return 0 + + def emit(self, ctx): + # BASE directive + if self.name == "BASE": + if isinstance(self.value, str): + ctx.base = ctx.symtab[self.value] + elif isinstance(self.value, int): + ctx.base = self.value + else: + raise ValueError("Invalid BASE operand") + return None + + # NOBASE directive + if self.name == "NOBASE": + ctx.base = None + return None + + # START, END, LTORG, ... + return None diff --git a/ass3/zbirnik/src/zbirnik/ukazi/f1.py b/ass3/zbirnik/src/zbirnik/ukazi/f1.py new file mode 100644 index 0000000..7e95a5b --- /dev/null +++ b/ass3/zbirnik/src/zbirnik/ukazi/f1.py @@ -0,0 +1,13 @@ +from zbirnik.ukazi.node import Node + +class f1(Node): + def __init__(self, mnemnonic : str, label : str | None = None): + self.mnemonic = mnemnonic + super().__init__(label) + + def size(self) -> int: + return 1 + + def emit(self, ctx): + opcode = ctx.opcodes[self.mnemonic] + return bytes([opcode]) \ No newline at end of file diff --git a/ass3/zbirnik/src/zbirnik/ukazi/f2.py b/ass3/zbirnik/src/zbirnik/ukazi/f2.py new file mode 100644 index 0000000..f9f7e7d --- /dev/null +++ b/ass3/zbirnik/src/zbirnik/ukazi/f2.py @@ -0,0 +1,30 @@ +from zbirnik.ukazi.node import Node + +class f2(Node): + def __init__(self, r1: str, r2: str | None, mnemonic: str, label : str | None = None): + self.r1 = r1 + self.r2 = r2 + self.mnemonic = mnemonic + super().__init__(label) + + def size(self) -> int: + return 2 + + def emit(self, ctx): + opcode = ctx.opcodes[self.mnemonic] + + if isinstance(self.r1, str): + r1_val = ctx.registers[self.r1] + else: + r1_val = self.r1 + + if self.r2 is None: + r2_val = 0 + elif isinstance(self.r2, str): + r2_val = ctx.registers[self.r2] + else: + r2_val = self.r2 + + byte2 = (r1_val << 4) | r2_val + + return bytes([opcode, byte2]) \ No newline at end of file diff --git a/ass3/zbirnik/src/zbirnik/ukazi/f3.py b/ass3/zbirnik/src/zbirnik/ukazi/f3.py new file mode 100644 index 0000000..8da7f9f --- /dev/null +++ b/ass3/zbirnik/src/zbirnik/ukazi/f3.py @@ -0,0 +1,62 @@ +from zbirnik.ukazi.node import Node +from zbirnik.adressing import AddrMode + +class f3(Node): + def __init__(self, operand: str | int | None, mnemonic: str, index : bool, adr_mode: str | None, label : str | None = None): + super().__init__(label) + self.operand = operand + self.mnemonic = mnemonic + self.index = index + self.adr_mode = adr_mode + + def size(self) -> int: + return 3 + + def emit(self, ctx): + opcode = ctx.opcodes[self.mnemonic] + base_opcode = opcode & 0b11111100 + + if self.adr_mode == AddrMode.SIMPLE: + n, i = 1, 1 + elif self.adr_mode == AddrMode.IMMEDIATE: + n, i = 0, 1 + elif self.adr_mode == AddrMode.INDIRECT: + n, i = 1, 0 + else: + raise ValueError("Invalid addressing mode") + + byte1 = base_opcode | (n << 1) | i + + x = 1 if self.index else 0 + + if isinstance(self.operand, int): + target = self.operand + else: + target = ctx.symtab[self.operand] + + pc = self.address + 3 + disp = target - pc + b = 0 + p = 1 + #PC relativno + if -2048 <= disp <= 2047: + b = 0 + p = 1 + #Bazno relativno + elif ctx.base is not None: + disp = target - ctx.base + if 0 <= disp <= 4095: + b = 1 + p = 0 + else: + raise ValueError("Displacement out of range") + + e = 0 + + byte2 = ((x << 7) | (b << 6) | (p << 5) | (e << 4) | ((disp >> 8) & 0x0F)) + byte3 = disp & 0xFF + + return bytes([byte1, byte2, byte3]) + + + diff --git a/ass3/zbirnik/src/zbirnik/ukazi/f4.py b/ass3/zbirnik/src/zbirnik/ukazi/f4.py new file mode 100644 index 0000000..4acc767 --- /dev/null +++ b/ass3/zbirnik/src/zbirnik/ukazi/f4.py @@ -0,0 +1,51 @@ +from zbirnik.ukazi.node import Node +from zbirnik.adressing import AddrMode + +class f4(Node): + def __init__( + self, + operand: str | int | None, + mnemonic: str, + label: str | None = None, + index: bool = False, + adr_mode: AddrMode = AddrMode.SIMPLE + ): + super().__init__(label) + self.operand = operand + self.mnemonic = mnemonic + self.index = index + self.adr_mode = adr_mode + + + def size(self) -> int: + return 4 + + def emit(self, ctx): + opcode = ctx.opcodes[self.mnemonic] + base_opcode = opcode & 0b11111100 + + if self.adr_mode == AddrMode.SIMPLE: + n, i = 1, 1 + elif self.adr_mode == AddrMode.IMMEDIATE: + n, i = 0, 1 + elif self.adr_mode == AddrMode.INDIRECT: + n, i = 1, 0 + else: + raise ValueError("Invalid addressing mode") + + byte1 = base_opcode | (n << 1) | i + x = 1 if self.index else 0 + b = 0 + p = 0 + e = 1 + + if isinstance(self.operand, int): + target = self.operand + else: + target = ctx.symtab[self.operand] + + byte2 = ((x << 7) | (b << 6) | (p << 5) | (e << 4) | ((target >> 16) & 0x0F)) + byte3 = (target >> 8) & 0xFF + byte4 = target & 0xFF + + return bytes([byte1, byte2, byte3, byte4]) diff --git a/ass3/zbirnik/src/zbirnik/ukazi/node.py b/ass3/zbirnik/src/zbirnik/ukazi/node.py new file mode 100644 index 0000000..3bd83a9 --- /dev/null +++ b/ass3/zbirnik/src/zbirnik/ukazi/node.py @@ -0,0 +1,9 @@ +class Node: + def __init__(self, label=None): + self.label = label + self.address = None + + def size(self): + raise NotImplementedError + def emit(self): + raise NotImplementedError diff --git a/ass3/zbirnik/src/zbirnik/ukazi/storage.py b/ass3/zbirnik/src/zbirnik/ukazi/storage.py new file mode 100644 index 0000000..9a488e5 --- /dev/null +++ b/ass3/zbirnik/src/zbirnik/ukazi/storage.py @@ -0,0 +1,43 @@ +from zbirnik.ukazi.node import Node + +class storage(Node): + def __init__(self, val : str | int, name : str, label : str | None = None): + super().__init__(label) + self.val = val + self.name = name + + def size(self) -> int: + return 0 + + def emit(self, ctx): + if self.name == "WORD": + if isinstance(self.value, str): + val = ctx.symtab[self.value] + else: + val = self.value + + val &= 0xFFFFFF # 24-bit signed + b1 = (val >> 16) & 0xFF + b2 = (val >> 8) & 0xFF + b3 = val & 0xFF + return bytes([b1, b2, b3]) + + if self.name == "BYTE": + s = self.value + # C'EOF' + if s.startswith("C'") and s.endswith("'"): + chars = s[2:-1] + return bytes(ord(c) for c in chars) + # X'F1A3' + if s.startswith("X'") and s.endswith("'"): + hexstr = s[2:-1] + return bytes.fromhex(hexstr) + + raise ValueError("Invalid BYTE constant") + + # RESB / RESW → no code + if self.name in ("RESB", "RESW"): + return b"" + + return b"" + diff --git a/ass3/zbirnik/tests/__init__.py b/ass3/zbirnik/tests/__init__.py new file mode 100644 index 0000000..e69de29