package Parser
+//import . "scanner"
import Scanner "scanner"
func (P *Parser) Error(msg string) {
panic "error: ", msg, "\n";
+ P.Next(); // make progress
}
func (P *Parser) Expect(tok int) {
- if tok != P.tok {
+ if P.tok == tok {
+ P.Next()
+ } else {
P.Error("expected `" + Scanner.TokenName(tok) + "`, found `" + Scanner.TokenName(P.tok) + "`");
}
- P.Next(); // make progress in any case
}
-func (P *Parser) ParseType();
+func (P *Parser) Optional(tok int) {
+ if P.tok == tok {
+ P.Next();
+ }
+}
+
+
+func (P *Parser) TryType() bool;
func (P *Parser) ParseExpression();
}
+func (P *Parser) ParseType() {
+ P.Trace("Type");
+ if !P.TryType() {
+ P.Error("type expected");
+ }
+ P.Ecart();
+}
+
+
func (P *Parser) ParseArrayType() {
P.Trace("ArrayType");
P.Expect(Scanner.LBRACK);
func (P *Parser) ParseChannelType() {
P.Trace("ChannelType");
- panic "ChannelType";
+ P.Expect(Scanner.CHAN);
+ switch P.tok {
+ case Scanner.LSS: fallthrough
+ case Scanner.GTR:
+ P.Next();
+ }
+ P.ParseType();
P.Ecart();
}
P.Expect(Scanner.SEMICOLON);
}
}
- if P.tok == Scanner.SEMICOLON {
- P.Next();
- }
+ P.Optional(Scanner.SEMICOLON);
P.Expect(Scanner.RBRACE);
P.Ecart();
}
}
-func (P *Parser) ParseType() {
- P.Trace("Type");
+func (P *Parser) TryType() bool {
+ P.Trace("Type (try)");
switch P.tok {
case Scanner.IDENT:
P.ParseTypeName();
case Scanner.MUL:
P.ParsePointerType();
default:
- P.Error("type expected");
+ P.Ecart();
+ return false;
}
P.Ecart();
+ return true;
}
P.Next();
P.ParseImportSpec();
}
- if P.tok == Scanner.SEMICOLON {
- P.Next();
- }
+ P.Optional(Scanner.SEMICOLON);
} else {
P.ParseImportSpec();
}
func (P *Parser) ParseConstSpec() {
P.Trace("ConstSpec");
P.ParseIdent();
- // TODO factor this code
- switch P.tok {
- case Scanner.IDENT, Scanner.LBRACK, Scanner.CHAN, Scanner.INTERFACE,
- Scanner.FUNC, Scanner.MAP, Scanner.STRUCT, Scanner.MUL:
- P.ParseType();
- default:
- break;
- }
+ P.TryType();
if P.tok == Scanner.ASSIGN {
P.Next();
P.ParseExpression();
P.Trace("ConstDecl");
P.Expect(Scanner.CONST);
if P.tok == Scanner.LPAREN {
- P.ParseConstSpec();
- for P.tok == Scanner.SEMICOLON {
- P.Next();
+ P.Next();
+ for P.tok != Scanner.RPAREN {
P.ParseConstSpec();
+ if P.tok != Scanner.RPAREN {
+ P.Expect(Scanner.SEMICOLON);
+ }
}
- if P.tok == Scanner.SEMICOLON {
- P.Next();
- }
+ P.Next();
} else {
P.ParseConstSpec();
}
func (P *Parser) ParseTypeSpec() {
P.Trace("TypeSpec");
P.ParseIdent();
- // TODO factor this code
- switch P.tok {
- case Scanner.IDENT, Scanner.LBRACK, Scanner.CHAN, Scanner.INTERFACE,
- Scanner.FUNC, Scanner.MAP, Scanner.STRUCT, Scanner.MUL:
- P.ParseType();
- default:
- break;
- }
+ P.TryType();
P.Ecart();
}
P.Trace("TypeDecl");
P.Expect(Scanner.TYPE);
if P.tok == Scanner.LPAREN {
- P.ParseTypeSpec();
- for P.tok == Scanner.SEMICOLON {
- P.Next();
+ P.Next();
+ for P.tok != Scanner.RPAREN {
P.ParseTypeSpec();
+ if P.tok != Scanner.RPAREN {
+ P.Expect(Scanner.SEMICOLON);
+ }
}
- if P.tok == Scanner.SEMICOLON {
- P.Next();
- }
+ P.Next();
} else {
P.ParseTypeSpec();
}
P.Trace("VarDecl");
P.Expect(Scanner.VAR);
if P.tok == Scanner.LPAREN {
- P.ParseVarSpec();
- for P.tok == Scanner.SEMICOLON {
- P.Next();
+ P.Next();
+ for P.tok != Scanner.RPAREN {
P.ParseVarSpec();
+ if P.tok != Scanner.RPAREN {
+ P.Expect(Scanner.SEMICOLON);
+ }
}
- if P.tok == Scanner.SEMICOLON {
- P.Next();
- }
+ P.Next();
} else {
P.ParseVarSpec();
}
func (P *Parser) ParseDeclaration();
-func (P *Parser) ParseStatement() bool;
+func (P *Parser) TryStatement() bool;
func (P *Parser) ParseStatementList();
func (P *Parser) ParseBlock();
func (P *Parser) ParsePrimaryExpr();
func (P *Parser) ParseSimpleStat() {
P.Trace("SimpleStat");
P.ParseExpression();
- switch P.tok {
- case Scanner.ASSIGN: fallthrough;
- case Scanner.DEFINE:
+ if P.tok == Scanner.COLON {
P.Next();
- P.ParseExpression();
- case Scanner.COMMA:
+ P.Ecart();
+ return;
+ }
+ if P.tok == Scanner.COMMA {
P.Next();
P.ParsePrimaryExprList();
- switch P.tok {
- case Scanner.ASSIGN:
- case Scanner.ADD_ASSIGN:
- case Scanner.SUB_ASSIGN:
- case Scanner.MUL_ASSIGN:
- case Scanner.QUO_ASSIGN:
- case Scanner.REM_ASSIGN:
- case Scanner.AND_ASSIGN:
- case Scanner.OR_ASSIGN:
- case Scanner.XOR_ASSIGN:
- case Scanner.SHL_ASSIGN:
- case Scanner.SHR_ASSIGN:
- break;
- default:
- P.Error("expected assignment operand");
- }
+ }
+ switch P.tok {
+ case Scanner.ASSIGN: fallthrough;
+ case Scanner.DEFINE: fallthrough;
+ case Scanner.ADD_ASSIGN: fallthrough;
+ case Scanner.SUB_ASSIGN: fallthrough;
+ case Scanner.MUL_ASSIGN: fallthrough;
+ case Scanner.QUO_ASSIGN: fallthrough;
+ case Scanner.REM_ASSIGN: fallthrough;
+ case Scanner.AND_ASSIGN: fallthrough;
+ case Scanner.OR_ASSIGN: fallthrough;
+ case Scanner.XOR_ASSIGN: fallthrough;
+ case Scanner.SHL_ASSIGN: fallthrough;
+ case Scanner.SHR_ASSIGN:
P.Next();
P.ParseExpressionList();
case Scanner.INC:
}
+func (P *Parser) ParseGoStat() {
+ P.Trace("GoStat");
+ P.Expect(Scanner.GO);
+ P.ParseExpression();
+}
+
+
func (P *Parser) ParseReturnStat() {
P.Trace("ReturnStat");
P.Expect(Scanner.RETURN);
}
-func (P *Parser) ParseBreakStat() {
- P.Trace("BreakStat");
- P.Expect(Scanner.BREAK);
+func (P *Parser) ParseControlFlowStat(tok int) {
+ P.Trace("ControlFlowStat");
+ P.Expect(tok);
if P.tok == Scanner.IDENT {
P.ParseIdent();
}
}
-func (P *Parser) ParseContinueStat() {
- P.Trace("ContinueStat");
- P.Expect(Scanner.CONTINUE);
- if P.tok == Scanner.IDENT {
- P.ParseIdent();
+func (P *Parser) ParseStatement() {
+ P.Trace("Statement");
+ if !P.TryStatement() {
+ P.Error("statement expected");
}
P.Ecart();
}
if P.tok != Scanner.LBRACE {
P.ParseSimpleStat();
if P.tok == Scanner.SEMICOLON {
+ P.Next();
P.ParseExpression();
}
}
P.ParseIfStat();
} else {
// TODO should be P.ParseBlock()
- if !P.ParseStatement() {
- P.Error("statement expected");
- }
+ P.ParseStatement();
}
}
P.Ecart();
P.ParseCaseList();
if P.tok != Scanner.FALLTHROUGH && P.tok != Scanner.RBRACE {
P.ParseStatementList();
- if P.tok == Scanner.SEMICOLON {
- P.Next();
- }
+ P.Optional(Scanner.SEMICOLON);
}
if P.tok == Scanner.FALLTHROUGH {
P.Next();
- if P.tok == Scanner.SEMICOLON {
- P.Next();
- }
+ P.Optional(Scanner.SEMICOLON);
}
P.Ecart();
}
if P.tok != Scanner.LBRACE {
P.ParseSimpleStat();
if P.tok == Scanner.SEMICOLON {
+ P.Next();
P.ParseExpression();
}
}
}
-func (P *Parser) ParseStatement() bool {
- P.Trace("Statement");
+func (P *Parser) TryStatement() bool {
+ P.Trace("Statement (try)");
switch P.tok {
case Scanner.CONST: fallthrough;
case Scanner.TYPE: fallthrough;
case Scanner.VAR: fallthrough;
case Scanner.FUNC:
P.ParseDeclaration();
+ case Scanner.GTR:
+ P.ParseSimpleStat(); // send
case Scanner.IDENT:
switch P.ident {
case "print", "panic":
P.ParseSimpleStat();
}
case Scanner.GO:
- panic "go statement";
+ P.ParseGoStat();
case Scanner.RETURN:
P.ParseReturnStat();
- case Scanner.BREAK:
- P.ParseBreakStat();
- case Scanner.CONTINUE:
- P.ParseContinueStat();
- case Scanner.GOTO:
- panic "goto statement";
+ case Scanner.BREAK, Scanner.CONTINUE, Scanner.GOTO:
+ P.ParseControlFlowStat(P.tok);
case Scanner.LBRACE:
P.ParseBlock();
case Scanner.IF:
func (P *Parser) ParseStatementList() {
P.Trace("StatementList");
- for P.ParseStatement() {
- if P.tok == Scanner.SEMICOLON {
- P.Next();
- }
+ for P.TryStatement() {
+ P.Optional(Scanner.SEMICOLON);
}
P.Ecart();
}
if P.tok != Scanner.RBRACE && P.tok != Scanner.SEMICOLON {
P.ParseStatementList();
}
- if P.tok == Scanner.SEMICOLON {
- P.Next();
- }
+ P.Optional(Scanner.SEMICOLON);
P.Expect(Scanner.RBRACE);
P.Ecart();
}
P.Next();
P.ParseIdent();
}
+ P.Optional(Scanner.COMMA);
P.Ecart();
}
P.ParseExportDecl();
default:
P.Error("declaration expected");
- P.Next(); // make progress
}
P.Ecart();
}
case Scanner.LPAREN:
P.Next();
P.ParseExpression();
- P.Expect(Scanner.LPAREN);
+ P.Expect(Scanner.RPAREN);
+ case Scanner.NIL: fallthrough;
case Scanner.IOTA: fallthrough;
case Scanner.TRUE: fallthrough;
case Scanner.FALSE:
case Scanner.SHL: fallthrough;
case Scanner.SHR: fallthrough;
case Scanner.AND:
+ P.Next();
P.ParseUnaryExpr();
default:
P.Ecart();
case Scanner.SUB: fallthrough;
case Scanner.OR: fallthrough;
case Scanner.XOR:
+ P.Next();
P.ParseMultiplicativeExpr();
default:
P.Ecart();
P.ParseIdent();
for P.tok == Scanner.IMPORT {
P.ParseImportDecl();
- if P.tok == Scanner.SEMICOLON {
- P.Next();
- }
+ P.Optional(Scanner.SEMICOLON);
}
for P.tok != Scanner.EOF {
P.ParseDeclaration();
- if P.tok == Scanner.SEMICOLON {
- P.Next();
- }
+ P.Optional(Scanner.SEMICOLON);
}
P.Ecart();
}