Commit 3997495d authored by Russ Cox's avatar Russ Cox

gc: semicolons

Fixes #89.
Fixes #92.
Fixes #118.
Fixes #182.
Fixes #328.
Fixes #340.

R=ken2, ken3
CC=golang-dev
https://golang.org/cl/172049
parent cd00bc78
...@@ -548,6 +548,7 @@ struct Io ...@@ -548,6 +548,7 @@ struct Io
char* infile; char* infile;
Biobuf* bin; Biobuf* bin;
int32 ilineno; int32 ilineno;
int nlsemi;
int peekc; int peekc;
int peekc1; // second peekc for ... int peekc1; // second peekc for ...
char* cp; // used for content when bin==nil char* cp; // used for content when bin==nil
...@@ -725,7 +726,6 @@ void importfile(Val*, int line); ...@@ -725,7 +726,6 @@ void importfile(Val*, int line);
void cannedimports(char*, char*); void cannedimports(char*, char*);
void unimportfile(); void unimportfile();
int32 yylex(void); int32 yylex(void);
void yyoptsemi(int);
void typeinit(void); void typeinit(void);
void lexinit(void); void lexinit(void);
char* lexname(int); char* lexname(int);
...@@ -1128,10 +1128,6 @@ EXTERN Prog* breakpc; ...@@ -1128,10 +1128,6 @@ EXTERN Prog* breakpc;
EXTERN Prog* pc; EXTERN Prog* pc;
EXTERN Prog* firstpc; EXTERN Prog* firstpc;
EXTERN int yylast;
EXTERN int yynext;
EXTERN int yysemi;
void allocparams(void); void allocparams(void);
void cgen_as(Node *nl, Node *nr); void cgen_as(Node *nl, Node *nr);
void cgen_callmeth(Node *n, int proc); void cgen_callmeth(Node *n, int proc);
......
...@@ -8,13 +8,14 @@ ...@@ -8,13 +8,14 @@
* The Go semicolon rules are: * The Go semicolon rules are:
* *
* 1. all statements and declarations are terminated by semicolons * 1. all statements and declarations are terminated by semicolons
* 2. semicolons can be omitted at top level. * 2. semicolons can be omitted before and after the closing ) or }
* 3. semicolons can be omitted before and after the closing ) or }
* on a list of statements or declarations. * on a list of statements or declarations.
* 3. semicolons are inserted by the lexer before a newline
* following a specific list of tokens.
* *
* This is accomplished by calling yyoptsemi() to mark the places * Rules #1 and #2 are accomplished by writing the lists as
* where semicolons are optional. That tells the lexer that if a * semicolon-separated lists with an optional trailing semicolon.
* semicolon isn't the next token, it should insert one for us. * Rule #3 is implemented in yylex.
*/ */
%{ %{
...@@ -67,7 +68,7 @@ ...@@ -67,7 +68,7 @@
%type <list> xdcl fnbody fnres switch_body loop_body dcl_name_list %type <list> xdcl fnbody fnres switch_body loop_body dcl_name_list
%type <list> new_name_list expr_list keyval_list braced_keyval_list expr_or_type_list xdcl_list %type <list> new_name_list expr_list keyval_list braced_keyval_list expr_or_type_list xdcl_list
%type <list> oexpr_list oexpr_or_type_list caseblock_list stmt_list oarg_type_list arg_type_list %type <list> oexpr_list oexpr_or_type_list_ocomma caseblock_list stmt_list oarg_type_list_ocomma arg_type_list
%type <list> interfacedcl_list vardcl vardcl_list structdcl structdcl_list %type <list> interfacedcl_list vardcl vardcl_list structdcl structdcl_list
%type <list> common_dcl constdcl constdcl1 constdcl_list typedcl_list %type <list> common_dcl constdcl constdcl1 constdcl_list typedcl_list
...@@ -112,13 +113,6 @@ ...@@ -112,13 +113,6 @@
%left ')' %left ')'
%left PreferToRightParen %left PreferToRightParen
%left '.'
%left '{'
%left NotSemi
%left ';'
%% %%
file: file:
loadsys loadsys
...@@ -134,9 +128,10 @@ package: ...@@ -134,9 +128,10 @@ package:
{ {
prevlineno = lineno; prevlineno = lineno;
yyerror("package statement must be first"); yyerror("package statement must be first");
flusherrors();
mkpackage("main"); mkpackage("main");
} }
| LPACKAGE sym | LPACKAGE sym ';'
{ {
mkpackage($2->name); mkpackage($2->name);
} }
...@@ -157,12 +152,12 @@ loadsys: ...@@ -157,12 +152,12 @@ loadsys:
} }
imports: imports:
| imports import | imports import ';'
import: import:
LIMPORT import_stmt osemi LIMPORT import_stmt
| LIMPORT '(' import_stmt_list osemi ')' osemi | LIMPORT '(' import_stmt_list osemi ')'
| LIMPORT '(' ')' osemi | LIMPORT '(' ')'
import_stmt: import_stmt:
import_here import_package import_there import_here import_package import_there
...@@ -235,7 +230,7 @@ import_here: ...@@ -235,7 +230,7 @@ import_here:
} }
import_package: import_package:
LPACKAGE sym LPACKAGE sym ';'
{ {
pkgimportname = $2; pkgimportname = $2;
if(strcmp($2->name, "main") == 0) if(strcmp($2->name, "main") == 0)
...@@ -265,24 +260,24 @@ import_there: ...@@ -265,24 +260,24 @@ import_there:
{ {
resumecheckwidth(); resumecheckwidth();
checkimports(); checkimports();
unimportfile();
} }
/* /*
* declarations * declarations
*/ */
xdcl: xdcl:
common_dcl osemi
| xfndcl osemi
{ {
$$ = list1($1); yyerror("empty top-level declaration");
$$ = nil;
} }
| error osemi | common_dcl
| xfndcl
{ {
$$ = nil; $$ = list1($1);
} }
| ';' | error
{ {
yyerror("empty top-level declaration");
$$ = nil; $$ = nil;
} }
...@@ -290,18 +285,14 @@ common_dcl: ...@@ -290,18 +285,14 @@ common_dcl:
LVAR vardcl LVAR vardcl
{ {
$$ = $2; $$ = $2;
if(yylast == LSEMIBRACE)
yyoptsemi(0);
} }
| LVAR '(' vardcl_list osemi ')' | LVAR '(' vardcl_list osemi ')'
{ {
$$ = $3; $$ = $3;
yyoptsemi(0);
} }
| LVAR '(' ')' | LVAR '(' ')'
{ {
$$ = nil; $$ = nil;
yyoptsemi(0);
} }
| LCONST constdcl | LCONST constdcl
{ {
...@@ -314,51 +305,38 @@ common_dcl: ...@@ -314,51 +305,38 @@ common_dcl:
$$ = $3; $$ = $3;
iota = 0; iota = 0;
lastconst = nil; lastconst = nil;
yyoptsemi(0);
} }
| LCONST '(' constdcl ';' constdcl_list osemi ')' | LCONST '(' constdcl ';' constdcl_list osemi ')'
{ {
$$ = concat($3, $5); $$ = concat($3, $5);
iota = 0; iota = 0;
lastconst = nil; lastconst = nil;
yyoptsemi(0);
} }
| LCONST '(' ')' | LCONST '(' ')'
{ {
$$ = nil; $$ = nil;
yyoptsemi(0);
} }
| LTYPE typedcl | LTYPE typedcl
{ {
$$ = list1($2); $$ = list1($2);
if(yylast == LSEMIBRACE)
yyoptsemi(0);
} }
| LTYPE '(' typedcl_list osemi ')' | LTYPE '(' typedcl_list osemi ')'
{ {
$$ = $3; $$ = $3;
yyoptsemi(0);
} }
| LTYPE '(' ')' | LTYPE '(' ')'
{ {
$$ = nil; $$ = nil;
yyoptsemi(0);
}
varoptsemi:
{
if(yylast == LSEMIBRACE)
yyoptsemi('=');
} }
vardcl: vardcl:
dcl_name_list ntype varoptsemi dcl_name_list ntype
{ {
$$ = variter($1, $2, nil); $$ = variter($1, $2, nil);
} }
| dcl_name_list ntype varoptsemi '=' expr_list | dcl_name_list ntype '=' expr_list
{ {
$$ = variter($1, $2, $5); $$ = variter($1, $2, $4);
} }
| dcl_name_list '=' expr_list | dcl_name_list '=' expr_list
{ {
...@@ -508,7 +486,6 @@ compound_stmt: ...@@ -508,7 +486,6 @@ compound_stmt:
{ {
$$ = liststmt($3); $$ = liststmt($3);
popdcl(); popdcl();
yyoptsemi(0);
} }
switch_body: switch_body:
...@@ -520,7 +497,6 @@ switch_body: ...@@ -520,7 +497,6 @@ switch_body:
{ {
$$ = $3; $$ = $3;
popdcl(); popdcl();
yyoptsemi(0);
} }
caseblock: caseblock:
...@@ -590,7 +566,6 @@ for_body: ...@@ -590,7 +566,6 @@ for_body:
{ {
$$ = $1; $$ = $1;
$$->nbody = concat($$->nbody, $2); $$->nbody = concat($$->nbody, $2);
yyoptsemi(0);
} }
for_stmt: for_stmt:
...@@ -630,7 +605,6 @@ if_stmt: ...@@ -630,7 +605,6 @@ if_stmt:
$$ = $3; $$ = $3;
$$->nbody = $4; $$->nbody = $4;
// no popdcl; maybe there's an LELSE // no popdcl; maybe there's an LELSE
yyoptsemi(LELSE);
} }
switch_stmt: switch_stmt:
...@@ -794,7 +768,7 @@ uexpr: ...@@ -794,7 +768,7 @@ uexpr:
* can be preceded by 'defer' and 'go' * can be preceded by 'defer' and 'go'
*/ */
pseudocall: pseudocall:
pexpr '(' oexpr_or_type_list ')' pexpr '(' oexpr_or_type_list_ocomma ')'
{ {
$$ = nod(OCALL, $1, N); $$ = nod(OCALL, $1, N);
$$->list = $3; $$->list = $3;
...@@ -1054,15 +1028,10 @@ structtype: ...@@ -1054,15 +1028,10 @@ structtype:
{ {
$$ = nod(OTSTRUCT, N, N); $$ = nod(OTSTRUCT, N, N);
$$->list = $3; $$->list = $3;
// Distinguish closing brace in struct from
// other closing braces by explicitly marking it.
// Used above (yylast == LSEMIBRACE).
yylast = LSEMIBRACE;
} }
| LSTRUCT '{' '}' | LSTRUCT '{' '}'
{ {
$$ = nod(OTSTRUCT, N, N); $$ = nod(OTSTRUCT, N, N);
yylast = LSEMIBRACE;
} }
interfacetype: interfacetype:
...@@ -1070,12 +1039,10 @@ interfacetype: ...@@ -1070,12 +1039,10 @@ interfacetype:
{ {
$$ = nod(OTINTER, N, N); $$ = nod(OTINTER, N, N);
$$->list = $3; $$->list = $3;
yylast = LSEMIBRACE;
} }
| LINTERFACE '{' '}' | LINTERFACE '{' '}'
{ {
$$ = nod(OTINTER, N, N); $$ = nod(OTINTER, N, N);
yylast = LSEMIBRACE;
} }
keyval: keyval:
...@@ -1100,7 +1067,7 @@ xfndcl: ...@@ -1100,7 +1067,7 @@ xfndcl:
} }
fndcl: fndcl:
dcl_name '(' oarg_type_list ')' fnres dcl_name '(' oarg_type_list_ocomma ')' fnres
{ {
Node *n; Node *n;
...@@ -1115,7 +1082,7 @@ fndcl: ...@@ -1115,7 +1082,7 @@ fndcl:
$$->nname->ntype = n; $$->nname->ntype = n;
funchdr($$); funchdr($$);
} }
| '(' oarg_type_list ')' new_name '(' oarg_type_list ')' fnres | '(' oarg_type_list_ocomma ')' new_name '(' oarg_type_list_ocomma ')' fnres
{ {
Node *rcvr, *t; Node *rcvr, *t;
...@@ -1145,7 +1112,7 @@ fndcl: ...@@ -1145,7 +1112,7 @@ fndcl:
} }
fntype: fntype:
LFUNC '(' oarg_type_list ')' fnres LFUNC '(' oarg_type_list_ocomma ')' fnres
{ {
$$ = nod(OTFUNC, N, N); $$ = nod(OTFUNC, N, N);
$$->list = $3; $$->list = $3;
...@@ -1161,7 +1128,6 @@ fnbody: ...@@ -1161,7 +1128,6 @@ fnbody:
$$ = $2; $$ = $2;
if($$ == nil) if($$ == nil)
$$ = list1(nod(OEMPTY, N, N)); $$ = list1(nod(OEMPTY, N, N));
yyoptsemi(0);
} }
fnres: fnres:
...@@ -1173,7 +1139,7 @@ fnres: ...@@ -1173,7 +1139,7 @@ fnres:
{ {
$$ = list1(nod(ODCLFIELD, N, $1)); $$ = list1(nod(ODCLFIELD, N, $1));
} }
| '(' oarg_type_list ')' | '(' oarg_type_list_ocomma ')'
{ {
$$ = $2; $$ = $2;
} }
...@@ -1201,7 +1167,7 @@ xdcl_list: ...@@ -1201,7 +1167,7 @@ xdcl_list:
{ {
$$ = nil; $$ = nil;
} }
| xdcl_list xdcl | xdcl_list xdcl ';'
{ {
$$ = concat($1, $2); $$ = concat($1, $2);
if(nsyntaxerrors == 0) if(nsyntaxerrors == 0)
...@@ -1312,7 +1278,7 @@ interfacedcl: ...@@ -1312,7 +1278,7 @@ interfacedcl:
} }
indcl: indcl:
'(' oarg_type_list ')' fnres '(' oarg_type_list_ocomma ')' fnres
{ {
// without func keyword // without func keyword
$$ = nod(OTFUNC, fakethis(), N); $$ = nod(OTFUNC, fakethis(), N);
...@@ -1349,11 +1315,11 @@ arg_type_list: ...@@ -1349,11 +1315,11 @@ arg_type_list:
$$ = list($1, $3); $$ = list($1, $3);
} }
oarg_type_list: oarg_type_list_ocomma:
{ {
$$ = nil; $$ = nil;
} }
| arg_type_list | arg_type_list ocomma
{ {
$$ = checkarglist($1); $$ = checkarglist($1);
} }
...@@ -1517,7 +1483,6 @@ braced_keyval_list: ...@@ -1517,7 +1483,6 @@ braced_keyval_list:
* optional things * optional things
*/ */
osemi: osemi:
%prec NotSemi
| ';' | ';'
ocomma: ocomma:
...@@ -1535,11 +1500,11 @@ oexpr_list: ...@@ -1535,11 +1500,11 @@ oexpr_list:
} }
| expr_list | expr_list
oexpr_or_type_list: oexpr_or_type_list_ocomma:
{ {
$$ = nil; $$ = nil;
} }
| expr_or_type_list | expr_or_type_list ocomma
osimple_stmt: osimple_stmt:
{ {
...@@ -1576,29 +1541,29 @@ oliteral: ...@@ -1576,29 +1541,29 @@ oliteral:
* an output package * an output package
*/ */
hidden_import: hidden_import:
LPACKAGE sym LPACKAGE sym ';'
/* variables */ /* variables */
| LVAR hidden_pkg_importsym hidden_type | LVAR hidden_pkg_importsym hidden_type ';'
{ {
importvar($2, $3, PEXTERN); importvar($2, $3, PEXTERN);
} }
| LCONST hidden_pkg_importsym '=' hidden_constant | LCONST hidden_pkg_importsym '=' hidden_constant ';'
{ {
importconst($2, types[TIDEAL], $4); importconst($2, types[TIDEAL], $4);
} }
| LCONST hidden_pkg_importsym hidden_type '=' hidden_constant | LCONST hidden_pkg_importsym hidden_type '=' hidden_constant ';'
{ {
importconst($2, $3, $5); importconst($2, $3, $5);
} }
| LTYPE hidden_pkgtype hidden_type | LTYPE hidden_pkgtype hidden_type ';'
{ {
importtype($2, $3); importtype($2, $3);
} }
| LFUNC hidden_pkg_importsym '(' ohidden_funarg_list ')' ohidden_funres | LFUNC hidden_pkg_importsym '(' ohidden_funarg_list ')' ohidden_funres ';'
{ {
importvar($2, functype(N, $4, $6), PFUNC); importvar($2, functype(N, $4, $6), PFUNC);
} }
| LFUNC '(' hidden_funarg_list ')' sym '(' ohidden_funarg_list ')' ohidden_funres | LFUNC '(' hidden_funarg_list ')' sym '(' ohidden_funarg_list ')' ohidden_funres ';'
{ {
if($3->next != nil || $3->n->op != ODCLFIELD) { if($3->next != nil || $3->n->op != ODCLFIELD) {
yyerror("bad receiver in method"); yyerror("bad receiver in method");
......
...@@ -85,6 +85,7 @@ main(int argc, char *argv[]) ...@@ -85,6 +85,7 @@ main(int argc, char *argv[])
fatal("open %s: %r", infile); fatal("open %s: %r", infile);
curio.peekc = 0; curio.peekc = 0;
curio.peekc1 = 0; curio.peekc1 = 0;
curio.nlsemi = 0;
block = 1; block = 1;
...@@ -310,6 +311,7 @@ importfile(Val *f, int line) ...@@ -310,6 +311,7 @@ importfile(Val *f, int line)
curio.peekc = 0; curio.peekc = 0;
curio.peekc1 = 0; curio.peekc1 = 0;
curio.infile = file; curio.infile = file;
curio.nlsemi = 0;
typecheckok = 1; typecheckok = 1;
for(;;) { for(;;) {
c = getc(); c = getc();
...@@ -354,6 +356,7 @@ cannedimports(char *file, char *cp) ...@@ -354,6 +356,7 @@ cannedimports(char *file, char *cp)
curio.peekc1 = 0; curio.peekc1 = 0;
curio.infile = file; curio.infile = file;
curio.cp = cp; curio.cp = cp;
curio.nlsemi = 0;
pkgmyname = S; pkgmyname = S;
typecheckok = 1; typecheckok = 1;
...@@ -389,8 +392,14 @@ _yylex(void) ...@@ -389,8 +392,14 @@ _yylex(void)
l0: l0:
c = getc(); c = getc();
if(isspace(c)) if(isspace(c)) {
if(c == '\n' && curio.nlsemi) {
ungetc(c);
DBG("lex: implicit semi\n");
return ';';
}
goto l0; goto l0;
}
lineno = lexlineno; /* start of token */ lineno = lexlineno; /* start of token */
...@@ -444,7 +453,6 @@ l0: ...@@ -444,7 +453,6 @@ l0:
cp = mal(sizeof(int32)); cp = mal(sizeof(int32));
clen = sizeof(int32); clen = sizeof(int32);
caseq:
for(;;) { for(;;) {
if(escchar('"', &escflag, &v)) if(escchar('"', &escflag, &v))
break; break;
...@@ -460,7 +468,7 @@ l0: ...@@ -460,7 +468,7 @@ l0:
clen += c; clen += c;
} }
} }
goto catem; goto strlit;
case '`': case '`':
/* `...` */ /* `...` */
...@@ -468,7 +476,6 @@ l0: ...@@ -468,7 +476,6 @@ l0:
cp = mal(sizeof(int32)); cp = mal(sizeof(int32));
clen = sizeof(int32); clen = sizeof(int32);
casebq:
for(;;) { for(;;) {
c = getc(); c = getc();
if(c == EOF) { if(c == EOF) {
...@@ -480,51 +487,8 @@ l0: ...@@ -480,51 +487,8 @@ l0:
cp = remal(cp, clen, 1); cp = remal(cp, clen, 1);
cp[clen++] = c; cp[clen++] = c;
} }
goto catem;
catem:
c = getc();
if(isspace(c))
goto catem;
// skip comments
if(c == '/') {
c1 = getc();
if(c1 == '*') {
for(;;) {
c = getr();
while(c == '*') {
c = getr();
if(c == '/')
goto catem;
}
if(c == EOF) {
yyerror("eof in comment");
errorexit();
}
}
}
if(c1 == '/') {
for(;;) {
c = getr();
if(c == '\n')
goto catem;
if(c == EOF) {
yyerror("eof in comment");
errorexit();
}
}
}
ungetc(c1);
}
// cat adjacent strings
if(c == '"')
goto caseq;
if(c == '`')
goto casebq;
ungetc(c);
strlit:
*(int32*)cp = clen-sizeof(int32); // length *(int32*)cp = clen-sizeof(int32); // length
do { do {
cp = remal(cp, clen, 1); cp = remal(cp, clen, 1);
...@@ -554,13 +518,23 @@ l0: ...@@ -554,13 +518,23 @@ l0:
case '/': case '/':
c1 = getc(); c1 = getc();
if(c1 == '*') { if(c1 == '*') {
int nl;
nl = 0;
for(;;) { for(;;) {
c = getr(); c = getr();
if(c == '\n')
nl = 1;
while(c == '*') { while(c == '*') {
c = getr(); c = getr();
if(c == '/') if(c == '/') {
if(nl)
ungetc('\n');
goto l0; goto l0;
} }
if(c == '\n')
nl = 1;
}
if(c == EOF) { if(c == EOF) {
yyerror("eof in comment"); yyerror("eof in comment");
errorexit(); errorexit();
...@@ -570,8 +544,10 @@ l0: ...@@ -570,8 +544,10 @@ l0:
if(c1 == '/') { if(c1 == '/') {
for(;;) { for(;;) {
c = getr(); c = getr();
if(c == '\n') if(c == '\n') {
ungetc(c);
goto l0; goto l0;
}
if(c == EOF) { if(c == EOF) {
yyerror("eof in comment"); yyerror("eof in comment");
errorexit(); errorexit();
...@@ -962,42 +938,43 @@ caseout: ...@@ -962,42 +938,43 @@ caseout:
return LLITERAL; return LLITERAL;
} }
/*
* help the parser. if the next token is not c and not ';',
* insert a ';' before it.
*/
void
yyoptsemi(int c)
{
if(c == 0)
c = -1;
if(yychar <= 0)
yysemi = c;
}
int32 int32
yylex(void) yylex(void)
{ {
// if we delayed a token, return that one. int lx;
if(yynext) {
yylast = yynext; lx = _yylex();
yynext = 0;
return yylast; if(curio.nlsemi && lx == EOF) {
} // if the nlsemi bit is set, we'd be willing to
// insert a ; if we saw a \n, but we didn't.
yylast = _yylex(); // that means the final \n is missing.
// complain here, because we can give a
// if there's an optional semicolon needed, // good message. the syntax error we'd get
// delay the token we just read. // otherwise is inscrutable.
if(yysemi) { yyerror("missing newline at end of file");
if(yylast != ';' && yylast != yysemi) { lx = ';';
yynext = yylast; }
yylast = ';';
} switch(lx) {
yysemi = 0; case LNAME:
case LLITERAL:
case LBREAK:
case LCONTINUE:
case LFALL:
case LRETURN:
case LINC:
case LDEC:
case ')':
case '}':
case ']':
curio.nlsemi = 1;
break;
default:
curio.nlsemi = 0;
break;
} }
return lx;
return yylast;
} }
int int
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment