diff --git a/main.go b/main.go index deac646..928b183 100644 --- a/main.go +++ b/main.go @@ -7,6 +7,7 @@ import ( "sfdl/parser" "sfdl/scanner" + "sfdl/semantices" ) func main() { @@ -14,15 +15,24 @@ func main() { fmt.Println("usage: sfdl ") return } - filename := os.Args[1] + sc, err := scanner.NewScannerFromFile(filename) if err != nil { log.Fatalf("open file failed: %v", err) } + // 初始化语义状态 & 画布 + parser.ResetState() + semantices.InitCanvas() + p := parser.NewParser(sc) p.Parse() - fmt.Println("Parse OK.") + // 保存图片 + outFile := "out.png" + if err := semantices.SavePNG(outFile); err != nil { + log.Fatalf("save png failed: %v", err) + } + fmt.Println("Done. output:", outFile) } diff --git a/parser/parser.go b/parser/parser.go index f255ce2..f4efad8 100644 --- a/parser/parser.go +++ b/parser/parser.go @@ -144,9 +144,7 @@ func (p *Parser) parseOriginStatement() { yExpr := p.parseExpression() p.match(scanner.R_BRACKET) - // todo: - // semantices.SetOrigin(xExpr, yExpr) - fmt.Println("Parsed ORIGIN", xExpr, yExpr) + originStatement(xExpr, yExpr) } // SCALE IS ( Expression , Expression ) @@ -159,7 +157,7 @@ func (p *Parser) parseScaleStatement() { yExpr := p.parseExpression() p.match(scanner.R_BRACKET) - fmt.Println("Parsed SCALE", xExpr, yExpr) + scaleStatement(xExpr, yExpr) } // ROT IS Expression @@ -168,7 +166,7 @@ func (p *Parser) parseRotStatement() { p.match(scanner.IS) angleExpr := p.parseExpression() - fmt.Println("Parsed ROT", angleExpr) + rotStatement(angleExpr) } // FOR T FROM Expression TO Expression STEP Expression @@ -190,8 +188,5 @@ func (p *Parser) parseForStatement() { yExpr := p.parseExpression() p.match(scanner.R_BRACKET) - fmt.Println("Parsed FOR", start, end, step, xExpr, yExpr) - - // todo: - // semantices.DrawLoop(start, end, step, xExpr, yExpr) + forStatement(start, end, step, xExpr, yExpr) } diff --git a/parser/semantices.go b/parser/semantices.go new file mode 100644 index 0000000..83c4aa4 --- /dev/null +++ b/parser/semantices.go @@ -0,0 +1,101 @@ +package parser + +import ( + "math" + + "sfdl/scanner" + "sfdl/semantices" +) + +var ( + Parameter float64 // T + OriginX, OriginY float64 + ScaleX, ScaleY float64 = 1, 1 + RotAngle float64 // 弧度 +) + +func ResetState() { + Parameter = 0 + OriginX, OriginY = 0, 0 + ScaleX, ScaleY = 1, 1 + RotAngle = 0 +} + +func evalExpr(root *ExprNode) float64 { + if root == nil { + return 0 + } + switch root.Op { + case scanner.PLUS: + return evalExpr(root.Left) + evalExpr(root.Right) + case scanner.MINUS: + return evalExpr(root.Left) - evalExpr(root.Right) + case scanner.MUL: + return evalExpr(root.Left) * evalExpr(root.Right) + case scanner.DIV: + return evalExpr(root.Left) / evalExpr(root.Right) + case scanner.POWER: + return math.Pow(evalExpr(root.Left), evalExpr(root.Right)) + case scanner.FUNC: + return root.Func(evalExpr(root.Left)) + case scanner.CONST_ID: + return root.Value + case scanner.T: + return Parameter + default: + return 0 + } +} + +func calcCoord(xExpr, yExpr *ExprNode) (float64, float64) { + x := evalExpr(xExpr) + y := evalExpr(yExpr) + + // scale + x *= ScaleX + y *= ScaleY + + // rotate + tx := x*math.Cos(RotAngle) + y*math.Sin(RotAngle) + ty := y*math.Cos(RotAngle) - x*math.Sin(RotAngle) + x, y = tx, ty + + // translate + x += OriginX + y += OriginY + + return x, y +} + +// ORIGIN IS (x, y) +func originStatement(xExpr, yExpr *ExprNode) { + OriginX = evalExpr(xExpr) + OriginY = evalExpr(yExpr) +} + +// SCALE IS (sx, sy) +func scaleStatement(xExpr, yExpr *ExprNode) { + ScaleX = evalExpr(xExpr) + ScaleY = evalExpr(yExpr) +} + +// ROT IS angle +func rotStatement(angleExpr *ExprNode) { + RotAngle = evalExpr(angleExpr) +} + +// FOR T FROM start TO end STEP step DRAW (xExpr, yExpr) +func forStatement(startExpr, endExpr, stepExpr, xExpr, yExpr *ExprNode) { + start := evalExpr(startExpr) + end := evalExpr(endExpr) + step := evalExpr(stepExpr) + + if step <= 1e-9 { + return + } + + for Parameter = start; Parameter <= end; Parameter += step { + x, y := calcCoord(xExpr, yExpr) + semantices.DrawPixel(int(math.Round(x)), int(math.Round(y))) + } +} diff --git a/semantices/draw.go b/semantices/draw.go index 9123ae2..c9a778e 100644 --- a/semantices/draw.go +++ b/semantices/draw.go @@ -1 +1,47 @@ package semantices + +import ( + "image" + "image/color" + "image/png" + "os" +) + +const ( + Width = 800 + Height = 600 +) + +var img *image.RGBA + +func InitCanvas() { + img = image.NewRGBA(image.Rect(0, 0, Width, Height)) + white := color.RGBA{255, 255, 255, 255} + for y := 0; y < Height; y++ { + for x := 0; x < Width; x++ { + img.Set(x, y, white) + } + } +} + +func DrawPixel(x, y int) { + if img == nil { + return + } + if x < 0 || x >= Width || y < 0 || y >= Height { + return + } + img.Set(x, y, color.Black) +} + +func SavePNG(filename string) error { + if img == nil { + return nil + } + f, err := os.Create(filename) + if err != nil { + return err + } + defer f.Close() + return png.Encode(f, img) +} diff --git a/semantices/semantices.go b/semantices/semantices.go deleted file mode 100644 index 9123ae2..0000000 --- a/semantices/semantices.go +++ /dev/null @@ -1 +0,0 @@ -package semantices diff --git a/test.sfdl b/test.sfdl index b114a27..6702f0f 100644 --- a/test.sfdl +++ b/test.sfdl @@ -1,6 +1,32 @@ -origin is (100, 300); -rot is 0; -scale is (1, 1); --- 画一个简单的函数 -for t from 0 to 10 step 0.5 draw (t, t*t); +-- Arrow +-- color is (255,255,0); + +scale is (1, 1); +-- size is 10; + +origin is (450, 450); +rot is pi; +for t from 0 to 400 step 1 draw( t, t ); + + +-- 心形曲线 + +origin is (200, 200); +rot is pi/2; +-- size is 5; + +-- 圆润型 +-- color is blue; +scale is (50, 50); +for t from -pi to pi step pi/200 draw((2*cos(t) - cos(2*t)), (2*sin(t)-sin(2*t)) ); + +-- 尖锐型 +origin is (200+80, 200+80); +-- color is red; +rot is pi; +scale is (8, 8); +for t from 0 to 2*pi step pi/200 draw( + 16*(sin(t)**3), + 13*cos(t) - 5*cos(2*t) - 2*cos(3*t)-cos(4*t) + );