Skip to content

Commit

Permalink
Merge pull request #2103 from xushiwei/q
Browse files Browse the repository at this point in the history
pseudo code
  • Loading branch information
xushiwei authored Feb 14, 2025
2 parents 07a54ca + cca27ae commit 37d1083
Show file tree
Hide file tree
Showing 4 changed files with 581 additions and 0 deletions.
90 changes: 90 additions & 0 deletions demo/gop-parser/pseudo/ast.gop
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
import "gop/ast"

// Stmt - 语句
type Stmt interface {
}

// Type - 类型
type Type interface {
}

// Ident - 标识符(类型)
//
type Ident struct {
Name string
}

// EmptyStmt - 空语句
type EmptyStmt struct {
}

// VarStmt - 变量声明语句
//
// DECLARE {变量名} : {类型}
type VarStmt struct {
Name string
Type Type
}

// ConstStmt - 常量声明语句
//
// CONSTANT {常量名} <- {表达式}
type ConstStmt struct {
Name string
Value ast.Expr
}

// AssignStmt - 赋值语句
//
// {变量名} <- {表达式}
type AssignStmt struct {
Name string
Value ast.Expr
}

// OutputStmt - 输出语句
//
// OUTPUT {表达式}
type OutputStmt struct {
Value ast.Expr
}

// InputStmt - 输入语句
//
// INPUT {变量名}
type InputStmt struct {
Name string
}

// IfStmt - 条件语句
//
// IF {表达式} THEN
// {语句块}
// ELSE
// {语句块}
// ENDIF
type IfStmt struct {
Cond ast.Expr
Body []Stmt
Else []Stmt // 可选
}

// WhileStmt - While循环语句
//
// WHILE {表达式} DO
// {语句块}
// ENDWHILE
type WhileStmt struct {
Cond ast.Expr
Body []Stmt
}

// UntilStmt - Unti循环语句
//
// REPEAT
// {语句块}
// UNTIL {表达式}
type UntilStmt struct {
Body []Stmt
Cond ast.Expr
}
18 changes: 18 additions & 0 deletions demo/gop-parser/pseudo/main.gop
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import "os"

func NewState() *state {
return &state{vars: {}, consts: {}}
}

func exec(code string) {
lines := code.split("\n")
stmts := parse(lines)
newState.exec(stmts)
}

if len(os.Args) < 2 {
println("Usage: pseudo <file>")
return
}
code := string(os.readFile(os.Args[1])!)
exec(code)
184 changes: 184 additions & 0 deletions demo/gop-parser/pseudo/parser.gop
Original file line number Diff line number Diff line change
@@ -0,0 +1,184 @@
import (
"gop/ast"
"gop/parser"
"gop/scanner"
"gop/token"
)

func parse(lines []string) []Stmt {
stmts, rest := parseBlockStmt(lines)
if len(rest) > 0 {
panic("unexpected ${rest[0]}")
}
return stmts
}

func parseBlockStmt(lines []string) (stmts []Stmt, rest []string) {
var stmt Stmt
for len(lines) > 0 {
stmt, lines = parseStmt(lines)
if stmt == nil {
break
}
stmts = append(stmts, stmt)
}
rest = lines
return
}

func parseStmt(lines []string) (Stmt, []string) {
parts := lines[0].trimLeft(" \t").splitN(" ", 2)
switch parts[0] {
case "DECLARE":
return parseVarStmt(parts[1], lines)
case "CONSTANT":
return parseConstStmt(parts[1], lines)
case "OUTPUT":
return parseOutputStmt(parts[1], lines)
case "INPUT":
return parseInputStmt(parts[1], lines)
case "IF":
return parseIfStmt(parts[1], lines)
case "WHILE":
return parseWhileStmt(parts[1], lines)
case "REPEAT":
return parseUntilStmt(lines)
case "":
return &EmptyStmt{}, lines[1:]
case "ENDIF", "ENDWHILE", "UNTIL", "ELSE":
return nil, lines
default:
return parseAssignStmt(lines)
}
}

