Created
September 25, 2014 19:44
-
-
Save bemasher/6392f80fb0f85a1c9825 to your computer and use it in GitHub Desktop.
Parser for Annotated expressions generated by FFTW's genfft tool.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
(:= T1 xi[0]) | |
(:= T6 xi[6]) | |
(:= T2 xi[4]) | |
(:= T3 xi[8]) | |
(:= T4 (+ T2 T3)) | |
(:= T32 (+ T3 (- T2))) | |
(:= T7 xi[10]) | |
(:= T8 xi[2]) | |
(:= T9 (+ T7 T8)) | |
(:= T33 (+ T8 (- T7))) | |
(:= T5 (+ T1 T4)) | |
(:= T10 (+ T6 T9)) | |
(:= T45 (+ T32 T33)) | |
(:= T34 (* KP866025403 (+ T32 (- T33)))) | |
(:= T26 (+ T6 (- (* KP500000000 T9)))) | |
(:= T25 (+ T1 (- (* KP500000000 T4)))) | |
(:= T12 xi[3]) | |
(:= T17 xi[9]) | |
(:= T13 xi[7]) | |
(:= T14 xi[11]) | |
(:= T15 (+ T13 T14)) | |
(:= T28 (+ T14 (- T13))) | |
(:= T18 xi[1]) | |
(:= T19 xi[5]) | |
(:= T20 (+ T18 T19)) | |
(:= T29 (+ T19 (- T18))) | |
(:= T16 (+ T12 T15)) | |
(:= T21 (+ T17 T20)) | |
(:= T44 (+ T28 T29)) | |
(:= T36 (+ T17 (- (* KP500000000 T20)))) | |
(:= T35 (+ T12 (- (* KP500000000 T15)))) | |
(:= T30 (* KP866025403 (+ T28 (- T29)))) | |
(:= T11 (+ T5 (- T10))) | |
(:= T22 (* I (+ T16 (- T21)))) | |
(:= xo[9] (+ T11 (- T22))) | |
(:= xo[3] (+ T11 T22)) | |
(:= T23 (+ T5 T10)) | |
(:= T24 (+ T16 T21)) | |
(:= xo[6] (+ T23 (- T24))) | |
(:= xo[0] (+ T23 T24)) | |
(:= T27 (+ T25 (- T26))) | |
(:= T31 (+ T27 (- T30))) | |
(:= T40 (+ T27 T30)) | |
(:= T37 (+ T35 (- T36))) | |
(:= T38 (* I (+ T34 T37))) | |
(:= T39 (* I (+ T34 (- T37)))) | |
(:= xo[5] (+ T31 (- T38))) | |
(:= xo[11] (+ T40 (- T39))) | |
(:= xo[7] (+ T38 T31)) | |
(:= xo[1] (+ T39 T40)) | |
(:= T46 (* I (* KP866025403 (+ T44 (- T45))))) | |
(:= T48 (* I (* KP866025403 (+ T45 T44)))) | |
(:= T41 (+ T25 T26)) | |
(:= T42 (+ T35 T36)) | |
(:= T43 (+ T41 (- T42))) | |
(:= T47 (+ T41 T42)) | |
(:= xo[10] (+ T43 (- T46))) | |
(:= xo[4] (+ T47 T48)) | |
(:= xo[2] (+ T43 T46)) | |
(:= xo[8] (+ T47 (- T48))) | |
DVK(KP500000000, +0.500000000000000000000000000000000000000000000); | |
DVK(KP866025403, +0.866025403784438646763723170752936183471402627); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package main | |
const ( | |
KP500000000 = +0.500000000000000000000000000000000000000000000 | |
KP866025403 = +0.866025403784438646763723170752936183471402627 | |
I = 1i | |
) | |
func DFT(xi, xo []complex128) { | |
T1 := xi[0] | |
T6 := xi[6] | |
T2 := xi[4] | |
T3 := xi[8] | |
T4 := T2 + T3 | |
T32 := T3 - T2 | |
T7 := xi[10] | |
T8 := xi[2] | |
T9 := T7 + T8 | |
T33 := T8 - T7 | |
T5 := T1 + T4 | |
T10 := T6 + T9 | |
T45 := T32 + T33 | |
T34 := KP866025403 * (T32 - T33) | |
T26 := T6 - (KP500000000 * T9) | |
T25 := T1 - (KP500000000 * T4) | |
T12 := xi[3] | |
T17 := xi[9] | |
T13 := xi[7] | |
T14 := xi[11] | |
T15 := T13 + T14 | |
T28 := T14 - T13 | |
T18 := xi[1] | |
T19 := xi[5] | |
T20 := T18 + T19 | |
T29 := T19 - T18 | |
T16 := T12 + T15 | |
T21 := T17 + T20 | |
T44 := T28 + T29 | |
T36 := T17 - (KP500000000 * T20) | |
T35 := T12 - (KP500000000 * T15) | |
T30 := KP866025403 * (T28 - T29) | |
T11 := T5 - T10 | |
T22 := I * (T16 - T21) | |
xo[9] = T11 - T22 | |
xo[3] = T11 + T22 | |
T23 := T5 + T10 | |
T24 := T16 + T21 | |
xo[6] = T23 - T24 | |
xo[0] = T23 + T24 | |
T27 := T25 - T26 | |
T31 := T27 - T30 | |
T40 := T27 + T30 | |
T37 := T35 - T36 | |
T38 := I * (T34 + T37) | |
T39 := I * (T34 - T37) | |
xo[5] = T31 - T38 | |
xo[11] = T40 - T39 | |
xo[7] = T38 + T31 | |
xo[1] = T39 + T40 | |
T46 := I * (KP866025403 * (T44 - T45)) | |
T48 := I * (KP866025403 * (T45 + T44)) | |
T41 := T25 + T26 | |
T42 := T35 + T36 | |
T43 := T41 - T42 | |
T47 := T41 + T42 | |
xo[10] = T43 - T46 | |
xo[4] = T47 + T48 | |
xo[2] = T43 + T46 | |
xo[8] = T47 - T48 | |
} | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package main | |
import ( | |
"bufio" | |
"fmt" | |
"go/format" | |
"log" | |
"os" | |
"regexp" | |
"strings" | |
) | |
// An expression consists of either an Operator or a Literal. Operators have | |
// at least one operand which are Expressions. | |
type Expression struct { | |
Op string | |
Lit string | |
OpIdx int | |
Expr []*Expression | |
} | |
// Determines if an operator is unary based on the number of operands. | |
func (expr Expression) IsUnary() bool { | |
return len(expr.Expr) == 1 | |
} | |
// Produces valid Go string representation of the expression. | |
func (expr Expression) String() string { | |
return expr.stringHelper(0) | |
} | |
// String() provides default depth value, this is the actual function. | |
func (expr Expression) stringHelper(depth int) (r string) { | |
// If the expression is an Operand, just print the literal. | |
if expr.Op == "" { | |
return expr.Lit | |
} | |
// Only print parenthesis if we're not at the top level. | |
if depth > 1 { | |
r += "(" | |
defer func() { | |
r += ")" | |
}() | |
} | |
// Only use the combined declaration//assignment operator if we're assigning to a T\d+ variable. | |
if expr.Op == "=" && strings.HasPrefix(expr.Expr[0].Lit, "T") { | |
expr.Op = ":=" | |
} | |
// If the expression is unary then print the operator before it's operand. | |
if expr.IsUnary() { | |
r += expr.Op | |
r += expr.Expr[0].stringHelper(depth + 1) | |
} else { | |
// For each operand. | |
for idx := range expr.Expr { | |
// Don't print an operator on the first operand. | |
if idx != 0 { | |
// If the operator is addition and the current operand is unary subtraction, simplify. | |
if expr.Op == "+" && expr.Expr[idx].IsUnary() && expr.Expr[idx].Op == "-" { | |
r += "-" | |
r += expr.Expr[idx].Expr[0].stringHelper(depth + 1) | |
continue | |
} else { | |
// Else, append the operator. | |
r += expr.Op | |
} | |
} | |
// Recurse for each operand. This is skipped if we did unary simplification. | |
r += expr.Expr[idx].stringHelper(depth + 1) | |
} | |
} | |
return | |
} | |
// Parse an expression into an expression tree. | |
func (expr *Expression) Parse(line string) { | |
// Skip '(:' | |
expr.parse(line[2:]) | |
} | |
// Parse(line string) skips first two characters of each expression, this is | |
// the actual function. | |
func (expr *Expression) parse(line string) (idx int) { | |
// Operators always have at least one operand. | |
// Empty expressions will never appear in String() output but we may want | |
// to conditionally create this later for large parse trees. | |
expr.Expr = append(expr.Expr, new(Expression)) | |
// While there are characters left to parse. | |
for idx = 0; idx < len(line); idx++ { | |
switch line[idx] { | |
// Opening parenthesis represent the beginning of a new expression. | |
// Recursively parse it and update index with number of characters | |
// consumed. | |
case '(': | |
idx += expr.Expr[expr.OpIdx].parse(line[idx+1:]) | |
// Colons are the first character in the assignment operator, we don't need it so skip it. | |
case ':': | |
continue | |
// Operators are appended to Op field and space following is consumed. | |
case '=', '+', '-', '*': | |
expr.Op = line[idx : idx+1] | |
idx += 1 | |
// Spaces will only ever be encountered between operands, so make a | |
// new operand and increment the operand index. | |
case ' ': | |
expr.Expr = append(expr.Expr, new(Expression)) | |
expr.OpIdx++ | |
// Closing parenthesis represent termination of an expression. Return | |
// consumed character count + 1 to include this character. | |
case ')': | |
return idx + 1 | |
// Anything else must be part of a literal, append it. | |
default: | |
expr.Expr[expr.OpIdx].Lit += line[idx : idx+1] | |
} | |
} | |
return | |
} | |
func init() { | |
log.SetFlags(log.Lshortfile) | |
} | |
func main() { | |
// Print usage if user didn't pass the right number of arguments. | |
if len(os.Args) != 2 { | |
fmt.Println("Usage: parse [filename]") | |
os.Exit(1) | |
} | |
// Open input file for reading. | |
inputFile, err := os.Open(os.Args[1]) | |
if err != nil { | |
log.Fatal("Error opening input file", err) | |
} | |
defer inputFile.Close() | |
// Create a line scanner, we only need input one line at a time. | |
inputScanner := bufio.NewScanner(inputFile) | |
var ( | |
body string | |
constants [][]string | |
) | |
// Regular expression matches constants. | |
constRe := regexp.MustCompile(`DVK\((K[NP]\d+), ([+-][\d\.]+)\);`) | |
// For each line in the input. | |
for idx := 0; inputScanner.Scan(); idx++ { | |
// Get the current line. | |
line := inputScanner.Text() | |
// If the line has the prefix we expect on a constant, try parsing it. | |
if strings.HasPrefix(line, "DVK") { | |
// If the regex matches we have a constant. | |
if constRe.MatchString(line) { | |
// Append the matching groups from the constant to the constant list. | |
constants = append(constants, constRe.FindStringSubmatch(line)[1:]) | |
} | |
// Continue so we don't try parsing this as an expression. | |
continue | |
} | |
// Parse the line and append it to the body. | |
var expr Expression | |
expr.Parse(line) | |
body += expr.String() + "\n" | |
} | |
// Lay out some boilerplate for the go formatter. | |
source := "package main\n" | |
// Append the constants we parsed including the imaginary constant. | |
source += "const (\n" | |
constants = append(constants, []string{"I", "1i"}) | |
for _, constant := range constants { | |
source += fmt.Sprintf("%s = %s\n", constant[0], constant[1]) | |
} | |
source += ")\n" | |
// Append the function signature, body and enclosing brackets. | |
source += "func DFT(xi, xo []complex128) {\n" + body + "}" | |
// Format the source. | |
formatted, err := format.Source([]byte(source)) | |
if err != nil { | |
log.Fatal("Error formatting go source:", err) | |
} | |
// Display the formatted source. | |
fmt.Println(string(formatted)) | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment