go-vise

Constrained Size Output Virtual Machine
Info | Log | Files | Refs | README | LICENSE

main.go (3084B)


      1 package main
      2 
      3 import (
      4 	"flag"
      5 	"fmt"
      6 	"io/ioutil"
      7 	"log"
      8 	"os"
      9 	"strconv"
     10 	"strings"
     11 
     12 	"github.com/alecthomas/participle/v2"
     13 	"github.com/alecthomas/participle/v2/lexer"
     14 
     15 	"git.defalsify.org/vise.git/asm"
     16 )
     17 
     18 type arg struct {
     19 	One   *string `(@Sym | @NumFirst)`
     20 	Two   *string `((@Sym | @NumFirst) Whitespace?)?`
     21 	Three *string `((@Sym | @NumFirst) Whitespace?)?`
     22 }
     23 
     24 type instruction struct {
     25 	OpCode  string `@Ident`
     26 	OpArg   arg    `(Whitespace @@)?`
     27 	Comment string `Comment? EOL`
     28 }
     29 
     30 type asmAsm struct {
     31 	Instructions []*instruction `@@*`
     32 }
     33 
     34 type processor struct {
     35 	*asm.FlagParser
     36 }
     37 
     38 func newProcessor(fp string) (*processor, error) {
     39 	o := &processor{
     40 		asm.NewFlagParser(),
     41 	}
     42 	_, err := o.Load(fp)
     43 	return o, err
     44 }
     45 
     46 func (p *processor) processFlag(s []string, one *string, two *string) ([]string, error) {
     47 	_, err := strconv.Atoi(*one)
     48 	if err != nil {
     49 		r, err := p.GetAsString(*one)
     50 		if err != nil {
     51 			return nil, err
     52 		}
     53 		log.Printf("translated flag %s to %s", *one, r)
     54 		s = append(s, r)
     55 	} else {
     56 		s = append(s, *one)
     57 	}
     58 	return append(s, *two), nil
     59 }
     60 
     61 func (p *processor) pass(s []string, a arg) []string {
     62 	for _, r := range []*string{a.One, a.Two, a.Three} {
     63 		if r == nil {
     64 			break
     65 		}
     66 		s = append(s, *r)
     67 	}
     68 	return s
     69 }
     70 
     71 func (pp *processor) run(b []byte) ([]byte, error) {
     72 	asmLexer := lexer.MustSimple([]lexer.SimpleRule{
     73 		{"Comment", `(?:#)[^\n]*`},
     74 		{"Ident", `^[A-Z]+`},
     75 		{"NumFirst", `[0-9][a-zA-Z0-9]*`},
     76 		{"Sym", `[a-zA-Z_\*\.\^\<\>][a-zA-Z0-9_]*`},
     77 		{"Whitespace", `[ \t]+`},
     78 		{"EOL", `[\n\r]+`},
     79 		{"Quote", `["']`},
     80 	})
     81 	asmParser := participle.MustBuild[asmAsm](
     82 		participle.Lexer(asmLexer),
     83 		participle.Elide("Comment", "Whitespace"),
     84 	)
     85 	ast, err := asmParser.ParseString("preprocessor", string(b))
     86 	if err != nil {
     87 		return nil, err
     88 	}
     89 
     90 	b = []byte{}
     91 	for _, v := range ast.Instructions {
     92 		s := []string{v.OpCode}
     93 		if v.OpArg.One != nil {
     94 			switch v.OpCode {
     95 			case "CATCH":
     96 				s = append(s, *v.OpArg.One)
     97 				s, err = pp.processFlag(s, v.OpArg.Two, v.OpArg.Three)
     98 				if err != nil {
     99 					return nil, err
    100 				}
    101 			case "CROAK":
    102 				s, err = pp.processFlag(s, v.OpArg.One, v.OpArg.Two)
    103 				if err != nil {
    104 					return nil, err
    105 				}
    106 			default:
    107 				s = pp.pass(s, v.OpArg)
    108 			}
    109 		}
    110 		b = append(b, []byte(strings.Join(s, " "))...)
    111 		b = append(b, 0x0a)
    112 	}
    113 
    114 	return b, nil
    115 }
    116 
    117 func main() {
    118 	var ppfp string
    119 	flag.StringVar(&ppfp, "f", "", "preprocessor data to load")
    120 	flag.Parse()
    121 	if len(flag.Args()) < 1 {
    122 		os.Exit(1)
    123 	}
    124 	fp := flag.Arg(0)
    125 	v, err := ioutil.ReadFile(fp)
    126 	if err != nil {
    127 		fmt.Fprintf(os.Stderr, "read error: %v\n", err)
    128 		os.Exit(1)
    129 	}
    130 
    131 	if len(ppfp) > 0 {
    132 		pp, err := newProcessor(ppfp)
    133 		if err != nil {
    134 			fmt.Fprintf(os.Stderr, "preprocessor load error: %v\n", err)
    135 			os.Exit(1)
    136 		}
    137 
    138 		v, err = pp.run(v)
    139 		if err != nil {
    140 			fmt.Fprintf(os.Stderr, "preprocess error: %v\n", err)
    141 			os.Exit(1)
    142 		}
    143 	}
    144 	log.Printf("preprocessor done")
    145 
    146 	n, err := asm.Parse(string(v), os.Stdout)
    147 	if err != nil {
    148 		fmt.Fprintf(os.Stderr, "parse error: %v\n", err)
    149 		os.Exit(1)
    150 	}
    151 	log.Printf("parsed total %v bytes", n)
    152 }