Skip to content

Commit

Permalink
finish for implementation, remove old one
Browse files Browse the repository at this point in the history
  • Loading branch information
bobertlo committed Dec 5, 2024
1 parent 480f02b commit 311553a
Show file tree
Hide file tree
Showing 3 changed files with 61 additions and 169 deletions.
173 changes: 22 additions & 151 deletions compile.go
Original file line number Diff line number Diff line change
Expand Up @@ -75,34 +75,6 @@ func (c *compiler) loadSymbols() {
}
}

func (c *compiler) reloadReferences() error {
c.labels = make(map[string]int)

var curPseudoLine int
for _, line := range c.lines {
if line.typ == lineInstruction {
for _, label := range line.labels {
_, ok := c.labels[label]
if ok {
return fmt.Errorf("line %d: label '%s' redefined", line.line, label)
}
c.labels[label] = line.codeLine
curPseudoLine = line.codeLine + 1
}
} else if line.typ == linePseudoOp {
for _, label := range line.labels {
_, ok := c.labels[label]
if ok {
return fmt.Errorf("line %d: label '%s' redefined", line.line, label)
}
c.labels[label] = curPseudoLine
}
}
}

return nil
}

func (c *compiler) expandExpression(expr []token, line int) ([]token, error) {
input := expr
var output []token
Expand Down Expand Up @@ -286,107 +258,6 @@ func (c *compiler) assembleLine(in sourceLine) (Instruction, error) {
}, nil
}

func (c *compiler) expandFor(start, end int) error {
output := make([]sourceLine, 0)
codeLineIndex := 0

// concatenate lines preceding start
for i := 0; i < start; i++ {
// curLine := c.lines[i]
if c.lines[i].typ == lineInstruction {
// curLine.line = codeLineIndex
codeLineIndex++
}
output = append(output, c.lines[i])
}

// get labels and count from for line
labels := c.lines[start].labels

countExpr, err := c.expandExpression(c.lines[start].a, start)
if err != nil {
return err
}
count, err := evaluateExpression(countExpr)
if err != nil {
return fmt.Errorf("line %d: invalid for count '%s", c.lines[start].line, c.lines[start].a)
}

for j := 1; j <= count; j++ {
for i := start + 1; i < end; i++ {
if c.lines[i].typ == lineInstruction {
thisLine := c.lines[i]

// subtitute symbols in line
for iLabel, label := range labels {
var newValue []token
if iLabel == len(labels)-1 {
newValue = []token{{tokNumber, fmt.Sprintf("%d", j)}}
} else {
if j == 1 {
newValue = []token{{tokNumber, "0"}}
} else {
newValue = []token{{tokSymbol, "-"}, {tokNumber, fmt.Sprintf("%d", -(1 - j))}}
}
}
thisLine = thisLine.subSymbol(label, newValue)
}

// update codeLine
thisLine.codeLine = codeLineIndex
codeLineIndex++

output = append(output, thisLine)
} else {
output = append(output, c.lines[i])
}
}

}

// continue appending lines until the end of the file
for i := end + 1; i < len(c.lines); i++ {
if c.lines[i].typ == lineInstruction {
thisLine := c.lines[i]
thisLine.codeLine = codeLineIndex
codeLineIndex++
output = append(output, thisLine)
} else {
output = append(output, c.lines[i])
}
}

c.lines = output
return c.reloadReferences()
}

// look for for statements from the bottom up. if one is found it is expanded
// and the function calls itself again.
func (c *compiler) expandForLoops() error {
rofSourceIndex := -1
for i := len(c.lines) - 1; i >= 0; i-- {
if c.lines[i].typ == linePseudoOp {
lop := strings.ToLower(c.lines[i].op)
if lop == "rof" {
rofSourceIndex = i
} else if lop == "for" {
if rofSourceIndex == -1 {
return fmt.Errorf("line %d: unmatched for", c.lines[i].codeLine)
}
err := c.expandFor(i, rofSourceIndex)
if err != nil {
return err
}
return c.expandForLoops()
}
}
}
if rofSourceIndex != -1 {
return fmt.Errorf("line %d: unmatched rof", c.lines[rofSourceIndex].line)
}
return nil
}

func (c *compiler) compile() (WarriorData, error) {
c.loadSymbols()

Expand All @@ -407,11 +278,6 @@ func (c *compiler) compile() (WarriorData, error) {
}
c.values = resolved

err = c.expandForLoops()
if err != nil {
return WarriorData{}, err
}

code := make([]Instruction, 0)
for _, line := range c.lines {
if line.typ != lineInstruction {
Expand Down Expand Up @@ -451,23 +317,28 @@ func CompileWarrior(r io.Reader, config SimulatorConfig) (WarriorData, error) {
return WarriorData{}, err
}

// for {
// symbols, forSeen, err := ScanInput(newBufTokenReader(tokens))
// if err != nil {
// return WarriorData{}, fmt.Errorf("symbol scanner: %s", err)
// }
// if forSeen {
// expandedTokens, err := ForExpand(newBufTokenReader(tokens), symbols)
// if err != nil {
// return WarriorData{}, fmt.Errorf("for: %s", err)
// }
// tokens = expandedTokens
// // oops the embedded for loops are not implemented
// break
// } else {
// break
// }
// }
depth := 0
for {
symbols, forSeen, err := ScanInput(newBufTokenReader(tokens))
if err != nil {
return WarriorData{}, fmt.Errorf("symbol scanner: %s", err)
}
if forSeen {
expandedTokens, err := ForExpand(newBufTokenReader(tokens), symbols)
if err != nil {
return WarriorData{}, fmt.Errorf("for: %s", err)
}
tokens = expandedTokens
// oops the embedded for loops are not implemented
// break
} else {
break
}
depth++
if depth > 12 {
return WarriorData{}, fmt.Errorf("for loop depth exceeded")
}
}

parser := newParser(newBufTokenReader(tokens))
sourceLines, metadata, err := parser.parse()
Expand Down
6 changes: 3 additions & 3 deletions compile_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,12 +43,12 @@ func runWarriorLoadFileTests(t *testing.T, tests []warriorTestCase) {
if test.err {
assert.Error(t, err, fmt.Sprintf("%s: error should be present", test.filename))
} else {
require.NoError(t, err)
require.NoError(t, err, test.loadFilename)
loadInput, err := os.Open(test.loadFilename)
require.NoError(t, err)
require.NoError(t, err, test.loadFilename)
defer loadInput.Close()
expectedData, err := ParseLoadFile(loadInput, test.config)
require.NoError(t, err)
require.NoError(t, err, test.loadFilename)
assert.Equal(t, expectedData.Code, warriorData.Code)
}
}
Expand Down
51 changes: 36 additions & 15 deletions forexpand.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,13 @@ type forExpander struct {
atEOF bool

// for state fields
forCountLabel string
forLineLabels []string
forCount int
forIndex int
forContent []token
forDepth int
forCountLabel string
forLineLabels []string
forLineLabelsToWrite []string
forCount int
forIndex int
forContent []token
forDepth int

symbols map[string][]token

Expand Down Expand Up @@ -116,7 +117,7 @@ func forLine(f *forExpander) forStateFn {
f.labelBuf = make([]string, 0)
return forConsumeLabels
default:
return f.emitConsume(forConsumeEmitLine)
return forConsumeEmitLine
}
}

Expand All @@ -128,7 +129,6 @@ func forLine(f *forExpander) forStateFn {
// other: nil
func forConsumeLabels(f *forExpander) forStateFn {
if f.nextToken.typ == tokText {

if f.nextToken.IsPseudoOp() {
opLower := strings.ToLower(f.nextToken.val)
if opLower == "for" {
Expand Down Expand Up @@ -191,6 +191,9 @@ func forConsumeExpression(f *forExpander) forStateFn {
case tokNewline:
f.next()
return forFor
case tokComment:
f.next()
return forConsumeExpression
case tokError:
return f.emitConsume(nil)
case tokEOF:
Expand Down Expand Up @@ -235,6 +238,11 @@ func forFor(f *forExpander) forStateFn {
f.forLineLabels = []string{}
}

f.forLineLabelsToWrite = make([]string, len(f.forLineLabels))
for i, label := range f.forLineLabels {
f.forLineLabelsToWrite[i] = fmt.Sprintf("__for_%s_%s", f.forCountLabel, label)
}

f.forCount = val
f.forIndex = 0 // should not be necessary
f.forContent = make([]token, 0)
Expand Down Expand Up @@ -263,7 +271,6 @@ func forInnerLabels(f *forExpander) forStateFn {
if f.nextToken.IsPseudoOp() {
opLower := strings.ToLower(f.nextToken.val)
if opLower == "for" {
fmt.Println("inner:", f.labelBuf, "for")
f.forDepth += 1
return forInnerEmitLabels
} else if opLower == "rof" {
Expand All @@ -277,7 +284,12 @@ func forInnerLabels(f *forExpander) forStateFn {
return forInnerEmitLabels
}
} else if f.nextToken.IsOp() {
// write labels and op into emit buffer then emitcomsume line
if f.forLineLabelsToWrite != nil {
for _, label := range f.forLineLabelsToWrite {
f.tokens <- token{tokText, label}
}
f.forLineLabelsToWrite = nil
}
return forInnerEmitLabels
} else {
f.labelBuf = append(f.labelBuf, f.nextToken.val)
Expand All @@ -300,12 +312,11 @@ func forInnerEmitLabels(f *forExpander) forStateFn {
func forInnerEmitConsumeLine(f *forExpander) forStateFn {
switch f.nextToken.typ {
case tokError:
// TODO
f.tokens <- f.nextToken
return nil
case tokEOF:
return nil
case tokNewline:
// f.tokens <- f.nextToken
f.forContent = append(f.forContent, f.nextToken)
f.next()
return forInnerLine
Expand All @@ -319,21 +330,31 @@ func forInnerEmitConsumeLine(f *forExpander) forStateFn {
func forRof(f *forExpander) forStateFn {
for f.nextToken.typ != tokNewline {
if f.nextToken.typ == tokEOF || f.nextToken.typ == tokError {
f.tokens <- f.nextToken
return nil
}
f.next()
}
f.next()

fmt.Println(f.forContent)

for i := 1; i <= f.forCount; i++ {
for _, tok := range f.forContent {
if tok.typ == tokText {
if tok.val == f.forCountLabel {
f.tokens <- token{tokNumber, fmt.Sprintf("%d", i)}
} else {
f.tokens <- tok
found := false
for _, label := range f.forLineLabels {
forLabel := fmt.Sprintf("__for_%s_%s", f.forCountLabel, label)
if tok.val == label {
f.tokens <- token{tokText, forLabel}
found = true
break
}
}
if !found {
f.tokens <- tok
}
}
} else {
f.tokens <- tok
Expand Down

0 comments on commit 311553a

Please sign in to comment.