feat: semantices
This commit is contained in:
14
main.go
14
main.go
@@ -7,6 +7,7 @@ import (
|
|||||||
|
|
||||||
"sfdl/parser"
|
"sfdl/parser"
|
||||||
"sfdl/scanner"
|
"sfdl/scanner"
|
||||||
|
"sfdl/semantices"
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
@@ -14,15 +15,24 @@ func main() {
|
|||||||
fmt.Println("usage: sfdl <source-file>")
|
fmt.Println("usage: sfdl <source-file>")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
filename := os.Args[1]
|
filename := os.Args[1]
|
||||||
|
|
||||||
sc, err := scanner.NewScannerFromFile(filename)
|
sc, err := scanner.NewScannerFromFile(filename)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatalf("open file failed: %v", err)
|
log.Fatalf("open file failed: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 初始化语义状态 & 画布
|
||||||
|
parser.ResetState()
|
||||||
|
semantices.InitCanvas()
|
||||||
|
|
||||||
p := parser.NewParser(sc)
|
p := parser.NewParser(sc)
|
||||||
p.Parse()
|
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)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -144,9 +144,7 @@ func (p *Parser) parseOriginStatement() {
|
|||||||
yExpr := p.parseExpression()
|
yExpr := p.parseExpression()
|
||||||
p.match(scanner.R_BRACKET)
|
p.match(scanner.R_BRACKET)
|
||||||
|
|
||||||
// todo:
|
originStatement(xExpr, yExpr)
|
||||||
// semantices.SetOrigin(xExpr, yExpr)
|
|
||||||
fmt.Println("Parsed ORIGIN", xExpr, yExpr)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// SCALE IS ( Expression , Expression )
|
// SCALE IS ( Expression , Expression )
|
||||||
@@ -159,7 +157,7 @@ func (p *Parser) parseScaleStatement() {
|
|||||||
yExpr := p.parseExpression()
|
yExpr := p.parseExpression()
|
||||||
p.match(scanner.R_BRACKET)
|
p.match(scanner.R_BRACKET)
|
||||||
|
|
||||||
fmt.Println("Parsed SCALE", xExpr, yExpr)
|
scaleStatement(xExpr, yExpr)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ROT IS Expression
|
// ROT IS Expression
|
||||||
@@ -168,7 +166,7 @@ func (p *Parser) parseRotStatement() {
|
|||||||
p.match(scanner.IS)
|
p.match(scanner.IS)
|
||||||
angleExpr := p.parseExpression()
|
angleExpr := p.parseExpression()
|
||||||
|
|
||||||
fmt.Println("Parsed ROT", angleExpr)
|
rotStatement(angleExpr)
|
||||||
}
|
}
|
||||||
|
|
||||||
// FOR T FROM Expression TO Expression STEP Expression
|
// FOR T FROM Expression TO Expression STEP Expression
|
||||||
@@ -190,8 +188,5 @@ func (p *Parser) parseForStatement() {
|
|||||||
yExpr := p.parseExpression()
|
yExpr := p.parseExpression()
|
||||||
p.match(scanner.R_BRACKET)
|
p.match(scanner.R_BRACKET)
|
||||||
|
|
||||||
fmt.Println("Parsed FOR", start, end, step, xExpr, yExpr)
|
forStatement(start, end, step, xExpr, yExpr)
|
||||||
|
|
||||||
// todo:
|
|
||||||
// semantices.DrawLoop(start, end, step, xExpr, yExpr)
|
|
||||||
}
|
}
|
||||||
|
|||||||
101
parser/semantices.go
Normal file
101
parser/semantices.go
Normal file
@@ -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)))
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1 +1,47 @@
|
|||||||
package semantices
|
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)
|
||||||
|
}
|
||||||
|
|||||||
@@ -1 +0,0 @@
|
|||||||
package semantices
|
|
||||||
36
test.sfdl
36
test.sfdl
@@ -1,6 +1,32 @@
|
|||||||
origin is (100, 300);
|
|
||||||
rot is 0;
|
|
||||||
scale is (1, 1);
|
|
||||||
|
|
||||||
-- 画一个简单的函数
|
-- Arrow
|
||||||
for t from 0 to 10 step 0.5 draw (t, t*t);
|
-- 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)
|
||||||
|
);
|
||||||
|
|||||||
Reference in New Issue
Block a user