Skip to content

Commit

Permalink
Refatoraçao no leitor e no extrator de labels; Criaçao de erros custo…
Browse files Browse the repository at this point in the history
…mizados
  • Loading branch information
adrianbrs committed Jun 10, 2020
1 parent a4107ea commit 67b8958
Show file tree
Hide file tree
Showing 8 changed files with 268 additions and 70 deletions.
15 changes: 8 additions & 7 deletions constants/constants.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,16 @@ const (
//TextSection texto para seção text
TextSection = "text"

//TextSectionAddress endereço início das instruções
TextSectionAddress = 0

//DataSection texto para seção data
DataSection = "data"

//LabelNotFound erro de label não encontrada
LabelNotFound = "Label not found"

//NoneInstructionFound erro de nome de instrução não encontrado
NoneInstructionFound = "None instruction found for this name: %s"
//DataSectionAddress endereço início das instruções
DataSectionAddress = 128

//InvalidOperandCount erro de quantidade de operadores invalidas
InvalidOperandCount = "Invalid operand count"
// MaxErrorCodeDigits define a quantidade máxima de digitos para
// o código de um erro do montador
MaxErrorCodeDigits = 3
)
16 changes: 10 additions & 6 deletions decoder/decoder.go
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
package decoder

import (
"fmt"
"ph1-assembly/constants"
"ph1-assembly/pherror"
)

