-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
0 parents
commit f673534
Showing
2 changed files
with
315 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,161 @@ | ||
package main | ||
|
||
import ( | ||
"bufio" | ||
"fmt" | ||
"os" | ||
"strconv" | ||
"strings" | ||
|
||
"gitlab.lazymio.cn/mio/miniplc0/vm" | ||
) | ||
|
||
var debugHelp = `Simple miniplc0 debugger. | ||
You can use the abbreviation of a command. | ||
[H]elp -- Show this message. | ||
[N]ext -- Run a single instruction. | ||
[L]ist n -- List n instructions. | ||
[S]tack n -- Show n stack elemets. | ||
[I]formation -- Show current information. | ||
[Q]uit -- Quit the debugger. | ||
` | ||
|
||
// [R]estart -- Restart the debugging. Not impleneted | ||
|
||
type cmd int32 | ||
|
||
const ( | ||
cNext cmd = iota | ||
cList | ||
cStack | ||
cInformation | ||
cRestart | ||
cHelp | ||
cQuit | ||
) | ||
|
||
type debuggerCommand struct { | ||
C cmd | ||
X int32 | ||
} | ||
|
||
func newCommandFromString(line string) *debuggerCommand { | ||
ln := strings.TrimSpace(line) | ||
tokens := strings.Split(ln, " ") | ||
if len(tokens) == 0 { | ||
return nil | ||
} | ||
if len(tokens) == 1 { | ||
switch strings.ToLower(tokens[0]) { | ||
case "h": | ||
fallthrough | ||
case "help": | ||
return &debuggerCommand{C: cHelp} | ||
case "q": | ||
fallthrough | ||
case "quit": | ||
return &debuggerCommand{C: cQuit} | ||
case "r": | ||
fallthrough | ||
case "restart": | ||
//return &debuggerCommand{C: cRestart} | ||
return nil | ||
case "i": | ||
fallthrough | ||
case "info": | ||
fallthrough | ||
case "infomation": | ||
return &debuggerCommand{C: cInformation} | ||
case "l": | ||
fallthrough | ||
case "list": | ||
return &debuggerCommand{C: cList, X: 10} | ||
case "s": | ||
fallthrough | ||
case "stack": | ||
return &debuggerCommand{C: cStack, X: 20} | ||
case "n": | ||
fallthrough | ||
case "next": | ||
return &debuggerCommand{C: cNext} | ||
} | ||
return nil | ||
} | ||
if len(tokens) == 2 { | ||
x, err := strconv.ParseInt(tokens[1], 10, 32) | ||
if err != nil { | ||
return nil | ||
} | ||
switch strings.ToLower(tokens[0]) { | ||
case "l": | ||
fallthrough | ||
case "list": | ||
return &debuggerCommand{C: cList, X: int32(x)} | ||
case "s": | ||
fallthrough | ||
case "stack": | ||
return &debuggerCommand{C: cStack, X: int32(x)} | ||
} | ||
return nil | ||
} | ||
return nil | ||
} | ||
|
||
// Debug debugs the epf file. | ||
func Debug(file *os.File) { | ||
epf, err := vm.NewEPFv1FromFile(file) | ||
if err != nil { | ||
panic(err) | ||
} | ||
v := vm.NewVMDefault(len(epf.GetInstructions()), epf.GetEntry()) | ||
v.Load(epf.GetInstructions()) | ||
scanner := bufio.NewScanner(os.Stdin) | ||
fmt.Print(debugHelp) | ||
for true { | ||
fmt.Print(">") | ||
scanner.Scan() | ||
cmd := newCommandFromString(scanner.Text()) | ||
quit := false | ||
if cmd == nil { | ||
fmt.Println("Wrong format.\nType 'help' to see more.") | ||
continue | ||
} | ||
switch cmd.C { | ||
case cHelp: | ||
fmt.Print(debugHelp) | ||
case cQuit: | ||
quit = true | ||
break | ||
case cRestart: | ||
quit = true | ||
break | ||
case cNext: | ||
if err = v.RunSingle(); err != nil { | ||
if err == vm.ErrIllegalInstruction { | ||
fmt.Println("The program has stopped.") | ||
} else { | ||
// Should have better user experience. | ||
fmt.Println(err) | ||
fmt.Println(*v) | ||
os.Exit(0) | ||
} | ||
} | ||
fmt.Printf("Next instruction: %v\n", *(v.NextInstruction())) | ||
case cInformation: | ||
fmt.Printf("IP=%v SP=%v\nInstructions[IP]:%v\n", v.IP, v.SP, *(v.NextInstruction())) | ||
stackvalue := v.GetStackTop() | ||
if stackvalue != nil { | ||
fmt.Printf("Stack[SP-1]=%v\n", *stackvalue) | ||
} else { | ||
fmt.Println("Stack[SP-1]=[Invalid]") | ||
} | ||
case cList: | ||
fmt.Println(v.InstructionGraph(cmd.X)) | ||
case cStack: | ||
fmt.Println(v.StackGraph(cmd.X)) | ||
} | ||
if quit { | ||
break | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,154 @@ | ||
package main | ||
|
||
import ( | ||
"bufio" | ||
"fmt" | ||
"os" | ||
|
||
"github.com/BUAA-SE-Compiling/vm" | ||
|
||
flag "github.com/spf13/pflag" | ||
) | ||
|
||
// Run runs the epf file. | ||
func Run(file *os.File) { | ||
epf, err := vm.NewEPFv1FromFile(file) | ||
if err != nil { | ||
panic(err) | ||
} | ||
vm := vm.NewVMDefault(len(epf.GetInstructions()), epf.GetEntry()) | ||
vm.Load(epf.GetInstructions()) | ||
if err := vm.Run(); err != nil { | ||
fmt.Println(vm) | ||
panic(err) | ||
} | ||
} | ||
|
||
// Interprete interprets the input file directly. | ||
func Interprete(file *os.File) { | ||
scanner := bufio.NewScanner(file) | ||
instructions := []vm.Instruction{} | ||
linenum := 0 | ||
for scanner.Scan() { | ||
linenum++ | ||
single := vm.ParseInstruction(scanner.Text()) | ||
if single == nil { | ||
fmt.Fprintf(os.Stderr, "Line %v: Bad instruction", linenum) | ||
} | ||
instructions = append(instructions, *single) | ||
} | ||
vm := vm.NewVMDefault(len(instructions), 0) | ||
vm.Load(instructions) | ||
if err := vm.Run(); err != nil { | ||
fmt.Println(vm) | ||
panic(err) | ||
} | ||
} | ||
|
||
// Decompile decompiles the epf file. | ||
func Decompile(file *os.File) { | ||
epf, err := vm.NewEPFv1FromFile(file) | ||
if err != nil { | ||
panic(err) | ||
} | ||
for _, i := range epf.GetInstructions() { | ||
fmt.Println(i) | ||
} | ||
return | ||
} | ||
|
||
// Assemble assembles the text file to an epf file. | ||
func Assemble(in *os.File, out *os.File) { | ||
scanner := bufio.NewScanner(in) | ||
instructions := []vm.Instruction{} | ||
linenum := 0 | ||
for scanner.Scan() { | ||
linenum++ | ||
single := vm.ParseInstruction(scanner.Text()) | ||
if single == nil { | ||
fmt.Fprintf(os.Stderr, "Line %v: Bad instruction", linenum) | ||
} | ||
instructions = append(instructions, *single) | ||
} | ||
epf := vm.NewEPFv1FromInstructions(instructions, 0) | ||
epf.WriteFile(out) | ||
return | ||
} | ||
|
||
// We don't know whehter a flag is unset or set with an empty string if its default value is an empty string. | ||
func isFlagPassed(name string) bool { | ||
found := false | ||
flag.Visit(func(f *flag.Flag) { | ||
if f.Name == name { | ||
found = true | ||
} | ||
}) | ||
return found | ||
} | ||
|
||
func main() { | ||
var input string | ||
var output string | ||
var decompile bool | ||
var run bool | ||
var debug bool | ||
var help bool | ||
var assemble bool | ||
var interprete bool | ||
flag.CommandLine.Init("Default", flag.ContinueOnError) | ||
flag.Usage = func() { | ||
fmt.Fprintf(os.Stderr, "A vm implementation for mini plc0.\n") | ||
fmt.Fprintf(os.Stderr, "Usage of %s:\n", os.Args[0]) | ||
flag.PrintDefaults() | ||
} | ||
flag.StringVarP(&input, "input", "i", "-", "The input file. The default is os.Stdin.") | ||
flag.StringVarP(&output, "output", "o", "", "The output file.") | ||
flag.BoolVarP(&decompile, "decompile", "D", false, "Decompile without running.") | ||
flag.BoolVarP(&run, "run", "R", false, "Run the file.") | ||
flag.BoolVarP(&interprete, "interprete", "I", false, "Interprete the file.") | ||
flag.BoolVarP(&debug, "debug", "d", false, "Debug the file.") | ||
flag.BoolVarP(&help, "help", "h", false, "Show this message.") | ||
flag.BoolVarP(&assemble, "assemble", "A", false, "Assemble a text file to an EPFv1 file.") | ||
if err := flag.CommandLine.Parse(os.Args[1:]); err != nil { | ||
fmt.Println(err) | ||
fmt.Fprintf(os.Stderr, "Run with --help for details.\n") | ||
os.Exit(2) | ||
} | ||
if help || (decompile && !isFlagPassed("output")) { | ||
flag.Usage() | ||
os.Exit(2) | ||
} | ||
if !debug && !run && !decompile && !assemble && !interprete { | ||
fmt.Fprintf(os.Stderr, "You must choose to decomple, run, assemble, interprete or debug.\n") | ||
fmt.Fprintf(os.Stderr, "Run with --help for details.\n") | ||
os.Exit(2) | ||
} | ||
var file *os.File | ||
var err error | ||
if input != "-" { | ||
file, err = os.Open(input) | ||
if err != nil { | ||
panic(err) | ||
} | ||
defer file.Close() | ||
} else { | ||
file = os.Stdin | ||
} | ||
if debug { | ||
Debug(file) | ||
} else if decompile { | ||
Decompile(file) | ||
} else if run { | ||
Run(file) | ||
} else if assemble { | ||
out, err := os.OpenFile(output, os.O_CREATE|os.O_TRUNC|os.O_WRONLY, 0660) | ||
if err != nil { | ||
panic(err) | ||
} | ||
defer out.Close() | ||
Assemble(file, out) | ||
} else if interprete { | ||
Interprete(file) | ||
} | ||
os.Exit(0) | ||
} |