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 {
|
||||
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) {
|
||||
|
|
90
main.go
90
main.go
|
@ -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 {
|
||||
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
|
||||
|
|
27
newtest.frs
27
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
|
||||
|
||||
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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
|
||||
|
|
28
receivers.go
28
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
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue