Example #1
0
// Run converts a Hack assembly code that `a` holds to a Hack binary code
// and write it into out.
func (a *Asm) Run(out io.Writer) error {
	//=== first loop: only creating a symbol table ===//
	for a.p.HasMoreCommands() {
		if e := a.p.Advance(); e != nil {
			return fmt.Errorf("asm: %s", e.Error())
		}

		// first loop focuses on label commands, so skip the others
		if a.p.CommandType() != parser.LCommand {
			continue
		}

		// add label symbol and next ROM address
		a.st.AddEntry(a.p.Symbol(), a.p.ROMAddr()+1)
	}

	//=== second loop: parsing entire code ===//
	a.p = parser.NewParser(bytes.NewBuffer(a.data))
	for a.p.HasMoreCommands() {
		if e := a.p.Advance(); e != nil {
			return fmt.Errorf("asm: %s", e.Error())
		}

		var (
			b   int
			err error
		)
		switch a.p.CommandType() {
		case parser.LCommand:
			// skip a label command
			continue
		case parser.ACommand:
			symb := a.p.Symbol()
			if b, err = strconv.Atoi(symb); err != nil {
				// add the symbol only if it is not an integer and is not contained yet in symbol table
				if !a.st.Contains(symb) {
					a.st.AddVar(symb)
				}
				// if symbol is not an integer, get its address from symbol table
				b = int(a.st.GetAddress(symb))
			}
		case parser.CCommand:
			if b, err = a.formatCCmd(a.p.Dest(), a.p.Comp(), a.p.Jump()); err != nil {
				return fmt.Errorf("failed to parse command: %s", err.Error())
			}
		}

		if e := a.write(out, b); e != nil {
			return fmt.Errorf("failed to write output: %s", e.Error())
		}
	}
	return nil
}
Example #2
0
// New creates a new Asm object that converts `in` to a Hack binary code.
func New(in io.Reader) (*Asm, error) {
	data, err := ioutil.ReadAll(in)
	if err != nil {
		return nil, fmt.Errorf("asm.New: %s", err.Error())
	}

	a := &Asm{
		data: data,
		p:    parser.NewParser(bytes.NewBuffer(data)),
		c:    &code.Code{},
		st:   symbtbl.NewSymbolTable(),
	}
	return a, nil
}