1
0
mirror of https://github.com/golang/go synced 2024-09-25 13:20:13 -06:00

- simplified parsing of composite literals and slices by

treating ":" as lowest-level binary operator
- more precise error message for composites
- added flag -columns (false) - when set, prints precise error column
- a few more tests

R=r
OCL=17428
CL=17428
This commit is contained in:
Robert Griesemer 2008-10-18 20:20:30 -07:00
parent e45eb60657
commit 52e9080d56
4 changed files with 56 additions and 62 deletions

View File

@ -161,7 +161,7 @@ func (P *Parser) NewExpr(pos, tok int, x, y *Node.Expr) *Node.Expr {
// Common productions // Common productions
func (P *Parser) TryType() *Node.Type; func (P *Parser) TryType() *Node.Type;
func (P *Parser) ParseExpression() *Node.Expr; func (P *Parser) ParseExpression(prec int) *Node.Expr;
func (P *Parser) ParseStatement() *Node.Stat; func (P *Parser) ParseStatement() *Node.Stat;
func (P *Parser) ParseDeclaration() *Node.Decl; func (P *Parser) ParseDeclaration() *Node.Decl;
@ -262,7 +262,7 @@ func (P *Parser) ParseArrayType() *Node.Type {
t := Node.NewType(P.pos, Scanner.LBRACK); t := Node.NewType(P.pos, Scanner.LBRACK);
P.Expect(Scanner.LBRACK); P.Expect(Scanner.LBRACK);
if P.tok != Scanner.RBRACK { if P.tok != Scanner.RBRACK {
t.expr = P.ParseExpression(); t.expr = P.ParseExpression(1);
} }
P.Expect(Scanner.RBRACK); P.Expect(Scanner.RBRACK);
t.elt = P.ParseType(); t.elt = P.ParseType();
@ -603,7 +603,7 @@ func (P *Parser) ParseBlock() *Node.List {
func (P *Parser) ParseExpressionList() *Node.Expr { func (P *Parser) ParseExpressionList() *Node.Expr {
P.Trace("ExpressionList"); P.Trace("ExpressionList");
x := P.ParseExpression(); x := P.ParseExpression(1);
if P.tok == Scanner.COMMA { if P.tok == Scanner.COMMA {
pos := P.pos; pos := P.pos;
P.Next(); P.Next();
@ -644,7 +644,7 @@ func (P *Parser) ParseOperand() *Node.Expr {
// (currently not working) // (currently not working)
P.Next(); P.Next();
P.expr_lev++; P.expr_lev++;
x = P.ParseExpression(); x = P.ParseExpression(1);
P.expr_lev--; P.expr_lev--;
P.Expect(Scanner.RPAREN); P.Expect(Scanner.RPAREN);
@ -695,31 +695,12 @@ func (P *Parser) ParseSelectorOrTypeGuard(x *Node.Expr) *Node.Expr {
} }
// mode = 0: single or pair accepted
// mode = 1: single only accepted
// mode = 2: pair only accepted
func (P *Parser) ParseExpressionPair(mode int) *Node.Expr {
P.Trace("ExpressionPair");
x := P.ParseExpression();
if mode == 0 && P.tok == Scanner.COLON || mode == 2 {
pos := P.pos;
P.Expect(Scanner.COLON);
y := P.ParseExpression();
x = P.NewExpr(pos, Scanner.COLON, x, y);
}
P.Ecart();
return x;
}
func (P *Parser) ParseIndex(x *Node.Expr) *Node.Expr { func (P *Parser) ParseIndex(x *Node.Expr) *Node.Expr {
P.Trace("IndexOrSlice"); P.Trace("IndexOrSlice");
pos := P.pos; pos := P.pos;
P.Expect(Scanner.LBRACK); P.Expect(Scanner.LBRACK);
i := P.ParseExpressionPair(0); i := P.ParseExpression(0);
P.Expect(Scanner.RBRACK); P.Expect(Scanner.RBRACK);
P.Ecart(); P.Ecart();
@ -736,7 +717,7 @@ func (P *Parser) ParseCall(x *Node.Expr) *Node.Expr {
P.Expect(Scanner.LPAREN); P.Expect(Scanner.LPAREN);
if P.tok != Scanner.RPAREN { if P.tok != Scanner.RPAREN {
// the very first argument may be a type if the function called is new() // the very first argument may be a type if the function called is new()
// call ParseBinaryExpr() which allows type expressions // call ParseBinaryExpr() which allows type expressions (instead of ParseExpression)
y := P.ParseBinaryExpr(1); y := P.ParseBinaryExpr(1);
if P.tok == Scanner.COMMA { if P.tok == Scanner.COMMA {
pos := P.pos; pos := P.pos;
@ -756,29 +737,34 @@ func (P *Parser) ParseCall(x *Node.Expr) *Node.Expr {
} }
// TODO make this non-recursive func (P *Parser) ParseCompositeList(mode int) *Node.Expr {
func (P *Parser) ParseExpressionPairList(mode int) *Node.Expr { x := P.ParseExpression(0);
P.Trace("ExpressionPairList");
x := P.ParseExpressionPair(mode); switch mode {
if mode == 0 { case 0: // first element determines mode
// first expression determines mode mode = 1;
if x.tok == Scanner.COLON { if x.tok == Scanner.COLON {
mode = 2; mode = 2;
} else { }
mode = 1; case 1:
if x.tok == Scanner.COLON {
P.Error(x.x.pos, "single value expected; found pair");
}
case 2:
if x.tok != Scanner.COLON {
P.Error(x.pos, "key:value pair expected; found single value");
} }
} }
if P.tok == Scanner.COMMA { if P.tok == Scanner.COMMA {
pos := P.pos; pos := P.pos;
P.Next(); P.Next();
if P.tok != Scanner.RBRACE && P.tok != Scanner.EOF { if P.tok != Scanner.RBRACE {
y := P.ParseExpressionPairList(mode); y := P.ParseCompositeList(mode);
x = P.NewExpr(pos, Scanner.COMMA, x, y); x = P.NewExpr(pos, Scanner.COMMA, x, y);
} }
} }
P.Ecart();
return x; return x;
} }
@ -790,7 +776,7 @@ func (P *Parser) ParseCompositeLit(t *Node.Type) *Node.Expr {
x.t = t; x.t = t;
P.Expect(Scanner.LBRACE); P.Expect(Scanner.LBRACE);
if P.tok != Scanner.RBRACE { if P.tok != Scanner.RBRACE {
x.y = P.ParseExpressionPairList(0); x.y = P.ParseCompositeList(0);
} }
P.Expect(Scanner.RBRACE); P.Expect(Scanner.RBRACE);
@ -876,11 +862,14 @@ func (P *Parser) ParseBinaryExpr(prec1 int) *Node.Expr {
} }
func (P *Parser) ParseExpression() *Node.Expr { func (P *Parser) ParseExpression(prec int) *Node.Expr {
P.Trace("Expression"); P.Trace("Expression");
indent := P.indent; indent := P.indent;
x := P.NoType(P.ParseBinaryExpr(1)); if prec < 0 {
panic("precedence must be >= 0");
}
x := P.NoType(P.ParseBinaryExpr(prec));
if indent != P.indent { if indent != P.indent {
panic("imbalanced tracing code (Expression)"); panic("imbalanced tracing code (Expression)");
@ -948,7 +937,7 @@ func (P *Parser) ParseGoStat() *Node.Stat {
s := Node.NewStat(P.pos, Scanner.GO); s := Node.NewStat(P.pos, Scanner.GO);
P.Expect(Scanner.GO); P.Expect(Scanner.GO);
s.expr = P.ParseExpression(); s.expr = P.ParseExpression(1);
P.Ecart(); P.Ecart();
return s; return s;
@ -997,7 +986,7 @@ func (P *Parser) ParseControlClause(keyword int) *Node.Stat {
if P.tok == Scanner.SEMICOLON { if P.tok == Scanner.SEMICOLON {
P.Next(); P.Next();
if P.tok != Scanner.SEMICOLON && P.tok != Scanner.LBRACE { if P.tok != Scanner.SEMICOLON && P.tok != Scanner.LBRACE {
s.expr = P.ParseExpression(); s.expr = P.ParseExpression(1);
} }
if keyword == Scanner.FOR { if keyword == Scanner.FOR {
P.Expect(Scanner.SEMICOLON); P.Expect(Scanner.SEMICOLON);
@ -1117,11 +1106,11 @@ func (P *Parser) ParseCommCase() *Node.Stat {
s := Node.NewStat(P.pos, Scanner.CASE); s := Node.NewStat(P.pos, Scanner.CASE);
if P.tok == Scanner.CASE { if P.tok == Scanner.CASE {
P.Next(); P.Next();
P.ParseExpression(); P.ParseExpression(1);
if P.tok == Scanner.ASSIGN || P.tok == Scanner.DEFINE { if P.tok == Scanner.ASSIGN || P.tok == Scanner.DEFINE {
P.Next(); P.Next();
P.Expect(Scanner.ARROW); P.Expect(Scanner.ARROW);
P.ParseExpression(); P.ParseExpression(1);
} }
} else { } else {
P.Expect(Scanner.DEFAULT); P.Expect(Scanner.DEFAULT);
@ -1171,7 +1160,7 @@ func (P *Parser) ParseRangeStat() *Node.Stat {
P.Expect(Scanner.RANGE); P.Expect(Scanner.RANGE);
P.ParseIdentList(); P.ParseIdentList();
P.Expect(Scanner.DEFINE); P.Expect(Scanner.DEFINE);
s.expr = P.ParseExpression(); s.expr = P.ParseExpression(1);
s.block = P.ParseBlock(); s.block = P.ParseBlock();
P.Ecart(); P.Ecart();
@ -1265,7 +1254,7 @@ func (P *Parser) ParseConstSpec(exported bool) *Node.Decl {
d.typ = P.TryType(); d.typ = P.TryType();
if P.tok == Scanner.ASSIGN { if P.tok == Scanner.ASSIGN {
P.Next(); P.Next();
d.val = P.ParseExpression(); d.val = P.ParseExpression(1);
} }
P.Ecart(); P.Ecart();

View File

@ -15,6 +15,7 @@ var (
silent = Flag.Bool("s", false, nil, "silent mode: no pretty print output"); silent = Flag.Bool("s", false, nil, "silent mode: no pretty print output");
verbose = Flag.Bool("v", false, nil, "verbose mode: trace parsing"); verbose = Flag.Bool("v", false, nil, "verbose mode: trace parsing");
sixg = Flag.Bool("6g", true, nil, "6g compatibility mode"); sixg = Flag.Bool("6g", true, nil, "6g compatibility mode");
columns = Flag.Bool("columns", Platform.USER == "gri", nil, "print column info in error messages");
testmode = Flag.Bool("t", false, nil, "test mode: interprets /* ERROR */ and /* SYNC */ comments"); testmode = Flag.Bool("t", false, nil, "test mode: interprets /* ERROR */ and /* SYNC */ comments");
tokenchan = Flag.Bool("token_chan", false, nil, "use token channel for scanner-parser connection"); tokenchan = Flag.Bool("token_chan", false, nil, "use token channel for scanner-parser connection");
) )
@ -45,7 +46,7 @@ func main() {
} }
scanner := new(Scanner.Scanner); scanner := new(Scanner.Scanner);
scanner.Open(src_file, src, testmode.BVal()); scanner.Open(src_file, src, columns.BVal(), testmode.BVal());
var tstream *<-chan *Scanner.Token; var tstream *<-chan *Scanner.Token;
if tokenchan.BVal() { if tokenchan.BVal() {

View File

@ -3,8 +3,6 @@
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
package Scanner package Scanner
import Platform "platform"
import Utils "utils" import Utils "utils"
@ -213,8 +211,9 @@ export func TokenString(tok int) string {
export func Precedence(tok int) int { export func Precedence(tok int) int {
// TODO should use a map or array here for lookup
switch tok { switch tok {
case COLON:
return 0;
case LOR: case LOR:
return 1; return 1;
case LAND: case LAND:
@ -228,23 +227,18 @@ export func Precedence(tok int) int {
case MUL, QUO, REM, SHL, SHR, AND: case MUL, QUO, REM, SHL, SHR, AND:
return 6; return 6;
} }
return 0; return -1;
} }
var Keywords *map [string] int; var Keywords *map [string] int;
var VerboseMsgs bool; // error message customization
func init() { func init() {
Keywords = new(map [string] int); Keywords = new(map [string] int);
for i := KEYWORDS_BEG + 1; i < KEYWORDS_END; i++ { for i := KEYWORDS_BEG + 1; i < KEYWORDS_END; i++ {
Keywords[TokenString(i)] = i; Keywords[TokenString(i)] = i;
} }
// Provide column information in error messages for gri only...
VerboseMsgs = Platform.USER == "gri";
} }
@ -277,7 +271,8 @@ export type Scanner struct {
filename string; // error reporting only filename string; // error reporting only
nerrors int; // number of errors nerrors int; // number of errors
errpos int; // last error position errpos int; // last error position
columns bool; // if set, print columns in error messages
// scanning // scanning
src string; // scanned source src string; // scanned source
pos int; // current reading position pos int; // current reading position
@ -416,7 +411,7 @@ func (S *Scanner) ErrorMsg(pos int, msg string) {
if pos >= 0 { if pos >= 0 {
// print position // print position
line, col := S.LineCol(pos); line, col := S.LineCol(pos);
if VerboseMsgs { if S.columns {
print(":", line, ":", col); print(":", line, ":", col);
} else { } else {
print(":", line); print(":", line);
@ -464,13 +459,14 @@ func (S *Scanner) ExpectNoErrors() {
} }
func (S *Scanner) Open(filename, src string, testmode bool) { func (S *Scanner) Open(filename, src string, columns, testmode bool) {
S.filename = filename; S.filename = filename;
S.nerrors = 0; S.nerrors = 0;
S.errpos = 0; S.errpos = 0;
S.src = src; S.src = src;
S.pos = 0; S.pos = 0;
S.columns = columns;
S.testmode = testmode; S.testmode = testmode;
S.ExpectNoErrors(); // after setting S.src S.ExpectNoErrors(); // after setting S.src

View File

@ -18,13 +18,21 @@ func /* ERROR receiver */ () f0() {} /* SYNC */
func /* ERROR receiver */ (*S0, *S0) f1() {} /* SYNC */ func /* ERROR receiver */ (*S0, *S0) f1() {} /* SYNC */
func f0(a b, c /* ERROR type */ ) {} func f0(a b, c /* ERROR type */ ) /* SYNC */ {}
func f1() { func f1() {
} }
func CompositeLiterals() {
a1 := []int{};
a2 := []int{0, 1, 2, };
a3 := []int{0, 1, 2, /* ERROR single value expected */ 3 : 4, 5}; /* SYNC */
a1 := []int{0 : 1, 2 : 3, /* ERROR key:value pair expected */ 4, }; /* SYNC */
}
func main () { func main () {
} }