Skip to content

Commit

Permalink
feature/utils_cli (#3)
Browse files Browse the repository at this point in the history
Add a utils cli subcommand
  • Loading branch information
nbbeeken authored Aug 21, 2019
2 parents 59e399e + 11d2983 commit d23d40b
Show file tree
Hide file tree
Showing 26 changed files with 178 additions and 701 deletions.
8 changes: 7 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,12 +23,18 @@ If you installed via pip you should now have a binary in your path that you can
dashmips
```

or equivalently

```sh
python -m dashmips
```

## "Compiling"

To compile or run a mips program you run:

```sh
dashmips compile -f FILE.mips
dashmips compile FILE.mips
```

What "compilation" means in dashmips is a conversion of the source file to a json format that is better understood by the program. You can use this json format to inspect the internals of how your mips program is interpreted by dashmips.
Expand Down
45 changes: 24 additions & 21 deletions dashmips/__main__.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,21 +11,11 @@

def main_compile(args: argparse.Namespace) -> int:
"""Compile/Exec mips code."""
if args.file:
program = preprocess(args.file)
program = preprocess(args.FILE)
if args.out:
json.dump(program.to_dict(), args.out)

if args.json:
# Ending matches socket communication
else:
print(json.dumps(program.to_dict()))

if args.vscode:
snippets = generate_snippets()
print(json.dumps(snippets, indent=4))
print("\n\n\n")
print(instruction_name_regex())

return 0


Expand Down Expand Up @@ -75,44 +65,53 @@ def main_docs(args: argparse.Namespace) -> int:
print("Instructions")
print(f"{'format':<35}{'description'}")
print(f"{'------':<35}{'-----------'}")
snips = generate_snippets(examples=True)
snippets = generate_snippets(examples=True)
instr_list = list(Instructions.items())
instr_list.sort(key=lambda i: i[0])
for instrname, instruction in instr_list:
ex_str = snips[instrname]["example"]
desc = snips[instrname]["description"]
ex_str = snippets[instrname]["example"]
desc = snippets[instrname]["description"]
print(f"{ex_str:35}# ", end="")
print(f"{desc}")

return 0


def main_utils(args: argparse.Namespace) -> int:
"""General utilities to help a mips developer."""
if args.snippets:
snippets = generate_snippets()
print(json.dumps(snippets, indent=4))
if args.instruction_regex:
print(instruction_name_regex())
return 0


def main() -> NoReturn:
"""Entry function for Dashmips."""
parser = argparse.ArgumentParser("dashmips")

parser.add_argument("-v", "--version", action="version", version="0.0.11")
parser.add_argument("-v", "--version", action="version", version="0.1.0")

sbp = parser.add_subparsers(title="commands", dest="command")
compileparse = sbp.add_parser("compile", aliases=["c"])
runparse = sbp.add_parser("run", aliases=["r"])
debugparse = sbp.add_parser("debug", aliases=["d"])
docsparse = sbp.add_parser("docs", aliases=["h"])
utilsparse = sbp.add_parser("utils", aliases=["u"])

compileparse.add_argument("-f", "--file", type=argparse.FileType("r", encoding="utf8"), help="Input file")
compileparse.add_argument("FILE", type=argparse.FileType("r", encoding="utf8"), help="Input file")
compileparse.add_argument("-o", "--out", type=argparse.FileType("w", encoding="utf8"), help="Output file name")
compileparse.add_argument("-j", "--json", action="store_true", help="Output json to stdout")
compileparse.add_argument("--vscode", action="store_true", help="Output json for vscode")
compileparse.set_defaults(func=main_compile)

runparse.add_argument("FILE", type=argparse.FileType("r", encoding="utf8"), help="Input file")
runparse.add_argument("-a", "--args", dest="mips_args", nargs="*", help="Arguments to pass into the mips main")
runparse.add_argument("-t", "--vt100", action="store_true", help="Start VT100 Simulator")
runparse.add_argument("--vt100", action="store_true", help="Start VT100 Simulator")
runparse.set_defaults(func=main_run)

debugparse.add_argument("FILE", type=argparse.FileType("r", encoding="utf8"), help="Input file")
debugparse.add_argument("-a", "--args", dest="mips_args", nargs="*", help="Arguments to pass into the mips main")
debugparse.add_argument("-t", "--vt100", action="store_true", help="Start VT100 Simulator")
debugparse.add_argument("--vt100", action="store_true", help="Start VT100 Simulator")
debugparse.add_argument("-p", "--port", type=int, default=2390, help="run debugger on port")
debugparse.add_argument("-i", "--host", default="0.0.0.0", help="run debugger on host")
debugparse.add_argument("-l", "--log", dest="log", action="store_true", help="Log all network traffic")
Expand All @@ -122,6 +121,10 @@ def main() -> NoReturn:
docsparse.add_argument("-i", "--instr", action="store_true", help="Show instruction table")
docsparse.set_defaults(func=main_docs)

utilsparse.add_argument("--snippets", action="store_true", help="Output snippets json")
utilsparse.add_argument("--instruction_regex", action="store_true", help="Output regex that matches instructions")
utilsparse.set_defaults(func=main_utils)

prog_args = parser.parse_args()
if not hasattr(prog_args, "func"):
# This is for python 3.6 compatibility
Expand Down
30 changes: 6 additions & 24 deletions dashmips/debugger.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,27 +9,19 @@
import os
from typing import List, Dict, Any, Tuple

from .utils import MipsException
from .models import MipsProgram
from .run import next_instruction, run
from .utils import MipsException


def debug_start(program: MipsProgram, params=None) -> Dict[str, int]:
"""Debug start.
:param operation: dict
:param program: MipsProgram
"""
"""Debug start."""
program.registers["pc"] = program.labels["main"].value
return {"pid": os.getpid()}


def debug_step(program: MipsProgram, params) -> Dict[str, Any]:
"""Debug step.
:param operation: dict
:param program: MipsProgram
"""
"""Debug step."""
try:
next_instruction(program)

Expand All @@ -43,20 +35,14 @@ def debug_step(program: MipsProgram, params) -> Dict[str, Any]:


def debug_continue(program: MipsProgram, params) -> Dict[str, Any]:
"""Debug continue.
:param program: MipsProgram
"""
"""Debug continue."""
starting_pc = program.registers["pc"]
# vscode should have done the translation
# these are pc values (aka index into srclines)
verified, breakpoints = verify_breakpoints(program, params)

def breaking_condition(program: MipsProgram) -> bool:
"""Condition function to stop execution.
:param program:
"""
"""Condition function to stop execution."""
nonlocal starting_pc
if program.registers["pc"] == starting_pc:
# current instruction will execute even if on breakpoint
Expand All @@ -79,11 +65,7 @@ def breaking_condition(program: MipsProgram) -> bool:


def debug_stop(program: MipsProgram, params) -> Dict[str, bool]:
"""Stop messages incoming mean nothing to a server.
:param operation: dict
:param program: MipsProgram
"""
"""Stop messages incoming mean nothing to a server."""
return {"exited": True}


Expand Down
56 changes: 10 additions & 46 deletions dashmips/directives.py
Original file line number Diff line number Diff line change
@@ -1,91 +1,55 @@
"""Directive handling."""
from typing import Union

from .utils import parse_int, bytesify
from .hardware import Memory
from .utils import parse_int, bytesify, MipsException


def directive_align(data: str, memory: Memory):
"""Align directive.
:param name: str:
:param data: str:
:param memory: Memory:
"""
raise Exception("Unsupported directive.")
"""Align directive."""
raise MipsException("Unsupported directive.")
return None


def directive_asciiz(data: str, memory: Memory) -> int:
"""Asciiz directive.
:param name: str:
:param data: str:
:param memory: Memory:
"""
"""Asciiz directive."""
string = data[1:-1].encode("ascii", "ignore").decode("unicode_escape")
address = memory.extend_data(bytesify(string, null_byte=True))
return address


def directive_ascii(data: str, memory: Memory) -> int:
"""Ascii directive.
:param name: str:
:param data: str:
:param memory: Memory:
"""
"""Ascii directive."""
string = data[1:-1].encode("ascii", "ignore").decode("unicode_escape")
address = memory.extend_data(bytesify(string, null_byte=False))
return address


def directive_byte(data: str, memory: Memory) -> int:
"""Byte directive.
:param name: str:
:param data: str:
:param memory: Memory:
"""
"""Byte directive."""
value = bytesify(parse_int(data), size=1)
address = memory.extend_data(value)
return address


def directive_half(data: str, memory: Memory) -> int:
"""Half directive.
:param name: str:
:param data: str:
:param memory: Memory:
"""
"""Half directive."""
value = bytesify(parse_int(data), size=2)
address = memory.extend_data(value)
return address


def directive_word(data: str, memory: Memory) -> int:
"""Word directive.
:param name: str:
:param data: str:
:param memory: Memory:
"""
"""Word directive."""
value = bytesify(parse_int(data), size=4)
address = memory.extend_data(value)
return address


def directive_space(data: str, memory: Memory) -> int:
"""Space directive.
:param name: str:
:param data: str:
:param memory: Memory:
"""
"""Space directive."""
value = parse_int(data)
if value > 0x77359400:
# 2 Gigabytes of space...
raise Exception("Please use less memory...")
raise MipsException("Please use less memory...")
address = memory.extend_data(bytes([0] * value))
return address
3 changes: 1 addition & 2 deletions dashmips/extension.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,15 +32,14 @@ def generate_snippets(examples: bool = False) -> Dict[str, Dict[str, str]]:
"scope": "mips",
}
if examples:
example = build_example(ins.name, ins.pattern, ins.label)
example = build_example(ins.name, ins.pattern)
snippets[name]["example"] = example
return snippets


def build_body(name: str, pattern: str, label: bool) -> str:
"""Create snippet body.
:param label:
:param name: Instruction name
:param pattern: Instruction regex pattern
"""
Expand Down
9 changes: 4 additions & 5 deletions dashmips/instructions/Instruction.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,8 @@
class Instruction:
"""Instruction Class, callable."""

def __init__(self, fn, regex_ptrn: str, parser, label: bool = False):
"""
Regex and argument parser for instruction.
def __init__(self, fn, regex_pattern: str, parser, label: bool = False):
"""Regex and argument parser for instruction.
Adds itself to list upon instantiation.
"""
Expand All @@ -27,8 +26,8 @@ def __init__(self, fn, regex_ptrn: str, parser, label: bool = False):
self.description = ""

self.label = label
self.pattern = regex_ptrn
self.regex = f"({self.name}){regex_ptrn}".format(**RE.ALL)
self.pattern = regex_pattern
self.regex = f"({self.name}){regex_pattern}".format(**RE.ALL)
self.parser = parser

def __call__(self, program: MipsProgram, args: Iterable[Any] = tuple()):
Expand Down
12 changes: 2 additions & 10 deletions dashmips/instructions/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,24 +3,16 @@
NOTE: If you add a new file/module to this package *YOU MUST*
import the file to `dashmips/__init__.py`
"""
from typing import Union

from .Instruction import Instruction

Instructions = {}


def mips_instruction(pattern: str, parser, label: bool = False):
"""Make an Instruction object from decorated function.
:param pattern: param parser:
:param parser:
"""
"""Make an Instruction object from decorated function."""
def decorator(function) -> Instruction:
"""Instruction Decorator wrapper.
:param function:
"""
"""Instruction Decorator wrapper."""
instr = Instruction(function, pattern, parser, label=label)
Instructions[instr.name] = instr
return instr
Expand Down
17 changes: 3 additions & 14 deletions dashmips/instructions/imm_instructions.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,29 +8,18 @@


def parse(args: Tuple[str, str, str]) -> Tuple[str]:
"""Parse label to pass to instruction function.
:param args:
"""
"""Parse label to pass to instruction function."""
return (args[2],)


@mips_instruction(PATTERN, parse, label=True)
def j(program: MipsProgram, address: str):
"""Jump unconditionally to label.
:param program:
:param address:
"""
"""Jump unconditionally to label."""
program.registers["pc"] = program.labels[address].value - 1


@mips_instruction(PATTERN, parse, label=True)
def jal(program: MipsProgram, address: str):
"""Jump unconditionally to label and set $ra to current $pc.
:param program:
:param address:
"""
"""Jump unconditionally to label and set $ra to current $pc."""
program.registers["$ra"] = program.registers["pc"] + 1
program.registers["pc"] = program.labels[address].value - 1
Loading

0 comments on commit d23d40b

Please sign in to comment.