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 {
a := float64(orig * orig)
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) {

88
main.go
View File

@ -56,8 +56,8 @@ func generateAST(path string) {
func validateInput(path string) {
generateAST(path)
if len(tree.Loops) > 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 {
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

View File

@ -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

View File

@ -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 {

View File

@ -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
}
if strings.ToUpper(t.val) == "BEG" {
subloop := p.parseLoop()
procedures = append(procedures, subloop...)
} else {
p.unscan()
procedure := p.parseProcedure()
l.Procedures = append(l.Procedures, procedure)
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

View File

@ -6,12 +6,12 @@ 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))
}
}
@ -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,14 +63,12 @@ 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
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 {
@ -106,3 +105,4 @@ func (p *point) update(change []parser.Expression) {
p.x = totalX
p.y = totalY
}

View File

@ -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