Adds sublooping, better tree structure, extra register, more variables
This commit is contained in:
parent
7d70006d2d
commit
9a16ed2b66
|
@ -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
90
main.go
|
@ -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
|
||||||
|
|
27
newtest.frs
27
newtest.frs
|
@ -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
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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
|
||||||
|
|
28
receivers.go
28
receivers.go
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue