This repository has been archived on 2026-05-13. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files
sfdl/parser/parser.go
2025-12-04 18:20:07 +08:00

198 lines
4.3 KiB
Go

package parser
import (
"fmt"
"sfdl/scanner"
)
type Parser struct {
sc *scanner.Scanner
tok scanner.Token
}
func NewParser(sc *scanner.Scanner) *Parser {
p := &Parser{sc: sc}
p.nextToken()
return p
}
func (p *Parser) nextToken() {
p.tok = p.sc.GetToken()
}
func (p *Parser) errorf(format string, args ...interface{}) {
msg := fmt.Sprintf(format, args...)
panic("Syntax error: " + msg)
}
func (p *Parser) match(t scanner.TokenType) {
if p.tok.Type != t {
p.errorf("expect %v, got %v (lexeme=%q)",
t, p.tok.Type, p.tok.Lexeme)
}
p.nextToken()
}
// Expression → Term { (PLUS | MINUS) Term }
func (p *Parser) parseExpression() *ExprNode {
left := p.parseTerm()
for p.tok.Type == scanner.PLUS || p.tok.Type == scanner.MINUS {
op := p.tok.Type
p.match(op)
right := p.parseTerm()
left = NewBinaryNode(op, left, right)
}
return left
}
// Term → Factor { (MUL | DIV) Factor }
func (p *Parser) parseTerm() *ExprNode {
left := p.parseFactor()
for p.tok.Type == scanner.MUL || p.tok.Type == scanner.DIV {
op := p.tok.Type
p.match(op)
right := p.parseFactor()
left = NewBinaryNode(op, left, right)
}
return left
}
// Factor → (PLUS | MINUS) Factor | Component
func (p *Parser) parseFactor() *ExprNode {
if p.tok.Type == scanner.PLUS || p.tok.Type == scanner.MINUS {
op := p.tok.Type
p.match(op)
child := p.parseFactor()
return NewUnaryNode(op, child)
}
return p.parseComponent()
}
// Component → Atom [ POWER Component ]
func (p *Parser) parseComponent() *ExprNode {
left := p.parseAtom()
if p.tok.Type == scanner.POWER {
p.match(scanner.POWER)
right := p.parseComponent() // 右结合
left = NewBinaryNode(scanner.POWER, left, right)
}
return left
}
// Atom → CONST_ID
//
// | T
// | FUNC L_BRACKET Expression R_BRACKET
// | L_BRACKET Expression R_BRACKET
func (p *Parser) parseAtom() *ExprNode {
switch p.tok.Type {
case scanner.CONST_ID:
node := NewConstNode(p.tok.Value)
p.nextToken()
return node
case scanner.T:
p.nextToken()
return NewTNode()
case scanner.FUNC:
fn := p.tok.Func
p.nextToken()
p.match(scanner.L_BRACKET)
child := p.parseExpression()
p.match(scanner.R_BRACKET)
return NewFuncNode(fn, child)
case scanner.L_BRACKET:
p.match(scanner.L_BRACKET)
node := p.parseExpression()
p.match(scanner.R_BRACKET)
return node
default:
p.errorf("unexpected token in Atom: %v (lexeme=%q)", p.tok.Type, p.tok.Lexeme)
return nil
}
}
// Parse all
func (p *Parser) Parse() {
for p.tok.Type != scanner.NONTOKEN {
p.parseStatement()
p.match(scanner.SEMICO)
}
}
func (p *Parser) parseStatement() {
switch p.tok.Type {
case scanner.ORIGIN:
p.parseOriginStatement()
case scanner.SCALE:
p.parseScaleStatement()
case scanner.ROT:
p.parseRotStatement()
case scanner.FOR:
p.parseForStatement()
default:
p.errorf("unknown statement start: %v (lexeme=%q)", p.tok.Type, p.tok.Lexeme)
}
}
// ORIGIN IS ( Expression , Expression )
func (p *Parser) parseOriginStatement() {
p.match(scanner.ORIGIN)
p.match(scanner.IS)
p.match(scanner.L_BRACKET)
xExpr := p.parseExpression()
p.match(scanner.COMMA)
yExpr := p.parseExpression()
p.match(scanner.R_BRACKET)
// todo:
// semantices.SetOrigin(xExpr, yExpr)
fmt.Println("Parsed ORIGIN", xExpr, yExpr)
}
// SCALE IS ( Expression , Expression )
func (p *Parser) parseScaleStatement() {
p.match(scanner.SCALE)
p.match(scanner.IS)
p.match(scanner.L_BRACKET)
xExpr := p.parseExpression()
p.match(scanner.COMMA)
yExpr := p.parseExpression()
p.match(scanner.R_BRACKET)
fmt.Println("Parsed SCALE", xExpr, yExpr)
}
// ROT IS Expression
func (p *Parser) parseRotStatement() {
p.match(scanner.ROT)
p.match(scanner.IS)
angleExpr := p.parseExpression()
fmt.Println("Parsed ROT", angleExpr)
}
// FOR T FROM Expression TO Expression STEP Expression
//
// DRAW ( Expression , Expression )
func (p *Parser) parseForStatement() {
p.match(scanner.FOR)
p.match(scanner.T)
p.match(scanner.FROM)
start := p.parseExpression()
p.match(scanner.TO)
end := p.parseExpression()
p.match(scanner.STEP)
step := p.parseExpression()
p.match(scanner.DRAW)
p.match(scanner.L_BRACKET)
xExpr := p.parseExpression()
p.match(scanner.COMMA)
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)
}