parse.go (4532B)
1 package main 2 3 import ( 4 "fmt" 5 "main/subex" 6 "strings" 7 "unicode/utf8" 8 ) 9 10 type parser struct { 11 tokenStream chan Token 12 rewinds []Token 13 labels map[rune]int 14 } 15 func (p *parser) next() Token { 16 var token Token 17 if len(p.rewinds) == 0 { 18 token = <- p.tokenStream 19 } else { 20 token = p.rewinds[len(p.rewinds)-1] 21 p.rewinds = p.rewinds[:len(p.rewinds)-1] 22 } 23 if token.typ == TokenErr { 24 fmt.Println(token) 25 panic("Lexing error") 26 } 27 return token 28 } 29 func (p *parser) rewind(token Token) { 30 p.rewinds = append(p.rewinds, token) 31 } 32 func (p *parser) peek() Token { 33 token := p.next() 34 p.rewind(token) 35 return token 36 } 37 38 func (p *parser) parseSubex() subex.SubexAST { 39 delim := p.next() 40 if delim.typ != TokenSubstituteDelimiter { 41 panic("Missing substitute delimiter") 42 } 43 subexProgramToken := p.next() 44 if subexProgramToken.typ != TokenSubex { 45 panic("Missing subex from substitution") 46 } 47 var subexProgram string 48 if delim.val == "=" || delim.val == "~" || delim.val == "\"" || delim.val == "`" || delim.val == "^" { 49 subexProgram = delim.val + subexProgramToken.val + delim.val 50 } else { 51 subexProgram = subexProgramToken.val 52 } 53 reader := subex.NewStringRuneReader(subexProgram) 54 subexAST := subex.Parse(reader) 55 delim = p.next() 56 if delim.typ != TokenSubstituteDelimiter { 57 panic("Missing end substitute delimiter") 58 } 59 return subexAST 60 } 61 62 func (p *parser) parseBasicCommand(commands []Command, commandChar rune) []Command { 63 switch commandChar { 64 case 'p': 65 return append(commands, PrintValueCommand{}) 66 case 'd': 67 return append(commands, DeleteValueCommand{}) 68 case 'D': 69 return append(commands, DeletePathCommand{}) 70 case 'n': 71 return append(commands, NextCommand{}) 72 case 'N': 73 return append(commands, AppendNextCommand{}) 74 case 's', 'S': 75 ast := p.parseSubex() 76 subex := subex.CompileTransducer(ast) 77 switch commandChar { 78 case 's': 79 return append(commands, SubstituteValueCommand {subex}, JumpCommand {len(commands) + 3}) 80 case 'S': 81 return append(commands, SubstitutePathCommand {subex}, JumpCommand {len(commands) + 3}) 82 default: 83 panic("Unreachable!?!?") 84 } 85 case 'o': 86 return append(commands, NoopCommand{}) 87 case 'x': 88 return append(commands, SwapXRegCommand{}) 89 case 'X': 90 return append(commands, AppendXRegCommand{}) 91 case 'y': 92 return append(commands, SwapYRegCommand{}) 93 case 'Y': 94 return append(commands, AppendYRegCommand{}) 95 case 'z': 96 return append(commands, SwapZRegCommand{}) 97 case 'Z': 98 return append(commands, AppendZRegCommand{}) 99 case 'k': 100 return append(commands, SwapPathCommand{}) 101 case 'K': 102 return append(commands, AppendPathCommand{}) 103 case ':': 104 labelToken := p.next() 105 if labelToken.typ != TokenLabel { 106 panic("Missing branch label") 107 } 108 label, _ := utf8.DecodeRuneInString(labelToken.val) 109 p.labels[label] = len(commands) 110 return commands 111 case 'b': 112 labelToken := p.next() 113 if labelToken.typ != TokenLabel { 114 panic("Missing branch label") 115 } 116 label, _ := utf8.DecodeRuneInString(labelToken.val) 117 return append(commands, BranchPlaceholderCommand {label}) 118 default: 119 panic("Invalid command") 120 } 121 } 122 123 func (p *parser) parseCommand(commands []Command) []Command { 124 token := p.next() 125 switch token.typ { 126 case TokenLBrace: 127 jumpToBlockCommand := &JumpCommand{0} 128 commands = append(commands, JumpCommand {len(commands) + 2}, jumpToBlockCommand) 129 commands = p.parseCommands(commands) 130 if p.next().typ != TokenRBrace { 131 panic("Missing matching }") 132 } 133 jumpToBlockCommand.destination = len(commands) 134 return commands 135 case TokenCommand: 136 commandChar, _, err := strings.NewReader(token.val).ReadRune() 137 if err != nil { 138 panic("Error reading a command character!?") 139 } 140 return p.parseBasicCommand(commands, commandChar) 141 default: 142 panic("Invalid token, expected command") 143 } 144 } 145 146 func (p *parser) parseCommands(commands []Command) []Command { 147 for { 148 nextToken := p.peek() 149 if nextToken.typ == TokenEOF || nextToken.typ == TokenRBrace { 150 return commands 151 } 152 commands = p.parseCommand(commands) 153 } 154 } 155 156 func Parse(tokens chan Token) []Command { 157 p := parser { 158 tokenStream: tokens, 159 rewinds: nil, 160 labels: make(map[rune]int), 161 } 162 program := p.parseCommands(nil) 163 for i, command := range program { 164 switch branch := command.(type) { 165 case BranchPlaceholderCommand: 166 destination, exists := p.labels[branch.label] 167 if !exists { 168 panic("Tried to branch to a label that doesn't exist") 169 } 170 program[i] = JumpCommand {destination} 171 } 172 } 173 return program 174 }