-
Notifications
You must be signed in to change notification settings - Fork 548
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #2103 from xushiwei/q
pseudo code
- Loading branch information
Showing
4 changed files
with
581 additions
and
0 deletions.
There are no files selected for viewing
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
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 | ||
} |
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
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) |
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
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") | ||
} |
Oops, something went wrong.