P.tok, P.pos, P.val = t.tok, t.pos, t.val;
}
P.opt_semi = false;
+
if P.verbose {
P.PrintIndent();
print("[", P.pos, "] ", Scanner.TokenString(P.tok), "\n");
func (P *Parser) Next() {
for P.Next0(); P.tok == Scanner.COMMENT; P.Next0() {
P.comments.Add(Node.NewComment(P.pos, P.val));
+ if P.val == "/*ERROR*/" {
+ // the position of the next token is the position of the next expected error
+
+ } else if P.val == "/*SYNC*/" {
+ // synchronized at the next token
+
+ }
}
}
}
+// ----------------------------------------------------------------------------
+// AST support
+
+func ExprType(x *Node.Expr) *Node.Type {
+ var t *Node.Type;
+ if x.tok == Scanner.TYPE {
+ t = x.t;
+ } else if x.tok == Scanner.IDENT {
+ // assume a type name
+ t = Node.NewType(x.pos, Scanner.IDENT);
+ t.expr = x;
+ } else if x.tok == Scanner.PERIOD && x.y != nil && ExprType(x.x) != nil {
+ // possibly a qualified (type) identifier
+ t = Node.NewType(x.pos, Scanner.IDENT);
+ t.expr = x;
+ }
+ return t;
+}
+
+
func (P *Parser) NoType(x *Node.Expr) *Node.Expr {
if x != nil && x.tok == Scanner.TYPE {
P.Error(x.pos, "expected expression, found type");
func (P *Parser) ParseIdent() *Node.Expr {
P.Trace("Ident");
- var x *Node.Expr;
+ x := Node.BadExpr;
if P.tok == Scanner.IDENT {
x = Node.NewLit(P.pos, Scanner.IDENT, P.val);
if P.verbose {
func (P *Parser) ParseType() *Node.Type {
P.Trace("Type");
- typ := P.TryType();
- if typ == nil {
+ t := P.TryType();
+ if t == nil {
P.Error(P.pos, "type expected");
+ t = Node.BadType;
}
P.Ecart();
- return typ;
+ return t;
}
}
-// Returns nil if no type was found.
func (P *Parser) TryType() *Node.Type {
P.Trace("Type (try)");
- var t *Node.Type;
+ t := Node.BadType;
switch P.tok {
case Scanner.IDENT: t = P.ParseTypeName();
case Scanner.LBRACK: t = P.ParseArrayType();
case Scanner.MAP: t = P.ParseMapType();
case Scanner.STRUCT: t = P.ParseStructType();
case Scanner.MUL: t = P.ParsePointerType();
+ default: t = nil; // no type found
}
P.Ecart();
list := Node.NewList();
for P.tok != Scanner.CASE && P.tok != Scanner.DEFAULT && P.tok != Scanner.RBRACE && P.tok != Scanner.EOF {
- list.Add(P.ParseStatement());
+ s := P.ParseStatement();
+ if s != nil {
+ // not the empty statement
+ list.Add(s);
+ }
if P.tok == Scanner.SEMICOLON {
P.Next();
} else if P.opt_semi {
// ----------------------------------------------------------------------------
// Expressions
-// TODO: Make this non-recursive.
+// TODO make this non-recursive
func (P *Parser) ParseExpressionList() *Node.Expr {
P.Trace("ExpressionList");
func (P *Parser) ParseFunctionLit() *Node.Expr {
P.Trace("FunctionLit");
+ x := Node.NewLit(P.pos, Scanner.FUNC, "");
P.Expect(Scanner.FUNC);
- P.ParseFunctionType();
+ x.t = P.ParseFunctionType();
P.scope_lev++;
- P.ParseBlock();
+ x.block = P.ParseBlock();
P.scope_lev--;
P.Ecart();
- return Node.NewLit(P.pos, Scanner.INT, "0"); // "null" expr
+ return x;
}
func (P *Parser) ParseOperand() *Node.Expr {
P.Trace("Operand");
- var x *Node.Expr;
+ x := Node.BadExpr;
switch P.tok {
case Scanner.IDENT:
x = P.ParseIdent();
case Scanner.LPAREN:
+ // TODO we could have a function type here as in: new(*())
+ // (currently not working)
P.Next();
P.expr_lev++;
x = P.ParseExpression();
} else {
P.Error(P.pos, "operand expected");
P.Next(); // make progress
- x = Node.NewLit(P.pos, Scanner.INT, "0"); // "null" expr
}
}
}
+// TODO make this non-recursive
func (P *Parser) ParseExpressionPairList(mode int) *Node.Expr {
P.Trace("ExpressionPairList");
func (P *Parser) ParseCompositeLit(t *Node.Type) *Node.Expr {
P.Trace("CompositeLit");
- pos := P.pos;
- P.Expect(Scanner.LBRACE);
- x := P.NewExpr(pos, Scanner.LBRACE, nil, P.ParseExpressionPairList(0));
+ x := P.NewExpr(P.pos, Scanner.LBRACE, nil, nil);
x.t = t;
+ P.Expect(Scanner.LBRACE);
+ if P.tok != Scanner.RBRACE {
+ x.y = P.ParseExpressionPairList(0);
+ }
P.Expect(Scanner.RBRACE);
P.Ecart();
// (composites inside control clauses must be parenthesized)
var t *Node.Type;
if P.expr_lev > 0 {
- if x.tok == Scanner.TYPE {
- t = x.t;
- } else if x.tok == Scanner.IDENT {
- // assume a type name
- t = Node.NewType(x.pos, Scanner.IDENT);
- t.expr = x;
- }
+ t = ExprType(x);
}
if t != nil {
x = P.ParseCompositeLit(t);
default: goto exit;
}
}
+
exit:
-
P.Ecart();
return x;
}
func (P *Parser) ParseUnaryExpr() *Node.Expr {
P.Trace("UnaryExpr");
- var x *Node.Expr;
+ x := Node.BadExpr;
switch P.tok {
case Scanner.ADD, Scanner.SUB, Scanner.MUL, Scanner.NOT, Scanner.XOR, Scanner.ARROW, Scanner.AND:
pos, tok := P.pos, P.tok;
func (P *Parser) ParseSimpleStat() *Node.Stat {
P.Trace("SimpleStat");
- var s *Node.Stat;
-
+ s := Node.BadStat;
x := P.ParseExpressionList();
switch P.tok {
pos, tok = P.pos, P.tok;
P.Next();
} else {
- pos, tok = x.pos, 0; // TODO give this a token value
+ pos, tok = x.pos, Scanner.EXPRSTAT;
}
s = Node.NewStat(pos, tok);
s.expr = x;
s.post = P.ParseIfStat();
} else {
// For 6g compliance - should really be P.ParseBlock()
- t := P.ParseStatement();
- if t.tok != Scanner.LBRACE {
- // wrap in a block if we don't have one
- t1 := Node.NewStat(P.pos, Scanner.LBRACE);
- t1.block = Node.NewList();
- t1.block.Add(t);
- t = t1;
+ s1 := P.ParseStatement();
+ if s1 != nil {
+ // not the empty statement
+ if s1.tok != Scanner.LBRACE {
+ // wrap in a block if we don't have one
+ b := Node.NewStat(P.pos, Scanner.LBRACE);
+ b.block = Node.NewList();
+ b.block.Add(s1);
+ s1 = b;
+ }
+ s.post = s1;
}
- s.post = t;
}
}
}
-func (P *Parser) ParseEmptyStat() {
- P.Trace("EmptyStat");
- P.Ecart();
-}
-
-
func (P *Parser) ParseStatement() *Node.Stat {
P.Trace("Statement");
indent := P.indent;
- var s *Node.Stat;
+ s := Node.BadStat;
switch P.tok {
case Scanner.CONST, Scanner.TYPE, Scanner.VAR:
s = Node.NewStat(P.pos, P.tok);
case Scanner.SELECT:
s = P.ParseSelectStat();
default:
- P.ParseEmptyStat(); // for complete tracing output only
+ // empty statement
+ s = nil;
}
if indent != P.indent {
}
-// TODO Replace this by using function pointers derived from methods.
+// TODO replace this by using function pointers derived from methods
func (P *Parser) ParseSpec(exported bool, keyword int) *Node.Decl {
switch keyword {
case Scanner.IMPORT: return P.ParseImportSpec();
func (P *Parser) ParseDecl(exported bool, keyword int) *Node.Decl {
P.Trace("Decl");
- var d *Node.Decl;
+ d := Node.BadDecl;
P.Expect(keyword);
if P.tok == Scanner.LPAREN {
P.Next();
func (P *Parser) ParseExportDecl() *Node.Decl {
P.Trace("ExportDecl");
- // TODO This is deprecated syntax and should go away eventually.
- // (Also at the moment the syntax is everything goes...)
- //P.Expect(Scanner.EXPORT);
-
d := Node.NewDecl(P.pos, Scanner.EXPORT, false);
-
- has_paren := false;
- if P.tok == Scanner.LPAREN {
- P.Next();
- has_paren = true;
- }
d.ident = P.ParseIdentList();
- /*
- for P.tok == Scanner.IDENT {
- P.ParseIdent();
- if P.tok == Scanner.COMMA {
- P.Next(); // TODO this seems wrong
- }
- }
- */
- if has_paren {
- P.Expect(Scanner.RPAREN)
- }
-
+
P.Ecart();
return d;
}
P.Trace("Declaration");
indent := P.indent;
- var d *Node.Decl;
-
+ d := Node.BadDecl;
exported := false;
if P.tok == Scanner.EXPORT {
if P.scope_lev == 0 {
P.semi, P.newl = false, 1;
}
+func (P *Printer) Error(pos int, tok int, msg string) {
+ P.String(0, "<");
+ P.Token(pos, tok);
+ P.String(0, " " + msg + ">");
+}
+
// ----------------------------------------------------------------------------
// Types
func (P *Printer) Type(t *Node.Type) {
- if t == nil { // TODO remove this check
- P.String(0, "<nil type>");
- return;
- }
-
switch t.tok {
case Scanner.IDENT:
P.Expr(t.expr);
}
default:
- panic("UNREACHABLE");
+ P.Error(t.pos, t.tok, "type");
}
}
// ----------------------------------------------------------------------------
// Expressions
+func (P *Printer) Block(list *Node.List, indent bool);
+
func (P *Printer) Expr1(x *Node.Expr, prec1 int) {
if x == nil {
return; // empty expression list
// literal
P.String(x.pos, x.s);
+ case Scanner.FUNC:
+ // function literal
+ P.String(x.pos, "func");
+ P.Type(x.t);
+ P.Block(x.block, true);
+ P.newl = 0;
+
case Scanner.COMMA:
// list
P.Expr1(x.x, 0);
func (P *Printer) Declaration(d *Node.Decl, parenthesized bool);
func (P *Printer) Stat(s *Node.Stat) {
- if s == nil { // TODO remove this check
- P.String(0, "<nil stat>");
- return;
- }
-
switch s.tok {
- case 0: // TODO use a real token const
+ case Scanner.EXPRSTAT:
// expression statement
P.Expr(s.expr);
P.semi = true;
P.semi = true;
default:
- P.String(s.pos, "<stat>");
- P.semi = true;
+ P.Error(s.pos, s.tok, "stat");
}
}
func (P *Printer) Declaration(d *Node.Decl, parenthesized bool) {
- if d == nil { // TODO remove this check
- P.String(0, "<nil decl>");
- return;
- }
-
if !parenthesized {
if d.exported {
P.String(0, "export ");
TYPE;
VAR;
KEYWORDS_END;
+
+ // AST use only
+ EXPRSTAT;
)
case SWITCH: return "switch";
case TYPE: return "type";
case VAR: return "var";
+
+ case EXPRSTAT: return "EXPRSTAT";
}
return "token(" + Utils.IntToString(tok, 10) + ")";
export type Scanner struct {
+ // error handling
filename string; // error reporting only
nerrors int; // number of errors
errpos int; // last error position
-
+
+ // scanning
src string; // scanned source
pos int; // current reading position
ch int; // one char look-ahead
}
+func (S *Scanner) ErrorMsg(pos int, msg string) {
+ print(S.filename);
+ if pos >= 0 {
+ // print position
+ line, col := S.LineCol(pos);
+ if VerboseMsgs {
+ print(":", line, ":", col);
+ } else {
+ print(":", line);
+ }
+ }
+ print(": ", msg, "\n");
+}
+
+
func (S *Scanner) Error(pos int, msg string) {
const errdist = 10;
delta := pos - S.errpos; // may be negative!
if delta < 0 {
delta = -delta;
}
+
if delta > errdist || S.nerrors == 0 /* always report first error */ {
- print(S.filename);
- if pos >= 0 {
- // print position
- line, col := S.LineCol(pos);
- if VerboseMsgs {
- print(":", line, ":", col);
- } else {
- print(":", line);
- }
- }
- print(": ", msg, "\n");
+ S.ErrorMsg(pos, msg);
S.nerrors++;
S.errpos = pos;
}