diff --git a/.gitignore b/.gitignore index 9a3a8d8..55edffc 100644 --- a/.gitignore +++ b/.gitignore @@ -12,3 +12,5 @@ # Output of the go coverage tool, specifically when used with LiteIDE *.out +# Binary from `go build` +filtress diff --git a/filtress_notes.txt b/filtress_notes.txt index 267f319..48df3ec 100644 --- a/filtress_notes.txt +++ b/filtress_notes.txt @@ -77,13 +77,6 @@ MOD [op]int . . . -Set fade time: -# If set below zero, becomes zero - -FAD [op]int - -. . . - Doing loops: # The int after BEG represents the number of times to loop # At present, loops may not be nested diff --git a/main.go b/main.go index 2f90f82..e1da090 100644 --- a/main.go +++ b/main.go @@ -1,27 +1,76 @@ package main +import ( + "flag" + "fmt" + "os" + "path/filepath" + "strings" + "tildegit.org/sloum/filtress/parser" +) + type point struct { - x int - y int - maxX int - maxY int + x int + y int + maxX int + maxY int } -type color int -type mode int +type filter struct { + max int + min int + val int +} type filterState struct { - red color - green color - blue color - alpha color - location point - mod mode - register int - fade uint - loop uint + red filter + green filter + blue filter + alpha filter + location point + mode filter +} + +var variables = map[string]int{} + +func openFileFromPath(path string) *os.File { + file, err := os.Open(path) + if err != nil { + panic(err) + } + + return file } func main() { + // Handle checking filter file argument + flag.Parse() + posArgs := flag.Args() + if len(posArgs) > 1 || len(posArgs) < 1 { + panic(fmt.Sprintf("Input error: Too many positional arguments. Expected one, received %d", len(flag.Args()))) + } + fpath := posArgs[0] + fext := strings.ToUpper(filepath.Ext(fpath)) + _, fname := filepath.Split(fpath) + + if fext != ".FRS" { + panic(fmt.Sprintf("Input error: Incorrect filetype. Expected .FRS, received \".%s\"", fext)) + } + + // Open file and parse + fmt.Println("Filtress v0.2.0") + filterFile := openFileFromPath(fpath) + parser := parser.NewParser(filterFile) + fmt.Printf("Parsing file: %s ...\n", fname) + tree := parser.Parse() + if len(tree.Loops) > 0 { + fmt.Printf("File has %d procedures\n", len(tree.Loops)) + fmt.Println("File is valid") + } else { + fmt.Println("Invalid input file") + } + + fmt.Print(tree) + fmt.Println() } diff --git a/parser/lexer.go b/parser/lexer.go index 7ae27a1..154c5b9 100644 --- a/parser/lexer.go +++ b/parser/lexer.go @@ -1,4 +1,4 @@ -package parse +package parser import ( "bufio" @@ -48,31 +48,33 @@ func (s *scanner) unread() { func (s *scanner) scan() Token { - char := s.read() + for { + char := s.read() - if isWhitespace(char) { - s.unread() - return s.scanWhitespace() - } else if isLetter(char) { - s.unread() - return s.scanText() - } else if isNumber(char) { - s.unread() - return s.scanNumber() - } else if char == '#' { - s.unread() - return s.scanComment() - } else if isOpperator(char) { - return Token{Opperator, string(char)} - } else if char == '\n' { - return Token{Newline,""} - } else if char == ':' { - return Token{Separator,""} - } else if char == eof { - return Token{End, ""} + if isWhitespace(char) { + s.unread() + s.scanWhitespace() + } else if isLetter(char) { + s.unread() + return s.scanText() + } else if isNumber(char) { + s.unread() + return s.scanNumber() + } else if char == '#' { + s.unread() + s.scanComment() + } else if isOpperator(char) { + return Token{Opperator, string(char)} + } else if char == '\n' { + return Token{Newline,"New Line"} + } else if char == ':' { + return Token{Separator,":"} + } else if char == eof { + return Token{End, "eof"} + } else { + return Token{Illegal, string(char)} + } } - - return Token{Illegal, string(char)} } diff --git a/parser/parser.go b/parser/parser.go index 40531ae..bc1e80a 100644 --- a/parser/parser.go +++ b/parser/parser.go @@ -1,4 +1,4 @@ -package parse +package parser import ( "io" @@ -45,11 +45,6 @@ func (p *Parser) scan() (current Token) { return p.buffer.token } - for { - if current = p.s.scan(); current.kind != Whitespace && current.kind != Comment { - break - } - } current = p.s.scan() p.buffer.token = current return @@ -70,8 +65,13 @@ func (p *Parser) parseExpressions(equals bool) []Expression { if t.kind == Opperator { ex.Opperator = rune(t.val[0]) t = p.scan() - } else { + } else if t.kind == Number || t.kind == Text { ex.Opperator = '=' + } else if t.kind == Newline { + p.unscan() + break + } else { + panic(fmt.Sprintf("Parse error: Invalid token %q on \033[1mline %d\033[0m", t.val, p.row)) } if t.kind == Number { @@ -86,6 +86,7 @@ func (p *Parser) parseExpressions(equals bool) []Expression { exprs = append(exprs, ex) + t = p.scan() if t.kind == Separator { continue } @@ -133,17 +134,12 @@ func (p *Parser) parseLoop() Loop { t := p.scan() l := Loop{} - if strings.ToUpper(t.val) == "LOOP" { - t = p.scan() - if t.kind == Number { - l.Counter, _ = 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)) - } + if t.kind == Number { + l.Counter, _ = strconv.Atoi(t.val) } else { - p.unscan() - l.Counter = 1 + 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) L: @@ -163,6 +159,9 @@ func (p *Parser) parseLoop() Loop { 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) @@ -193,8 +192,15 @@ 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: - p.unscan() - loop := p.parseLoop() + var loop Loop + if strings.ToUpper(t.val) == "BEG" { + loop = p.parseLoop() + } else { + p.unscan() + loop = Loop{1, make([]Procedure, 0, 1)} + procedure := p.parseProcedure() + loop.Procedures = append(loop.Procedures, procedure) + } tree.Loops = append(tree.Loops, loop) } } @@ -205,8 +211,7 @@ func (p *Parser) Parse() AST { func isValidProcedure(p string) bool { switch p { case "REG", "LOC", "BEG", "END", "RED", - "GRN", "BLU", "APH", "COL", "APY", "MOD", - "FAD": + "GRN", "BLU", "APH", "COL", "APY", "MOD": return true } return false @@ -224,3 +229,5 @@ func isVariable(v string) bool { func NewParser(r io.Reader) *Parser { return &Parser{s: NewScanner(r)} } + + diff --git a/receivers.go b/receivers.go new file mode 100644 index 0000000..71819c4 --- /dev/null +++ b/receivers.go @@ -0,0 +1,96 @@ +package main + +import ( + "fmt" + "tildegit.org/sloum/filtress/parser" +) + +func (f *filter) update(change parser.Expression, vars map[string]int) { + opand := change.Opperand + if change.Variable != "" { + if val, ok := vars[change.Variable]; ok { + opand = val + } else { + panic(fmt.Sprintf("Runtime error: Encountered unknown variable %q", val)) + } + } + + switch change.Opperator { + case '+': + f.val += opand + case '-': + f.val -= opand + case '*': + f.val *= opand + case '/': + if opand == 0 { + f.val = 1 + } else { + f.val /= opand + } + case '=': + f.val = opand + } + if f.val > f.max { + f.val %= f.max + } + if f.val < f.min { + f.val = f.max - f.val%f.max + } +} + +func (p *point) update(change []parser.Expression, vars map[string]int) { + var totalX, totalY, val, opand, max int + var target *int + + for i, e := range change { + if i == 0 { + target = &totalX + val = p.x + max = p.maxX + } else if i == 1 { + target = &totalY + val = p.y + max = p.maxY + } else { + break + } + + if e.Variable != "" { + if val, ok := vars[e.Variable]; ok { + opand = val + } else { + panic(fmt.Sprintf("Runtime error: Encountered unknown variable %q", val)) + } + } else { + opand = e.Opperand + } + + switch e.Opperator { + case '+': + *target = val + opand + case '-': + *target = val - opand + case '*': + *target = val * opand + case '/': + if opand == 0 { + *target = 1 + } else { + *target = val / opand + } + case '=': + *target = opand + } + + if *target > max { + *target %= max + } + + if *target < 0 { + *target = max - *target%max + } + } + p.x = totalX + p.y = totalY +} diff --git a/test.frs b/test.frs new file mode 100644 index 0000000..176fdf9 --- /dev/null +++ b/test.frs @@ -0,0 +1,17 @@ +# First attempt at a filtress file!! +MOD 1 +RED 100 + +BEG 10 +LOC +100:WID +BLU /300 +END + +#comment +APY +100:+100 + + + + + +