diff options
Diffstat (limited to 'main/parse.go')
| -rw-r--r-- | main/parse.go | 243 | 
1 files changed, 195 insertions, 48 deletions
| diff --git a/main/parse.go b/main/parse.go index 36bd3ee..d0a0255 100644 --- a/main/parse.go +++ b/main/parse.go @@ -10,7 +10,6 @@ import (  type parser struct {  	tokenStream chan Token  	rewinds []Token -	labels map[rune]int  }  func (p *parser) next() Token {  	var token Token @@ -53,146 +52,288 @@ func (p *parser) parseSubex() subex.SubexAST {  	return subexAST  } -func (p *parser) parseBasicCommand(commands []Command, commandChar rune) []Command { +func (p *parser) parseBasicCommand(commandChar rune) []Command {  	switch commandChar {  		case 'p': -			return append(commands, PrintValueCommand{}) +			return []Command {PrintValueCommand{}}  		case 'd': -			return append(commands, DeleteValueCommand{}) +			return []Command {DeleteValueCommand{}}  		case 'n':  			delim := p.peek()  			if delim.typ != TokenSubstituteDelimiter { -				return append(commands, NextCommand{}) +				return []Command {NextCommand{}}  			}  			ast := p.parseSubex()  			subex := subex.CompileTransducer(ast) -			return append(commands, SubstituteNextCommand {subex}, JumpCommand {len(commands) + 3}) +			elseBranch := p.parseCommand() +			return append( +				[]Command { +					SubstituteNextCommand { +						subex: subex, +						elseJump: len(elseBranch) + 1, +					}, +				}, +				elseBranch..., +			)  		case 'N':  			delim := p.peek()  			if delim.typ != TokenSubstituteDelimiter { -				return append(commands, AppendNextCommand{}) +				return []Command {AppendNextCommand{}}  			}  			ast := p.parseSubex()  			subex := subex.CompileTransducer(ast) -			return append(commands, SubstituteAppendNextCommand {subex}, JumpCommand {len(commands) + 3}) +			elseBranch := p.parseCommand() +			return append( +				[]Command { +					SubstituteAppendNextCommand { +						subex: subex, +						elseJump: len(elseBranch) + 1, +					}, +				}, +				elseBranch..., +			)  		case 'm': -			return append(commands, MergeCommand{}) +			return []Command {MergeCommand {}}  		case 'M':  			ast := p.parseSubex()  			subex := subex.CompileTransducer(ast) -			return append(commands, FullMergeCommand {subex}, JumpCommand {len(commands) + 3}) +			elseBranch := p.parseCommand() +			return append( +				[]Command { +					FullMergeCommand { +						subex: subex, +						elseJump: len(elseBranch) + 1, +					}, +				}, +				elseBranch..., +			)  		case 's':  			ast := p.parseSubex()  			subex := subex.CompileTransducer(ast) -			return append(commands, SubstituteValueCommand {subex}, JumpCommand {len(commands) + 3}) +			elseBranch := p.parseCommand() +			return append( +				[]Command { +					SubstituteValueCommand { +						subex: subex, +						elseJump: len(elseBranch) + 1, +					}, +				}, +				elseBranch..., +			) +		case 'r': +			ast := p.parseSubex() +			subex := subex.CompileTransducer(ast) +			return []Command { +				SubstituteValueCommand { +					subex: subex, +					elseJump: 2, +				}, +				RelativeJumpCommand { +					destination: -1, +				}, +			}  		case 'o': -			return append(commands, NoopCommand{}) +			return []Command {NoopCommand {}}  		case 'x':  			delim := p.peek()  			if delim.typ != TokenSubstituteDelimiter { -				return append(commands, SwapXRegCommand{}) +				return []Command {SwapXRegCommand {}}  			}  			ast := p.parseSubex()  			subex := subex.CompileTransducer(ast) -			return append(commands, SubstituteToXRegCommand {subex}, JumpCommand {len(commands) + 3}) +			elseBranch := p.parseCommand() +			return append( +				[]Command { +					SubstituteToXRegCommand { +						subex: subex, +						elseJump: len(elseBranch) + 1, +					}, +				}, +				elseBranch..., +			)  		case 'X':  			delim := p.peek()  			if delim.typ != TokenSubstituteDelimiter { -				return append(commands, AppendXRegCommand{}) +				return []Command {AppendXRegCommand {}}  			}  			ast := p.parseSubex()  			subex := subex.CompileTransducer(ast) -			return append(commands, SubstituteAppendXRegCommand {subex}, JumpCommand {len(commands) + 3}) +			elseBranch := p.parseCommand() +			return append( +				[]Command { +					SubstituteAppendXRegCommand { +						subex: subex, +						elseJump: len(elseBranch) + 1, +					}, +				}, +				elseBranch..., +			)  		case 'y':  			delim := p.peek()  			if delim.typ != TokenSubstituteDelimiter { -				return append(commands, SwapYRegCommand{}) +				return []Command {SwapYRegCommand {}}  			}  			ast := p.parseSubex()  			subex := subex.CompileTransducer(ast) -			return append(commands, SubstituteToYRegCommand {subex}, JumpCommand {len(commands) + 3}) +			elseBranch := p.parseCommand() +			return append( +				[]Command { +					SubstituteToYRegCommand { +						subex: subex, +						elseJump: len(elseBranch) + 1, +					}, +				}, +				elseBranch..., +			)  		case 'Y':  			delim := p.peek()  			if delim.typ != TokenSubstituteDelimiter { -				return append(commands, AppendYRegCommand{}) +				return []Command {AppendYRegCommand {}}  			}  			ast := p.parseSubex()  			subex := subex.CompileTransducer(ast) -			return append(commands, SubstituteAppendYRegCommand {subex}, JumpCommand {len(commands) + 3}) +			elseBranch := p.parseCommand() +			return append( +				[]Command { +					SubstituteAppendYRegCommand { +						subex: subex, +						elseJump: len(elseBranch) + 1, +					}, +				}, +				elseBranch..., +			)  		case 'z':  			delim := p.peek()  			if delim.typ != TokenSubstituteDelimiter { -				return append(commands, SwapZRegCommand{}) +				return []Command {SwapZRegCommand {}}  			}  			ast := p.parseSubex()  			subex := subex.CompileTransducer(ast) -			return append(commands, SubstituteToZRegCommand {subex}, JumpCommand {len(commands) + 3}) +			elseBranch := p.parseCommand() +			return append( +				[]Command { +					SubstituteToZRegCommand { +						subex: subex, +						elseJump: len(elseBranch) + 1, +					}, +				}, +				elseBranch..., +			)  		case 'Z':  			delim := p.peek()  			if delim.typ != TokenSubstituteDelimiter { -				return append(commands, AppendZRegCommand{}) +				return []Command {AppendZRegCommand {}}  			}  			ast := p.parseSubex()  			subex := subex.CompileTransducer(ast) -			return append(commands, SubstituteAppendZRegCommand {subex}, JumpCommand {len(commands) + 3}) +			elseBranch := p.parseCommand() +			return append( +				[]Command { +					SubstituteAppendZRegCommand { +						subex: subex, +						elseJump: len(elseBranch) + 1, +					}, +				}, +				elseBranch..., +			)  		case 'a': -			return append(commands, IsStartCommand{}, JumpCommand {len(commands) + 3}) +			elseBranch := p.parseCommand() +			return append( +				[]Command { +					IsStartCommand { +						elseJump: len(elseBranch) + 1, +					}, +				}, +				elseBranch..., +			)  		case 'A': -			return append(commands, IsPrevStartCommand{}, JumpCommand {len(commands) + 3}) +			elseBranch := p.parseCommand() +			return append( +				[]Command { +					IsPrevStartCommand { +						elseJump: len(elseBranch) + 1, +					}, +				}, +				elseBranch..., +			)  		case 'e': -			return append(commands, IsEndCommand{}, JumpCommand {len(commands) + 3}) +			elseBranch := p.parseCommand() +			return append( +				[]Command { +					IsEndCommand { +						elseJump: len(elseBranch) + 1, +					}, +				}, +				elseBranch..., +			)  		case 'E': -			return append(commands, IsNextEndCommand{}, JumpCommand {len(commands) + 3}) +			elseBranch := p.parseCommand() +			return append( +				[]Command { +					IsNextEndCommand { +						elseJump: len(elseBranch) + 1, +					}, +				}, +				elseBranch..., +			)  		case ':':  			labelToken := p.next()  			if labelToken.typ != TokenLabel {  				panic("Missing branch label")  			}  			label, _ := utf8.DecodeRuneInString(labelToken.val) -			p.labels[label] = len(commands) -			return commands +			return []Command { +				LabelCommand { +					label: label, +				}, +			}  		case 'b':  			labelToken := p.next()  			if labelToken.typ != TokenLabel {  				panic("Missing branch label")  			}  			label, _ := utf8.DecodeRuneInString(labelToken.val) -			return append(commands, BranchPlaceholderCommand {label}) +			return []Command { +				BranchPlaceholderCommand { +					label: label, +				}, +			}  		default:  			panic("Invalid command")  	}  } -func (p *parser) parseCommand(commands []Command) []Command { +func (p *parser) parseCommand() []Command {  	token := p.next()  	switch token.typ {  		case TokenLBrace: -			jumpToBlockCommand := &JumpCommand{0} -			commands = append(commands, JumpCommand {len(commands) + 2}, jumpToBlockCommand) -			commands = p.parseCommands(commands) +			children := p.parseCommandSequence()  			if p.next().typ != TokenRBrace {  				panic("Missing matching }")  			} -			jumpToBlockCommand.destination = len(commands) -			return commands +			return children +		case TokenRBrace, TokenEOF: +			p.rewind(token) +			return nil  		case TokenCommand:  			commandChar, _, err := strings.NewReader(token.val).ReadRune()  			if err != nil {  				panic("Error reading a command character!?")  			} -			return p.parseBasicCommand(commands, commandChar) +			return p.parseBasicCommand(commandChar)  		default:  			panic("Invalid token, expected command")  	}  } -func (p *parser) parseCommands(commands []Command) []Command { +func (p *parser) parseCommandSequence() []Command { +	var commands []Command  	for {  		nextToken := p.peek()  		if nextToken.typ == TokenEOF || nextToken.typ == TokenRBrace {  			return commands  		} -		commands = p.parseCommand(commands) +		commands = append(commands, p.parseCommand()...)  	}  } @@ -200,17 +341,23 @@ func Parse(tokens chan Token) []Command {  	p := parser {  		tokenStream: tokens,  		rewinds: nil, -		labels: make(map[rune]int),  	} -	program := p.parseCommands(nil) +	program := p.parseCommandSequence() +	labels := make(map[rune]int) +	for i, command := range program { +		switch label := command.(type) { +		case LabelCommand: +			labels[label.label] = i +		} +	}  	for i, command := range program {  		switch branch := command.(type) { -			case BranchPlaceholderCommand: -				destination, exists := p.labels[branch.label] -				if !exists { -					panic("Tried to branch to a label that doesn't exist") -				} -				program[i] = JumpCommand {destination} +		case BranchPlaceholderCommand: +			destination, exists := labels[branch.label] +			if !exists { +				panic("Tried to branch to a label that doesn't exist") +			} +			program[i] = JumpCommand {destination}  		}  	}  	return program | 