func expect(s *scanner.Scanner, tokExp token.Token) (token.Pos, string) {
pos, tok, lit := s.scan()
if tok != tokExp {
panic("expect ${tokExp}")
}
return pos, lit
}

// Type - 类型
func parseType(s *scanner.Scanner) Type {
_, name := expect(s, token.IDENT)
return &Ident{Name: name}
}

// Expr - 表达式
func parseExpr(expr string) ast.Expr {
e, err := parser.parseExpr(expr)
if err != nil {
panic(err)
}
return e
}

// VarStmt - 变量声明语句
//
// DECLARE {变量名} : {类型}
func parseVarStmt(rest string, lines []string) (Stmt, []string) {
s := scanner.new(rest, nil, 0)
_, name := expect(s, token.IDENT) // {变量名}
expect(s, token.COLON) // :
typ := parseType(s) // {类型}
return &VarStmt{Name: name, Type: typ}, lines[1:]
}

func parseNameAndValue(rest string) (string, ast.Expr) {
s := scanner.new(rest, nil, 0)
_, name := expect(s, token.IDENT) // {名称}
pos, _ := expect(s, token.ARROW) // <-
value := parseExpr(rest[pos+1:]) // {表达式}
return name, value
}

// ConstStmt - 常量声明语句
//
// CONSTANT {常量名} <- {表达式}
func parseConstStmt(rest string, lines []string) (Stmt, []string) {
name, value := parseNameAndValue(rest)
return &ConstStmt{Name: name, Value: value}, lines[1:]
}

// AssignStmt - 赋值语句
//
// {变量名} <- {表达式}
func parseAssignStmt(lines []string) (Stmt, []string) {
name, value := parseNameAndValue(lines[0])
return &AssignStmt{Name: name, Value: value}, lines[1:]
}

// OutputStmt - 输出语句
//
// OUTPUT {表达式}
func parseOutputStmt(rest string, lines []string) (Stmt, []string) {
value := parseExpr(rest)
return &OutputStmt{Value: value}, lines[1:]
}

// InputStmt - 输入语句
//
// INPUT {变量名}
func parseInputStmt(rest string, lines []string) (Stmt, []string) {
s := scanner.new(rest, nil, 0)
_, name := expect(s, token.IDENT) // {变量名}
return &InputStmt{Name: name}, lines[1:]
}

// IfStmt - If 语句
//
// IF {条件} THEN
// {语句块}
// ELSE
// {语句块}
// ENDIF
func parseIfStmt(rest string, lines []string) (Stmt, []string) {
rest = rest.trimRight(" \t").trimSuffix("THEN")
cond := parseExpr(rest)
body, lines := parseBlockStmt(lines[1:])
if len(lines) == 0 {
panic("expect ELSE or ENDIF")
}
stmt := &IfStmt{Cond: cond, Body: body}
if lines[0].trimSpace == "ELSE" {
stmt.Else, lines = parseBlockStmt(lines[1:])
}
if len(lines) == 0 || lines[0].trimSpace != "ENDIF" {
panic("expect ENDIF")
}
return stmt, lines[1:]
}

// WhileStmt - While 语句
//
// WHILE {条件} DO
// {语句块}
// ENDWHILE
func parseWhileStmt(rest string, lines []string) (Stmt, []string) {
rest = rest.trimRight(" \t").trimSuffix("DO")
cond := parseExpr(rest)
body, lines := parseBlockStmt(lines[1:])
if len(lines) == 0 || lines[0].trimSpace != "ENDWHILE" {
panic("expect ENDWHILE")
}
return &WhileStmt{Cond: cond, Body: body}, lines[1:]
}

// UntilStmt - Until 语句
//
// REPEAT
// {语句块}
// UNTIL {条件}
func parseUntilStmt(lines []string) (Stmt, []string) {
body, lines := parseBlockStmt(lines[1:])
if len(lines) > 0 {
line := lines[0].trimLeft(" \t")
if line.hasPrefix("UNTIL ") {
cond := parseExpr(line[6:])
return &UntilStmt{Body: body, Cond: cond}, lines[1:]
}
}
panic("expect UNTIL")
}
Loading

0 comments on commit 37d1083

Please sign in to comment.