type metaInstruction struct {
Expand Down Expand Up @@ -30,14 +29,19 @@ var operations = map[string]*metaInstruction{
"HLT": &metaInstruction{opCode: "F0", size: 1},
}

// Decode traduz o mnemônico de uma instrução e retorna
// DecodeText traduz o mnemônico de uma instrução e retorna
// seu opcode e tamanho
func Decode(name string) (string, int, error) {
func DecodeText(name string) (string, int) {
instruction := operations[name]

if instruction == nil {
return "", 0, fmt.Errorf(constants.NoneInstructionFound, name)
panic(pherror.Format(pherror.NoneInstructionFound, name))
}

return instruction.opCode, instruction.size, nil
return instruction.opCode, instruction.size
}

// DecodeData decodifica um tipo de dados, retornando seu tamanho em bytes
func DecodeData(name string) (size int) {
return 1
}
14 changes: 6 additions & 8 deletions extractor/instructions.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"ph1-assembly/constants"
"ph1-assembly/decoder"
"ph1-assembly/input"
"ph1-assembly/pherror"
"strconv"
)

Expand All @@ -23,20 +24,16 @@ type Data struct {

//ExtractInstructions efetua a segunda passagem no código, guardando as
// instrucoes em uma lista de struct
func ExtractInstructions(contents []*input.SourceLine, labelMap map[string]int) []Instruction {
func ExtractInstructions(textContent []*input.SourceLine, labelMap map[string]int) []Instruction {
var instructions = make([]Instruction, 0)

for _, srcLine := range contents {
for _, srcLine := range textContent {

if srcLine.Name == constants.TextSection || srcLine.Name == constants.DataSection {
break
}

opCode, size, err := decoder.Decode(srcLine.Name)

if err != nil {
panic(err)
}
opCode, size := decoder.DecodeText(srcLine.Name)

// Cria instrução sem operando
instruction := &Instruction{
Expand All @@ -51,10 +48,11 @@ func ExtractInstructions(contents []*input.SourceLine, labelMap map[string]int)
operandValue, found := labelMap[srcLine.Operand]

if found == false {
var err error
operandValue, err = strconv.Atoi(srcLine.Operand)

if err != nil {
panic(constants.LabelNotFound)
panic(pherror.Format(pherror.LabelNotFound, srcLine.Operand))
}
}

Expand Down
38 changes: 11 additions & 27 deletions extractor/labels.go
Original file line number Diff line number Diff line change
@@ -1,42 +1,26 @@
package extractor

import (
"ph1-assembly/decoder"
"ph1-assembly/input"
)

// ExtractLabels efetua a primeira passagem no código, guardando os rótulos
// e seus endereços em um map que irá retornar
func ExtractLabels(contents []*input.SourceLine) map[string]int {
func ExtractLabels(src *input.Source) map[string]int {
labels := map[string]int{}

var labelMap = make(map[string]int)

sections := map[string]int{
"text": 0,
"data": 128,
}
currentSection := ""

for _, srcLine := range contents {
if _, ok := sections[srcLine.Name]; ok {
currentSection = srcLine.Name
continue
}

srcLine.Address = sections[currentSection]

_, size, _ := decoder.Decode(srcLine.Name)

if size == 0 {
size = 1
// Encontra as labels
for _, srcText := range src.Text {
if srcText.Label != "" {
labels[srcText.Label] = srcText.Address
}
sections[currentSection] += size
}

// Adiciona o label no map se a label não for vazia
if srcLine.Label != "" {
labelMap[srcLine.Label] = srcLine.Address
for _, srcData := range src.Data {
if srcData.Label != "" {
labels[srcData.Label] = srcData.Address
}
}

return labelMap
return labels
}
76 changes: 66 additions & 10 deletions input/reader.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ import (
"bufio"
"os"
"ph1-assembly/constants"
"ph1-assembly/decoder"
"ph1-assembly/pherror"
"regexp"
"strings"
)
Expand All @@ -17,16 +19,38 @@ var (

// SourceLine contém os dados necessários de uma linha do código fonte
type SourceLine struct {
Label string
Name string
Operand string
Address int
Label string
Name string
Operand string
LineNumber int
Address int
}

// Source contém as informações do código fonte
type Source struct {
Filename string
Contents []*SourceLine
Filename string
Text []*SourceLine
Data []*SourceLine
CurrentTextAddress int
CurrentDataAddress int
}

// AppendText adiciona uma nova linha na seção text, atribuindo
// seu endereço e validando a instrução
func (src *Source) AppendText(line *SourceLine) {
_, size := decoder.DecodeText(line.Name)
line.Address = src.CurrentTextAddress
src.Text = append(src.Text, line)
src.CurrentTextAddress += size
}

// AppendData adiciona uma nova linha na seção data, atribuindo
// seu endereço e validando o tipo de dado
func (src *Source) AppendData(line *SourceLine) {
size := decoder.DecodeData(line.Name)
line.Address = src.CurrentDataAddress
src.Data = append(src.Data, line)
src.CurrentDataAddress += size
}

// ReadSource lê o codigo fonte e transforma para o tipo Source
Expand All @@ -37,11 +61,43 @@ func ReadSource(filename string) (source *Source, err error) {
return
}

source = &Source{Filename: filename}
source = &Source{
Filename: filename,
CurrentTextAddress: constants.TextSectionAddress,
CurrentDataAddress: constants.DataSectionAddress,
}

for _, line := range contents {
// Seção atual do código (text ou data)
var section string

// Cria um erro relacionado ao arquivo
fileError := &pherror.ErrorType{Filename: filename}

// Lẽ cada linha salvanda na seção atual
for lineNumber, line := range contents {
// Atualiza a linha atual do erro de arquivo
fileError.LineNumber = lineNumber + 1

// Faz uma validação previa da linha
if validateSourceLine(line) {
source.Contents = append(source.Contents, parseSourceLine(line))

// Extrai os dados da linha atual
sourceLine := parseSourceLine(line)
sourceLine.LineNumber = lineNumber + 1

// Verifica a seção atual
if strings.ToUpper(sourceLine.Name) == strings.ToUpper(constants.TextSection) {
section = constants.TextSection
} else if strings.ToUpper(sourceLine.Name) == strings.ToUpper(constants.DataSection) {
section = constants.DataSection
} else if section == constants.TextSection {
source.AppendText(sourceLine)
} else if section == constants.DataSection {
source.AppendData(sourceLine)
} else {
err := pherror.Join(pherror.DecoratorNotFound, fileError)
panic(pherror.Format(err, sourceLine.Name))
}
}
}

Expand All @@ -63,7 +119,7 @@ func parseSourceLine(line string) (srcLine *SourceLine) {
match := lineMatchRegex.FindStringSubmatch(line)

if len(match) == 0 {
panic(constants.InvalidOperandCount)
panic(pherror.InvalidOperandCount)
}

// Instantcia um novo SourceLine
Expand Down
42 changes: 30 additions & 12 deletions main.go
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
package main

import (
"errors"
"fmt"
"os"
"path/filepath"
"ph1-assembly/extractor"
"ph1-assembly/input"
"ph1-assembly/output"
"ph1-assembly/pherror"
"strings"
)

Expand All @@ -19,29 +22,44 @@ type Options struct {
// Mount lê um arquivo fonte em assembly PH1 e monta para linguagem de máquina
// no padrão do emulador PH1
func Mount(opt *Options) {
// Validação para permitir que o usuário tente mais vezes caso o nome do arquivo esteja
// errado
source, err := input.ReadSource(opt.Input)

if err != nil {
// Validação para permitir que o usuário tente mais vezes caso o nome do arquivo esteja
// errado
for err != nil {
fmt.Print("Cannot read input file, please try again: ")
fmt.Scanln(&opt.Input)
fmt.Println()
for err != nil {
var perr *os.PathError
if errors.As(err, &perr) {
panic(pherror.Format(pherror.FileNotFound, opt.Input))
} else {
panic(pherror.Format(pherror.CannotOpenFile, opt.Input))
}
}

// Primeira passagem: labels
labels := extractor.ExtractLabels(source.Contents)
labels := extractor.ExtractLabels(source)

// Segunda passagem: instruções
instructions := extractor.ExtractInstructions(source.Contents, labels)
instructions := extractor.ExtractInstructions(source.Text, labels)

// Gera o arquivo de saída a partir do nome definido no options
output.CreateOutputFile(instructions, opt.Output)
}

func main() {
// Tratamento de erro
defer func() {
if err := recover(); err != nil {
pherr := pherror.Format(err)
fmt.Println(pherr)

if pherr.Code != 0 {
os.Exit(pherr.Code)
}
os.Exit(1)
}
}()

if len(os.Args) < 2 {
panic("Informe o nome do arquivo")
panic(pherror.MissingInputFile)
}
var input, output string

Expand All @@ -54,7 +72,7 @@ func main() {
} else {

// Gera o output através do nome do arquivo
output = strings.Split(input, ".")[0] + ".ph1"
output = strings.Split(filepath.Base(input), ".")[0] + ".ph1"
}

options := &Options{
Expand Down
46 changes: 46 additions & 0 deletions pherror/errors.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
package pherror

var (
//MissingInputFile erro de arquivo de entrada não informado
MissingInputFile = &ErrorType{
Code: 1,
Message: "No input file given",
}

//FileNotFound erro arquivo não encontrado
FileNotFound = &ErrorType{
Code: 2,
Message: "File \"%s\" not found",
}

//CannotOpenFile erro genérico ao falhar tentando abrir um arquivo
CannotOpenFile = &ErrorType{
Code: 3,
Message: "Error opening file %s",
}

//LabelNotFound erro de label não encontrada
LabelNotFound = &ErrorType{
Code: 4,
Message: "Label \"%s\" not found",
}

//NoneInstructionFound erro de nome de instrução não encontrado
NoneInstructionFound = &ErrorType{
Code: 5,
Message: "None instruction found for \"%s\"",
}

//InvalidOperandCount erro de quantidade de operadores invalidas
InvalidOperandCount = &ErrorType{
Code: 6,
Message: "Invalid operand count",
}

//DecoratorNotFound erro retornado ao não encontrar nenhuma instrução ou
// decorador com o nome informado
DecoratorNotFound = &ErrorType{
Code: 7,
Message: "Decorator or instruction not found for \"%s\"",
}
)
Loading

0 comments on commit 67b8958

Please sign in to comment.