From 9a16ed2b6629c41f1d838969a48d45da92625113 Mon Sep 17 00:00:00 2001 From: Brian Evans Date: Fri, 19 Jul 2019 14:30:20 -0700 Subject: [PATCH] Adds sublooping, better tree structure, extra register, more variables --- .DS_Store | Bin 0 -> 6148 bytes imageHandler.go | 2 +- main.go | 90 ++++++++++++++++++++++++++++++++--------------- newtest.frs | 27 +++++++++++--- parser/lexer.go | 2 +- parser/parser.go | 48 +++++++++++++++---------- receivers.go | 28 +++++++-------- test.frs | 8 ++--- 8 files changed, 135 insertions(+), 70 deletions(-) create mode 100644 .DS_Store diff --git a/.DS_Store b/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..5008ddfcf53c02e82d7eee2e57c38e5672ef89f6 GIT binary patch literal 6148 zcmeH~Jr2S!425mzP>H1@V-^m;4Wg<&0T*E43hX&L&p$$qDprKhvt+--jT7}7np#A3 zem<@ulZcFPQ@L2!n>{z**++&mCkOWA81W14cNZlEfg7;MkzE(HCqgga^y>{tEnwC%0;vJ&^%eQ zLs35+`xjp>T0 0 { - fmt.Printf("File has %d procedures\n", len(tree.Loops)) + if len(tree.Procedures) > 0 { + fmt.Printf("File has %d procedures\n", len(tree.Procedures)) fmt.Println("File is valid") } else { fmt.Println("Invalid or empty input file") @@ -67,12 +67,11 @@ func validateInput(path string) { } func filterImage(path, fname string) { - fmt.Print("Loading image \r") + fmt.Print("Loading image... ") im, imFormat = loadImage(path) imSize := im.Bounds().Size() - variables["WID"] = imSize.X - variables["HIG"] = imSize.Y - variables["REG"] = 0 + variables["RG1"] = 0 + variables["RG2"] = 0 fil.location.maxX = imSize.X fil.location.maxY = imSize.Y @@ -85,42 +84,70 @@ func filterImage(path, fname string) { filter{3,0,0}, } - fmt.Print("Filtering image \r") - for _, loop := range tree.Loops { - for ;loop.Counter > 0; loop.Counter-- { - for _, proc := range loop.Procedures { - procedure(proc) - } - } + fmt.Print("Filtering image... ") + for _, proc := range tree.Procedures { + procedure(proc) } - fmt.Print("Saving image \n") + fmt.Print("Saving image... \n") saveImage(path, fname, imFormat, im) fmt.Print("Image saved. Done. \n") } -func updateRegister(exp parser.Expression) { +func updateRegister(reg string, exp parser.Expression) { + var err error opand := exp.Opperand if exp.Variable != "" { - opand = variables[exp.Variable] + opand, err = retrieveVariableValue(exp.Variable) + if err != nil { + panic(fmt.Sprintf("Runtime error: Unknown variable %q encountered", exp.Variable)) + } } switch exp.Opperator { case '+': - variables["REG"] += opand + variables[reg] += opand case '-': - variables["REG"] -= opand + variables[reg] -= opand case '*': - variables["REG"] *= opand + variables[reg] *= opand case '/': if opand == 0 { - variables["REG"] = 1 + variables[reg] = 1 } else { - variables["REG"] /= opand + variables[reg] /= opand } case '=': - variables["REG"] = opand + variables[reg] = opand } } +func retrieveVariableValue(ident string) (int, error) { + var val int + switch ident { + case "RG1", "RG2": + val = variables[ident] + case "WID": + val = fil.location.maxX + case "HIG": + val = fil.location.maxY + case "RED": + val = fil.red.val + case "GRN": + val = fil.green.val + case "BLU": + val = fil.blue.val + case "APH": + val = fil.alpha.val + case "LOX": + val = fil.location.x + case "LOY": + val = fil.location.y + default: + return 0, fmt.Errorf("Unknown variable %q sent to retrieveVariableValue", ident) + } + + return val, nil +} + func procedure(p parser.Procedure) { switch p.Kind { case "LOC": @@ -131,9 +158,9 @@ func procedure(p parser.Procedure) { if len(p.Expressions) >= 1 { fil.mode.update(p.Expressions[0]) } - case "REG": + case "RG1", "RG2": if len(p.Expressions) >= 1 { - updateRegister(p.Expressions[0]) + updateRegister(p.Kind, p.Expressions[0]) } case "APY": applyToImage(p.Expressions) @@ -164,6 +191,7 @@ func procedure(p parser.Procedure) { } func applyToImage(exps []parser.Expression) { + var err error if len(exps) == 0 { im.SetRGBA( fil.location.x, @@ -178,14 +206,20 @@ func applyToImage(exps []parser.Expression) { endX := exps[0].Opperand endY := exps[1].Opperand if exps[0].Variable != "" { - endX = variables[exps[0].Variable] + endX, err = retrieveVariableValue(exps[0].Variable) + if err != nil { + panic(fmt.Sprintf("Runtime error: Unknown variable %q encountered", exps[0].Variable)) + } } if exps[1].Variable != "" { - endY = variables[exps[1].Variable] + endY, err = retrieveVariableValue(exps[1].Variable) + if err != nil { + panic(fmt.Sprintf("Runtime error: Unknown variable %q encountered", exps[1].Variable)) + } } - endX = getBoxBound(fil.location.x, endX, variables["WID"], exps[0].Opperator) - endY = getBoxBound(fil.location.y, endY, variables["HIG"], exps[1].Opperator) + endX = getBoxBound(fil.location.x, endX, fil.location.maxX, exps[0].Opperator) + endY = getBoxBound(fil.location.y, endY, fil.location.maxY, exps[1].Opperator) var r,g,b,a int var col color.RGBA diff --git a/newtest.frs b/newtest.frs index 731efeb..04366af 100644 --- a/newtest.frs +++ b/newtest.frs @@ -1,7 +1,26 @@ +# Set mode to 1 (average) MOD 1 -BEG 25 - COL 255:0:0:200 - APY +10:+HIG - LOC +20:+0 +# Set register 1 to handle our Y axis +RG1 HIG +RG1 /10 +RG1 /2 + +# Set register 2 to handle our x axis +RG2 WID +RG2 /10 +RG2 /2 + +# Nest loop over y then x axis +BEG 10 + BEG 10 + COL +80:*6:-200:-4 + APY +RG2:+RG1 + LOC +RG2:+0 + LOC +RG2:+0 + END + LOC +RG2:+RG1 + LOC +RG2:+RG1 END + + diff --git a/parser/lexer.go b/parser/lexer.go index 154c5b9..7cefc8b 100644 --- a/parser/lexer.go +++ b/parser/lexer.go @@ -125,7 +125,7 @@ func (s *scanner) scanText() Token { if ch := s.read(); ch == eof { s.unread() break - } else if !isLetter(ch) { + } else if !isLetter(ch) && !isNumber(ch) { s.unread() break } else { diff --git a/parser/parser.go b/parser/parser.go index bc1e80a..a3667d4 100644 --- a/parser/parser.go +++ b/parser/parser.go @@ -33,6 +33,7 @@ type Loop struct { } type AST struct { + Procedures []Procedure Loops []Loop } @@ -124,23 +125,22 @@ func (p *Parser) parseProcedure() Procedure { default: panic(fmt.Sprintf("Parse error: Invalid token %q on \033[1mline %d\033[0m", t.val, p.row)) } - // isVariable(t.val) return out } -func (p *Parser) parseLoop() Loop { +func (p *Parser) parseLoop() []Procedure { t := p.scan() - l := Loop{} + var lcount int if t.kind == Number { - l.Counter, _ = strconv.Atoi(t.val) + lcount, _ = strconv.Atoi(t.val) } else { panic(fmt.Sprintf("Parse error: Loop declared, but not followed by a number on \033[1mline %d\033[0m", p.row)) } - l.Procedures = make([]Procedure,0, 5) + procedures := make([]Procedure,0, lcount * 2) L: for { @@ -155,19 +155,32 @@ func (p *Parser) parseLoop() Loop { case Separator: panic(fmt.Sprintf("Parse error: Illegal field separator ':' on \033[1mline %d\033[0m", p.row)) case End: - break L + panic(fmt.Sprintf("Parse error: Encountered EOF before END of loop on \033[1mline %d\033[0m", p.row)) case Number: panic(fmt.Sprintf("Parse error: Number %q outside of procedure call on \033[1mline %d\033[0m", t.val, p.row)) case Text: if strings.ToUpper(t.val) == "END" { break L } - p.unscan() - procedure := p.parseProcedure() - l.Procedures = append(l.Procedures, procedure) + if strings.ToUpper(t.val) == "BEG" { + subloop := p.parseLoop() + procedures = append(procedures, subloop...) + + } else { + p.unscan() + procedure := p.parseProcedure() + procedures = append(procedures, procedure) + } } } - return l + + fullLoop := make([]Procedure, 0, len(procedures) * lcount) + + for i := lcount;i > 0; i-- { + fullLoop = append(fullLoop, procedures...) + } + + return fullLoop } @@ -192,16 +205,14 @@ func (p *Parser) Parse() AST { case Number: panic(fmt.Sprintf("Parse error: Number %q outside of procedure call on \033[1mline %d\033[0m", t.val, p.row)) case Text: - var loop Loop if strings.ToUpper(t.val) == "BEG" { - loop = p.parseLoop() + loopVal := p.parseLoop() + tree.Procedures = append(tree.Procedures, loopVal...) } else { p.unscan() - loop = Loop{1, make([]Procedure, 0, 1)} procedure := p.parseProcedure() - loop.Procedures = append(loop.Procedures, procedure) + tree.Procedures = append(tree.Procedures, procedure) } - tree.Loops = append(tree.Loops, loop) } } @@ -210,8 +221,8 @@ func (p *Parser) Parse() AST { func isValidProcedure(p string) bool { switch p { - case "REG", "LOC", "BEG", "END", "RED", - "GRN", "BLU", "APH", "COL", "APY", "MOD": + case "RG1", "RG2", "LOC", "BEG", "END", "RED", + "GRN", "BLU", "APH", "COL", "APY", "MOD", "LOX", "LOY": return true } return false @@ -220,7 +231,8 @@ func isValidProcedure(p string) bool { func isVariable(v string) bool { v = strings.ToUpper(v) switch v { - case "WID", "HIG", "REG": + case "WID", "HIG", "RG1", "RG2", "LOX", "LOY", + "RED", "BLU", "GRN", "APH": return true } return false diff --git a/receivers.go b/receivers.go index 78c6e89..589e811 100644 --- a/receivers.go +++ b/receivers.go @@ -6,13 +6,13 @@ import ( ) func (f *filter) update(change parser.Expression) { + var err error opand := change.Opperand if change.Variable != "" { - if val, ok := variables[change.Variable]; ok { - opand = val - } else { - panic(fmt.Sprintf("Runtime error: Encountered unknown variable %q", val)) - } + opand, err = retrieveVariableValue(change.Variable) + if err != nil { + panic(fmt.Sprintf("Runtime error: Unknown variable %q encountered", change.Variable)) + } } switch change.Opperator { @@ -46,6 +46,7 @@ func (f *filter) update(change parser.Expression) { } func (p *point) update(change []parser.Expression) { + var err error var totalX, totalY, val, opand, max int var target *int @@ -62,15 +63,13 @@ func (p *point) update(change []parser.Expression) { break } - if e.Variable != "" { - if val, ok := variables[e.Variable]; ok { - opand = val - } else { - panic(fmt.Sprintf("Runtime error: Encountered unknown variable %q", val)) - } - } else { - opand = e.Opperand - } + opand = e.Opperand + if e.Variable != "" { + opand, err = retrieveVariableValue(e.Variable) + if err != nil { + panic(fmt.Sprintf("Runtime error: Unknown variable %q encountered", e.Variable)) + } + } switch e.Opperator { case '+': @@ -106,3 +105,4 @@ func (p *point) update(change []parser.Expression) { p.x = totalX p.y = totalY } + diff --git a/test.frs b/test.frs index a88e237..8e0c8e5 100644 --- a/test.frs +++ b/test.frs @@ -4,9 +4,9 @@ APH 255 RED 100 BLU 100 GRN 100 -REG WID -REG /20 -REG /4 +RG1 WID +RG1 /20 +RG1 /4 LOC +1:+1 BEG 100 @@ -16,7 +16,7 @@ BEG 100 LOC +0:+4 APY +WID:+0 LOC +0:-4 - LOC +REG:*24 + LOC +RG1:*24 END