Adds sublooping, better tree structure, extra register, more variables

This commit is contained in:
Brian Evans 2019-07-19 14:30:20 -07:00
parent 7d70006d2d
commit 9a16ed2b66
8 changed files with 135 additions and 70 deletions

BIN
.DS_Store vendored Normal file

Binary file not shown.

View File

@ -15,7 +15,7 @@ import (
func avgColor(orig, upd int) int { func avgColor(orig, upd int) int {
a := float64(orig * orig) a := float64(orig * orig)
b := float64(upd * upd) b := float64(upd * upd)
return int(math.Sqrt(float64((a + b)/2))) return int(math.Sqrt((a + b)/2))
} }
func loadImage(path string) (*image.RGBA, string) { func loadImage(path string) (*image.RGBA, string) {

90
main.go
View File

@ -56,8 +56,8 @@ func generateAST(path string) {
func validateInput(path string) { func validateInput(path string) {
generateAST(path) generateAST(path)
if len(tree.Loops) > 0 { if len(tree.Procedures) > 0 {
fmt.Printf("File has %d procedures\n", len(tree.Loops)) fmt.Printf("File has %d procedures\n", len(tree.Procedures))
fmt.Println("File is valid") fmt.Println("File is valid")
} else { } else {
fmt.Println("Invalid or empty input file") fmt.Println("Invalid or empty input file")
@ -67,12 +67,11 @@ func validateInput(path string) {
} }
func filterImage(path, fname string) { func filterImage(path, fname string) {
fmt.Print("Loading image \r") fmt.Print("Loading image... ")
im, imFormat = loadImage(path) im, imFormat = loadImage(path)
imSize := im.Bounds().Size() imSize := im.Bounds().Size()
variables["WID"] = imSize.X variables["RG1"] = 0
variables["HIG"] = imSize.Y variables["RG2"] = 0
variables["REG"] = 0
fil.location.maxX = imSize.X fil.location.maxX = imSize.X
fil.location.maxY = imSize.Y fil.location.maxY = imSize.Y
@ -85,42 +84,70 @@ func filterImage(path, fname string) {
filter{3,0,0}, filter{3,0,0},
} }
fmt.Print("Filtering image \r") fmt.Print("Filtering image... ")
for _, loop := range tree.Loops { for _, proc := range tree.Procedures {
for ;loop.Counter > 0; loop.Counter-- { procedure(proc)
for _, proc := range loop.Procedures {
procedure(proc)
}
}
} }
fmt.Print("Saving image \n") fmt.Print("Saving image... \n")
saveImage(path, fname, imFormat, im) saveImage(path, fname, imFormat, im)
fmt.Print("Image saved. Done. \n") fmt.Print("Image saved. Done. \n")
} }
func updateRegister(exp parser.Expression) { func updateRegister(reg string, exp parser.Expression) {
var err error
opand := exp.Opperand opand := exp.Opperand
if exp.Variable != "" { 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 { switch exp.Opperator {
case '+': case '+':
variables["REG"] += opand variables[reg] += opand
case '-': case '-':
variables["REG"] -= opand variables[reg] -= opand
case '*': case '*':
variables["REG"] *= opand variables[reg] *= opand
case '/': case '/':
if opand == 0 { if opand == 0 {
variables["REG"] = 1 variables[reg] = 1
} else { } else {
variables["REG"] /= opand variables[reg] /= opand
} }
case '=': 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) { func procedure(p parser.Procedure) {
switch p.Kind { switch p.Kind {
case "LOC": case "LOC":
@ -131,9 +158,9 @@ func procedure(p parser.Procedure) {
if len(p.Expressions) >= 1 { if len(p.Expressions) >= 1 {
fil.mode.update(p.Expressions[0]) fil.mode.update(p.Expressions[0])
} }
case "REG": case "RG1", "RG2":
if len(p.Expressions) >= 1 { if len(p.Expressions) >= 1 {
updateRegister(p.Expressions[0]) updateRegister(p.Kind, p.Expressions[0])
} }
case "APY": case "APY":
applyToImage(p.Expressions) applyToImage(p.Expressions)
@ -164,6 +191,7 @@ func procedure(p parser.Procedure) {
} }
func applyToImage(exps []parser.Expression) { func applyToImage(exps []parser.Expression) {
var err error
if len(exps) == 0 { if len(exps) == 0 {
im.SetRGBA( im.SetRGBA(
fil.location.x, fil.location.x,
@ -178,14 +206,20 @@ func applyToImage(exps []parser.Expression) {
endX := exps[0].Opperand endX := exps[0].Opperand
endY := exps[1].Opperand endY := exps[1].Opperand
if exps[0].Variable != "" { 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 != "" { 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) endX = getBoxBound(fil.location.x, endX, fil.location.maxX, exps[0].Opperator)
endY = getBoxBound(fil.location.y, endY, variables["HIG"], exps[1].Opperator) endY = getBoxBound(fil.location.y, endY, fil.location.maxY, exps[1].Opperator)
var r,g,b,a int var r,g,b,a int
var col color.RGBA var col color.RGBA

View File

@ -1,7 +1,26 @@
# Set mode to 1 (average)
MOD 1 MOD 1
BEG 25 # Set register 1 to handle our Y axis
COL 255:0:0:200 RG1 HIG
APY +10:+HIG RG1 /10
LOC +20:+0 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 END

View File

@ -125,7 +125,7 @@ func (s *scanner) scanText() Token {
if ch := s.read(); ch == eof { if ch := s.read(); ch == eof {
s.unread() s.unread()
break break
} else if !isLetter(ch) { } else if !isLetter(ch) && !isNumber(ch) {
s.unread() s.unread()
break break
} else { } else {

View File

@ -33,6 +33,7 @@ type Loop struct {
} }
type AST struct { type AST struct {
Procedures []Procedure
Loops []Loop Loops []Loop
} }
@ -124,23 +125,22 @@ func (p *Parser) parseProcedure() Procedure {
default: default:
panic(fmt.Sprintf("Parse error: Invalid token %q on \033[1mline %d\033[0m", t.val, p.row)) panic(fmt.Sprintf("Parse error: Invalid token %q on \033[1mline %d\033[0m", t.val, p.row))
} }
// isVariable(t.val)
return out return out
} }
func (p *Parser) parseLoop() Loop { func (p *Parser) parseLoop() []Procedure {
t := p.scan() t := p.scan()
l := Loop{} var lcount int
if t.kind == Number { if t.kind == Number {
l.Counter, _ = strconv.Atoi(t.val) lcount, _ = strconv.Atoi(t.val)
} else { } else {
panic(fmt.Sprintf("Parse error: Loop declared, but not followed by a number on \033[1mline %d\033[0m", p.row)) 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: L:
for { for {
@ -155,19 +155,32 @@ func (p *Parser) parseLoop() Loop {
case Separator: case Separator:
panic(fmt.Sprintf("Parse error: Illegal field separator ':' on \033[1mline %d\033[0m", p.row)) panic(fmt.Sprintf("Parse error: Illegal field separator ':' on \033[1mline %d\033[0m", p.row))
case End: 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: case Number:
panic(fmt.Sprintf("Parse error: Number %q outside of procedure call on \033[1mline %d\033[0m", t.val, p.row)) panic(fmt.Sprintf("Parse error: Number %q outside of procedure call on \033[1mline %d\033[0m", t.val, p.row))
case Text: case Text:
if strings.ToUpper(t.val) == "END" { if strings.ToUpper(t.val) == "END" {
break L break L
} }
p.unscan() if strings.ToUpper(t.val) == "BEG" {
procedure := p.parseProcedure() subloop := p.parseLoop()
l.Procedures = append(l.Procedures, procedure) 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: case Number:
panic(fmt.Sprintf("Parse error: Number %q outside of procedure call on \033[1mline %d\033[0m", t.val, p.row)) panic(fmt.Sprintf("Parse error: Number %q outside of procedure call on \033[1mline %d\033[0m", t.val, p.row))
case Text: case Text:
var loop Loop
if strings.ToUpper(t.val) == "BEG" { if strings.ToUpper(t.val) == "BEG" {
loop = p.parseLoop() loopVal := p.parseLoop()
tree.Procedures = append(tree.Procedures, loopVal...)
} else { } else {
p.unscan() p.unscan()
loop = Loop{1, make([]Procedure, 0, 1)}
procedure := p.parseProcedure() 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 { func isValidProcedure(p string) bool {
switch p { switch p {
case "REG", "LOC", "BEG", "END", "RED", case "RG1", "RG2", "LOC", "BEG", "END", "RED",
"GRN", "BLU", "APH", "COL", "APY", "MOD": "GRN", "BLU", "APH", "COL", "APY", "MOD", "LOX", "LOY":
return true return true
} }
return false return false
@ -220,7 +231,8 @@ func isValidProcedure(p string) bool {
func isVariable(v string) bool { func isVariable(v string) bool {
v = strings.ToUpper(v) v = strings.ToUpper(v)
switch v { switch v {
case "WID", "HIG", "REG": case "WID", "HIG", "RG1", "RG2", "LOX", "LOY",
"RED", "BLU", "GRN", "APH":
return true return true
} }
return false return false

View File

@ -6,13 +6,13 @@ import (
) )
func (f *filter) update(change parser.Expression) { func (f *filter) update(change parser.Expression) {
var err error
opand := change.Opperand opand := change.Opperand
if change.Variable != "" { if change.Variable != "" {
if val, ok := variables[change.Variable]; ok { opand, err = retrieveVariableValue(change.Variable)
opand = val if err != nil {
} else { panic(fmt.Sprintf("Runtime error: Unknown variable %q encountered", change.Variable))
panic(fmt.Sprintf("Runtime error: Encountered unknown variable %q", val)) }
}
} }
switch change.Opperator { switch change.Opperator {
@ -46,6 +46,7 @@ func (f *filter) update(change parser.Expression) {
} }
func (p *point) update(change []parser.Expression) { func (p *point) update(change []parser.Expression) {
var err error
var totalX, totalY, val, opand, max int var totalX, totalY, val, opand, max int
var target *int var target *int
@ -62,15 +63,13 @@ func (p *point) update(change []parser.Expression) {
break break
} }
if e.Variable != "" { opand = e.Opperand
if val, ok := variables[e.Variable]; ok { if e.Variable != "" {
opand = val opand, err = retrieveVariableValue(e.Variable)
} else { if err != nil {
panic(fmt.Sprintf("Runtime error: Encountered unknown variable %q", val)) panic(fmt.Sprintf("Runtime error: Unknown variable %q encountered", e.Variable))
} }
} else { }
opand = e.Opperand
}
switch e.Opperator { switch e.Opperator {
case '+': case '+':
@ -106,3 +105,4 @@ func (p *point) update(change []parser.Expression) {
p.x = totalX p.x = totalX
p.y = totalY p.y = totalY
} }

View File

@ -4,9 +4,9 @@ APH 255
RED 100 RED 100
BLU 100 BLU 100
GRN 100 GRN 100
REG WID RG1 WID
REG /20 RG1 /20
REG /4 RG1 /4
LOC +1:+1 LOC +1:+1
BEG 100 BEG 100
@ -16,7 +16,7 @@ BEG 100
LOC +0:+4 LOC +0:+4
APY +WID:+0 APY +WID:+0
LOC +0:-4 LOC +0:-4
LOC +REG:*24 LOC +RG1:*24
END END