// Copyright 2009 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. /* * Go language grammar. * * The Go semicolon rules are: * * 1. all statements and declarations are terminated by semicolons. * 2. semicolons can be omitted before a closing ) or }. * 3. semicolons are inserted by the lexer before a newline * following a specific list of tokens. * * Rules #1 and #2 are accomplished by writing the lists as * semicolon-separated lists with an optional trailing semicolon. * Rule #3 is implemented in yylex. */ %{ #include #include /* if we don't, bison will, and go.h re-#defines getc */ #include #include "go.h" static void fixlbrace(int); %} %union { Node* node; NodeList* list; Type* type; Sym* sym; struct Val val; int lint; } // |sed 's/.* //' |9 fmt -l1 |sort |9 fmt -l50 | sed 's/^/%xxx /' %token LLITERAL %token LASOP %token LBREAK LCASE LCHAN LCOLAS LCONST LCONTINUE LDDD %token LDEFAULT LDEFER LELSE LFALL LFOR LFUNC LGO LGOTO %token LIF LIMPORT LINTERFACE LMAP LNAME %token LPACKAGE LRANGE LRETURN LSELECT LSTRUCT LSWITCH %token LTYPE LVAR %token LANDAND LANDNOT LBODY LCOMM LDEC LEQ LGE LGT %token LIGNORE LINC LLE LLSH LLT LNE LOROR LRSH %type lbrace import_here %type sym packname %type oliteral %type stmt ntype %type arg_type %type case caseblock %type compound_stmt dotname embed expr complitexpr %type expr_or_type %type fndcl fnliteral %type for_body for_header for_stmt if_header if_stmt else non_dcl_stmt %type interfacedcl keyval labelname name %type name_or_type non_expr_type %type new_name dcl_name oexpr typedclname %type onew_name %type osimple_stmt pexpr pexpr_no_paren %type pseudocall range_stmt select_stmt %type simple_stmt %type switch_stmt uexpr %type xfndcl typedcl %type xdcl fnbody fnres loop_body dcl_name_list %type new_name_list expr_list keyval_list braced_keyval_list expr_or_type_list xdcl_list %type oexpr_list caseblock_list stmt_list oarg_type_list_ocomma arg_type_list %type interfacedcl_list vardcl vardcl_list structdcl structdcl_list %type common_dcl constdcl constdcl1 constdcl_list typedcl_list %type convtype comptype dotdotdot %type indcl interfacetype structtype ptrtype %type recvchantype non_recvchantype othertype fnret_type fntype %type hidden_importsym hidden_pkg_importsym %type hidden_constant hidden_literal hidden_dcl %type hidden_interfacedcl hidden_structdcl hidden_opt_sym %type hidden_funres %type ohidden_funres %type hidden_funarg_list ohidden_funarg_list %type hidden_interfacedcl_list ohidden_interfacedcl_list %type hidden_structdcl_list ohidden_structdcl_list %type hidden_type hidden_type_misc hidden_pkgtype %type hidden_type_func %type hidden_type_recv_chan hidden_type_non_recv_chan %left LCOMM /* outside the usual hierarchy; here for good error messages */ %left LOROR %left LANDAND %left LEQ LNE LLE LGE LLT LGT %left '+' '-' '|' '^' %left '*' '/' '%' '&' LLSH LRSH LANDNOT /* * manual override of shift/reduce conflicts. * the general form is that we assign a precedence * to the token being shifted and then introduce * NotToken with lower precedence or PreferToToken with higher * and annotate the reducing rule accordingly. */ %left NotPackage %left LPACKAGE %left NotParen %left '(' %left ')' %left PreferToRightParen %error-verbose %% file: loadsys package imports xdcl_list { xtop = concat(xtop, $4); } package: %prec NotPackage { prevlineno = lineno; yyerror("package statement must be first"); flusherrors(); mkpackage("main"); } | LPACKAGE sym ';' { mkpackage($2->name); } /* * this loads the definitions for the low-level runtime functions, * so that the compiler can generate calls to them, * but does not make the name "runtime" visible as a package. */ loadsys: { importpkg = runtimepkg; if(debug['A']) cannedimports("runtime.builtin", "package runtime\n\n$$\n\n"); else cannedimports("runtime.builtin", runtimeimport); curio.importsafe = 1; } import_package import_there { importpkg = nil; } imports: | imports import ';' import: LIMPORT import_stmt | LIMPORT '(' import_stmt_list osemi ')' | LIMPORT '(' ')' import_stmt: import_here import_package import_there { Pkg *ipkg; Sym *my; Node *pack; ipkg = importpkg; my = importmyname; importpkg = nil; importmyname = S; if(my == nil) my = lookup(ipkg->name); pack = nod(OPACK, N, N); pack->sym = my; pack->pkg = ipkg; pack->lineno = $1; if(my->name[0] == '.') { importdot(ipkg, pack); break; } if(my->name[0] == '_' && my->name[1] == '\0') break; if(my->def) { lineno = $1; redeclare(my, "as imported package name"); } my->def = pack; my->lastlineno = $1; my->block = 1; // at top level } import_stmt_list: import_stmt | import_stmt_list ';' import_stmt import_here: LLITERAL { // import with original name $$ = parserline(); importmyname = S; importfile(&$1, $$); } | sym LLITERAL { // import with given name $$ = parserline(); importmyname = $1; importfile(&$2, $$); } | '.' LLITERAL { // import into my name space $$ = parserline(); importmyname = lookup("."); importfile(&$2, $$); } import_package: LPACKAGE sym import_safety ';' { if(importpkg->name == nil) { importpkg->name = $2->name; pkglookup($2->name, nil)->npkg++; } else if(strcmp(importpkg->name, $2->name) != 0) yyerror("conflicting names %s and %s for package \"%Z\"", importpkg->name, $2->name, importpkg->path); importpkg->direct = 1; if(safemode && !curio.importsafe) yyerror("cannot import unsafe package \"%Z\"", importpkg->path); } import_safety: | LNAME { if(strcmp($1->name, "safe") == 0) curio.importsafe = 1; } import_there: { defercheckwidth(); } hidden_import_list '$' '$' { resumecheckwidth(); unimportfile(); } /* * declarations */ xdcl: { yyerror("empty top-level declaration"); $$ = nil; } | common_dcl | xfndcl { $$ = list1($1); } | non_dcl_stmt { yyerror("non-declaration statement outside function body"); $$ = nil; } | error { $$ = nil; } common_dcl: LVAR vardcl { $$ = $2; } | LVAR '(' vardcl_list osemi ')' { $$ = $3; } | LVAR '(' ')' { $$ = nil; } | lconst constdcl { $$ = $2; iota = -100000; lastconst = nil; } | lconst '(' constdcl osemi ')' { $$ = $3; iota = -100000; lastconst = nil; } | lconst '(' constdcl ';' constdcl_list osemi ')' { $$ = concat($3, $5); iota = -100000; lastconst = nil; } | lconst '(' ')' { $$ = nil; iota = -100000; } | LTYPE typedcl { $$ = list1($2); } | LTYPE '(' typedcl_list osemi ')' { $$ = $3; } | LTYPE '(' ')' { $$ = nil; } lconst: LCONST { iota = 0; } vardcl: dcl_name_list ntype { $$ = variter($1, $2, nil); } | dcl_name_list ntype '=' expr_list { $$ = variter($1, $2, $4); } | dcl_name_list '=' expr_list { $$ = variter($1, nil, $3); } constdcl: dcl_name_list ntype '=' expr_list { $$ = constiter($1, $2, $4); } | dcl_name_list '=' expr_list { $$ = constiter($1, N, $3); } constdcl1: constdcl | dcl_name_list ntype { $$ = constiter($1, $2, nil); } | dcl_name_list { $$ = constiter($1, N, nil); } typedclname: sym { // different from dclname because the name // becomes visible right here, not at the end // of the declaration. $$ = typedcl0($1); } typedcl: typedclname ntype { $$ = typedcl1($1, $2, 1); } simple_stmt: expr { $$ = $1; } | expr LASOP expr { $$ = nod(OASOP, $1, $3); $$->etype = $2; // rathole to pass opcode } | expr_list '=' expr_list { if($1->next == nil && $3->next == nil) { // simple $$ = nod(OAS, $1->n, $3->n); break; } // multiple $$ = nod(OAS2, N, N); $$->list = $1; $$->rlist = $3; } | expr_list LCOLAS expr_list { if($3->n->op == OTYPESW) { $$ = nod(OTYPESW, N, $3->n->right); if($3->next != nil) yyerror("expr.(type) must be alone in list"); if($1->next != nil) yyerror("argument count mismatch: %d = %d", count($1), 1); else if($1->n->op != ONAME && $1->n->op != OTYPE && $1->n->op != ONONAME) yyerror("invalid variable name %N in type switch", $1->n); else $$->left = dclname($1->n->sym); // it's a colas, so must not re-use an oldname. break; } $$ = colas($1, $3); } | expr LINC { $$ = nod(OASOP, $1, nodintconst(1)); $$->etype = OADD; } | expr LDEC { $$ = nod(OASOP, $1, nodintconst(1)); $$->etype = OSUB; } case: LCASE expr_or_type_list ':' { Node *n, *nn; // will be converted to OCASE // right will point to next case // done in casebody() markdcl(); $$ = nod(OXCASE, N, N); $$->list = $2; if(typesw != N && typesw->right != N && (n=typesw->right->left) != N) { // type switch - declare variable nn = newname(n->sym); declare(nn, dclcontext); $$->nname = nn; // keep track of the instances for reporting unused nn->defn = typesw->right; } } | LCASE expr_or_type_list '=' expr ':' { Node *n; // will be converted to OCASE // right will point to next case // done in casebody() markdcl(); $$ = nod(OXCASE, N, N); if($2->next == nil) n = nod(OAS, $2->n, $4); else { n = nod(OAS2, N, N); n->list = $2; n->rlist = list1($4); } $$->list = list1(n); } | LCASE expr_or_type_list LCOLAS expr ':' { // will be converted to OCASE // right will point to next case // done in casebody() markdcl(); $$ = nod(OXCASE, N, N); $$->list = list1(colas($2, list1($4))); } | LDEFAULT ':' { Node *n, *nn; markdcl(); $$ = nod(OXCASE, N, N); if(typesw != N && typesw->right != N && (n=typesw->right->left) != N) { // type switch - declare variable nn = newname(n->sym); declare(nn, dclcontext); $$->nname = nn; // keep track of the instances for reporting unused nn->defn = typesw->right; } } compound_stmt: '{' { markdcl(); } stmt_list '}' { $$ = liststmt($3); popdcl(); } caseblock: case { // If the last token read by the lexer was consumed // as part of the case, clear it (parser has cleared yychar). // If the last token read by the lexer was the lookahead // leave it alone (parser has it cached in yychar). // This is so that the stmt_list action doesn't look at // the case tokens if the stmt_list is empty. yylast = yychar; } stmt_list { int last; // This is the only place in the language where a statement // list is not allowed to drop the final semicolon, because // it's the only place where a statement list is not followed // by a closing brace. Handle the error for pedantry. // Find the final token of the statement list. // yylast is lookahead; yyprev is last of stmt_list last = yyprev; if(last > 0 && last != ';' && yychar != '}') yyerror("missing statement after label"); $$ = $1; $$->nbody = $3; popdcl(); } caseblock_list: { $$ = nil; } | caseblock_list caseblock { $$ = list($1, $2); } loop_body: LBODY { markdcl(); } stmt_list '}' { $$ = $3; popdcl(); } range_stmt: expr_list '=' LRANGE expr { $$ = nod(ORANGE, N, $4); $$->list = $1; $$->etype = 0; // := flag } | expr_list LCOLAS LRANGE expr { $$ = nod(ORANGE, N, $4); $$->list = $1; $$->colas = 1; colasdefn($1, $$); } for_header: osimple_stmt ';' osimple_stmt ';' osimple_stmt { // init ; test ; incr if($5 != N && $5->colas != 0) yyerror("cannot declare in the for-increment"); $$ = nod(OFOR, N, N); if($1 != N) $$->ninit = list1($1); $$->ntest = $3; $$->nincr = $5; } | osimple_stmt { // normal test $$ = nod(OFOR, N, N); $$->ntest = $1; } | range_stmt for_body: for_header loop_body { $$ = $1; $$->nbody = concat($$->nbody, $2); } for_stmt: LFOR { markdcl(); } for_body { $$ = $3; popdcl(); } if_header: osimple_stmt { // test $$ = nod(OIF, N, N); $$->ntest = $1; } | osimple_stmt ';' osimple_stmt { // init ; test $$ = nod(OIF, N, N); if($1 != N) $$->ninit = list1($1); $$->ntest = $3; } /* IF cond body (ELSE IF cond body)* (ELSE block)? */ if_stmt: LIF { markdcl(); } if_header { if($3->ntest == N) yyerror("missing condition in if statement"); } loop_body { $3->nbody = $5; } else { popdcl(); $$ = $3; if($7 != N) $$->nelse = list1($7); } else: { $$ = N; } | LELSE if_stmt { $$ = $2; } | LELSE compound_stmt { $$ = $2; } switch_stmt: LSWITCH { markdcl(); } if_header { Node *n; n = $3->ntest; if(n != N && n->op != OTYPESW) n = N; typesw = nod(OXXX, typesw, n); } LBODY caseblock_list '}' { $$ = $3; $$->op = OSWITCH; $$->list = $6; typesw = typesw->left; popdcl(); } select_stmt: LSELECT { typesw = nod(OXXX, typesw, N); } LBODY caseblock_list '}' { $$ = nod(OSELECT, N, N); $$->lineno = typesw->lineno; $$->list = $4; typesw = typesw->left; } /* * expressions */ expr: uexpr | expr LOROR expr { $$ = nod(OOROR, $1, $3); } | expr LANDAND expr { $$ = nod(OANDAND, $1, $3); } | expr LEQ expr { $$ = nod(OEQ, $1, $3); } | expr LNE expr { $$ = nod(ONE, $1, $3); } | expr LLT expr { $$ = nod(OLT, $1, $3); } | expr LLE expr { $$ = nod(OLE, $1, $3); } | expr LGE expr { $$ = nod(OGE, $1, $3); } | expr LGT expr { $$ = nod(OGT, $1, $3); } | expr '+' expr { $$ = nod(OADD, $1, $3); } | expr '-' expr { $$ = nod(OSUB, $1, $3); } | expr '|' expr { $$ = nod(OOR, $1, $3); } | expr '^' expr { $$ = nod(OXOR, $1, $3); } | expr '*' expr { $$ = nod(OMUL, $1, $3); } | expr '/' expr { $$ = nod(ODIV, $1, $3); } | expr '%' expr { $$ = nod(OMOD, $1, $3); } | expr '&' expr { $$ = nod(OAND, $1, $3); } | expr LANDNOT expr { $$ = nod(OANDNOT, $1, $3); } | expr LLSH expr { $$ = nod(OLSH, $1, $3); } | expr LRSH expr { $$ = nod(ORSH, $1, $3); } /* not an expression anymore, but left in so we can give a good error */ | expr LCOMM expr { $$ = nod(OSEND, $1, $3); } uexpr: pexpr | '*' uexpr { $$ = nod(OIND, $2, N); } | '&' uexpr { $$ = nod(OADDR, $2, N); } | '+' uexpr { $$ = nod(OPLUS, $2, N); } | '-' uexpr { $$ = nod(OMINUS, $2, N); } | '!' uexpr { $$ = nod(ONOT, $2, N); } | '~' uexpr { yyerror("the bitwise complement operator is ^"); $$ = nod(OCOM, $2, N); } | '^' uexpr { $$ = nod(OCOM, $2, N); } | LCOMM uexpr { $$ = nod(ORECV, $2, N); } /* * call-like statements that * can be preceded by 'defer' and 'go' */ pseudocall: pexpr '(' ')' { $$ = nod(OCALL, $1, N); } | pexpr '(' expr_or_type_list ocomma ')' { $$ = nod(OCALL, $1, N); $$->list = $3; } | pexpr '(' expr_or_type_list LDDD ocomma ')' { $$ = nod(OCALL, $1, N); $$->list = $3; $$->isddd = 1; } pexpr_no_paren: LLITERAL { $$ = nodlit($1); } | name | pexpr '.' sym { if($1->op == OPACK) { Sym *s; s = restrictlookup($3->name, $1->pkg); $1->used = 1; $$ = oldname(s); break; } $$ = nod(OXDOT, $1, newname($3)); } | pexpr '.' '(' expr_or_type ')' { $$ = nod(ODOTTYPE, $1, $4); } | pexpr '.' '(' LTYPE ')' { $$ = nod(OTYPESW, N, $1); } | pexpr '[' expr ']' { $$ = nod(OINDEX, $1, $3); } | pexpr '[' oexpr ':' oexpr ']' { $$ = nod(OSLICE, $1, nod(OKEY, $3, $5)); } | pseudocall | convtype '(' expr ')' { // conversion $$ = nod(OCALL, $1, N); $$->list = list1($3); } | comptype lbrace braced_keyval_list '}' { // composite expression $$ = nod(OCOMPLIT, N, $1); $$->list = $3; fixlbrace($2); } | pexpr_no_paren '{' braced_keyval_list '}' { // composite expression $$ = nod(OCOMPLIT, N, $1); $$->list = $3; } | '(' expr_or_type ')' '{' braced_keyval_list '}' { yyerror("cannot parenthesize type in composite literal"); // composite expression $$ = nod(OCOMPLIT, N, $2); $$->list = $5; } | fnliteral keyval: expr ':' complitexpr { $$ = nod(OKEY, $1, $3); } complitexpr: expr | '{' braced_keyval_list '}' { $$ = nod(OCOMPLIT, N, N); $$->list = $2; } pexpr: pexpr_no_paren | '(' expr_or_type ')' { $$ = $2; // Need to know on lhs of := whether there are ( ). // Don't bother with the OPAREN in other cases: // it's just a waste of memory and time. switch($$->op) { case ONAME: case ONONAME: case OPACK: case OTYPE: case OLITERAL: $$ = nod(OPAREN, $$, N); } } expr_or_type: expr | non_expr_type %prec PreferToRightParen name_or_type: ntype lbrace: LBODY { $$ = LBODY; } | '{' { $$ = '{'; } /* * names and types * newname is used before declared * oldname is used after declared */ new_name: sym { $$ = newname($1); } dcl_name: sym { $$ = dclname($1); } onew_name: { $$ = N; } | new_name sym: LNAME | hidden_importsym hidden_importsym: '@' LLITERAL '.' LNAME { if($2.u.sval->len == 0) $$ = pkglookup($4->name, importpkg); else $$ = pkglookup($4->name, mkpkg($2.u.sval)); } name: sym %prec NotParen { $$ = oldname($1); if($$->pack != N) $$->pack->used = 1; } labelname: new_name /* * to avoid parsing conflicts, type is split into * channel types * function types * parenthesized types * any other type * the type system makes additional restrictions, * but those are not implemented in the grammar. */ dotdotdot: LDDD { yyerror("final argument in variadic function missing type"); $$ = nod(ODDD, typenod(typ(TINTER)), N); } | LDDD ntype { $$ = nod(ODDD, $2, N); } ntype: recvchantype | fntype | othertype | ptrtype | dotname | '(' ntype ')' { $$ = nod(OTPAREN, $2, N); } non_expr_type: recvchantype | fntype | othertype | '*' non_expr_type { $$ = nod(OIND, $2, N); } non_recvchantype: fntype | othertype | ptrtype | dotname | '(' ntype ')' { $$ = nod(OTPAREN, $2, N); } convtype: fntype | othertype comptype: othertype fnret_type: recvchantype | fntype | othertype | ptrtype | dotname dotname: name | name '.' sym { if($1->op == OPACK) { Sym *s; s = restrictlookup($3->name, $1->pkg); $1->used = 1; $$ = oldname(s); break; } $$ = nod(OXDOT, $1, newname($3)); } othertype: '[' oexpr ']' ntype { $$ = nod(OTARRAY, $2, $4); } | '[' LDDD ']' ntype { // array literal of nelem $$ = nod(OTARRAY, nod(ODDD, N, N), $4); } | LCHAN non_recvchantype { $$ = nod(OTCHAN, $2, N); $$->etype = Cboth; } | LCHAN LCOMM ntype { $$ = nod(OTCHAN, $3, N); $$->etype = Csend; } | LMAP '[' ntype ']' ntype { $$ = nod(OTMAP, $3, $5); } | structtype | interfacetype ptrtype: '*' ntype { $$ = nod(OIND, $2, N); } recvchantype: LCOMM LCHAN ntype { $$ = nod(OTCHAN, $3, N); $$->etype = Crecv; } structtype: LSTRUCT lbrace structdcl_list osemi '}' { $$ = nod(OTSTRUCT, N, N); $$->list = $3; fixlbrace($2); } | LSTRUCT lbrace '}' { $$ = nod(OTSTRUCT, N, N); fixlbrace($2); } interfacetype: LINTERFACE lbrace interfacedcl_list osemi '}' { $$ = nod(OTINTER, N, N); $$->list = $3; fixlbrace($2); } | LINTERFACE lbrace '}' { $$ = nod(OTINTER, N, N); fixlbrace($2); } /* * function stuff * all in one place to show how crappy it all is */ xfndcl: LFUNC fndcl fnbody { $$ = $2; if($$ == N) break; $$->nbody = $3; $$->endlineno = lineno; funcbody($$); } fndcl: dcl_name '(' oarg_type_list_ocomma ')' fnres { Node *n; $3 = checkarglist($3, 1); $$ = nod(ODCLFUNC, N, N); $$->nname = $1; n = nod(OTFUNC, N, N); n->list = $3; n->rlist = $5; if(strcmp($1->sym->name, "init") == 0) { $$->nname = renameinit($1); if($3 != nil || $5 != nil) yyerror("func init must have no arguments and no return values"); } if(strcmp(localpkg->name, "main") == 0 && strcmp($1->sym->name, "main") == 0) { if($3 != nil || $5 != nil) yyerror("func main must have no arguments and no return values"); } // TODO: check if nname already has an ntype $$->nname->ntype = n; funchdr($$); } | '(' oarg_type_list_ocomma ')' sym '(' oarg_type_list_ocomma ')' fnres { Node *rcvr, *t; Node *name; name = newname($4); $2 = checkarglist($2, 0); $6 = checkarglist($6, 1); $$ = N; if($2 == nil) { yyerror("method has no receiver"); break; } if($2->next != nil) { yyerror("method has multiple receivers"); break; } rcvr = $2->n; if(rcvr->op != ODCLFIELD) { yyerror("bad receiver in method"); break; } if(rcvr->right->op == OTPAREN || (rcvr->right->op == OIND && rcvr->right->left->op == OTPAREN)) yyerror("cannot parenthesize receiver type"); $$ = nod(ODCLFUNC, N, N); $$->nname = methodname1(name, rcvr->right); t = nod(OTFUNC, rcvr, N); t->list = $6; t->rlist = $8; $$->nname->ntype = t; $$->shortname = name; funchdr($$); } fntype: LFUNC '(' oarg_type_list_ocomma ')' fnres { $3 = checkarglist($3, 1); $$ = nod(OTFUNC, N, N); $$->list = $3; $$->rlist = $5; } fnbody: { $$ = nil; } | '{' stmt_list '}' { $$ = $2; if($$ == nil) $$ = list1(nod(OEMPTY, N, N)); } fnres: %prec NotParen { $$ = nil; } | fnret_type { $$ = list1(nod(ODCLFIELD, N, $1)); } | '(' oarg_type_list_ocomma ')' { $2 = checkarglist($2, 0); $$ = $2; } fnlitdcl: fntype { closurehdr($1); } fnliteral: fnlitdcl lbrace stmt_list '}' { $$ = closurebody($3); fixlbrace($2); } | fnlitdcl error { $$ = closurebody(nil); } /* * lists of things * note that they are left recursive * to conserve yacc stack. they need to * be reversed to interpret correctly */ xdcl_list: { $$ = nil; } | xdcl_list xdcl ';' { $$ = concat($1, $2); if(nsyntaxerrors == 0) testdclstack(); } vardcl_list: vardcl | vardcl_list ';' vardcl { $$ = concat($1, $3); } constdcl_list: constdcl1 | constdcl_list ';' constdcl1 { $$ = concat($1, $3); } typedcl_list: typedcl { $$ = list1($1); } | typedcl_list ';' typedcl { $$ = list($1, $3); } structdcl_list: structdcl | structdcl_list ';' structdcl { $$ = concat($1, $3); } interfacedcl_list: interfacedcl { $$ = list1($1); } | interfacedcl_list ';' interfacedcl { $$ = list($1, $3); } structdcl: new_name_list ntype oliteral { NodeList *l; for(l=$1; l; l=l->next) { l->n = nod(ODCLFIELD, l->n, $2); l->n->val = $3; } } | embed oliteral { $1->val = $2; $$ = list1($1); } | '(' embed ')' oliteral { $2->val = $4; $$ = list1($2); yyerror("cannot parenthesize embedded type"); } | '*' embed oliteral { $2->right = nod(OIND, $2->right, N); $2->val = $3; $$ = list1($2); } | '(' '*' embed ')' oliteral { $3->right = nod(OIND, $3->right, N); $3->val = $5; $$ = list1($3); yyerror("cannot parenthesize embedded type"); } | '*' '(' embed ')' oliteral { $3->right = nod(OIND, $3->right, N); $3->val = $5; $$ = list1($3); yyerror("cannot parenthesize embedded type"); } packname: LNAME { Node *n; $$ = $1; n = oldname($1); if(n->pack != N) n->pack->used = 1; } | LNAME '.' sym { Pkg *pkg; if($1->def == N || $1->def->op != OPACK) { yyerror("%S is not a package", $1); pkg = localpkg; } else { $1->def->used = 1; pkg = $1->def->pkg; } $$ = restrictlookup($3->name, pkg); } embed: packname { $$ = embedded($1); } interfacedcl: new_name indcl { $$ = nod(ODCLFIELD, $1, $2); ifacedcl($$); } | packname { $$ = nod(ODCLFIELD, N, oldname($1)); } | '(' packname ')' { $$ = nod(ODCLFIELD, N, oldname($2)); yyerror("cannot parenthesize embedded type"); } indcl: '(' oarg_type_list_ocomma ')' fnres { // without func keyword $2 = checkarglist($2, 1); $$ = nod(OTFUNC, fakethis(), N); $$->list = $2; $$->rlist = $4; } /* * function arguments. */ arg_type: name_or_type | sym name_or_type { $$ = nod(ONONAME, N, N); $$->sym = $1; $$ = nod(OKEY, $$, $2); } | sym dotdotdot { $$ = nod(ONONAME, N, N); $$->sym = $1; $$ = nod(OKEY, $$, $2); } | dotdotdot arg_type_list: arg_type { $$ = list1($1); } | arg_type_list ',' arg_type { $$ = list($1, $3); } oarg_type_list_ocomma: { $$ = nil; } | arg_type_list ocomma { $$ = $1; } /* * statement */ stmt: { $$ = N; } | compound_stmt | common_dcl { $$ = liststmt($1); } | non_dcl_stmt | error { $$ = N; } non_dcl_stmt: simple_stmt | for_stmt | switch_stmt | select_stmt | if_stmt | labelname ':' { $1 = nod(OLABEL, $1, N); $1->sym = dclstack; // context, for goto restrictions } stmt { NodeList *l; $1->defn = $4; l = list1($1); if($4) l = list(l, $4); $$ = liststmt(l); } | LFALL { // will be converted to OFALL $$ = nod(OXFALL, N, N); } | LBREAK onew_name { $$ = nod(OBREAK, $2, N); } | LCONTINUE onew_name { $$ = nod(OCONTINUE, $2, N); } | LGO pseudocall { $$ = nod(OPROC, $2, N); } | LDEFER pseudocall { $$ = nod(ODEFER, $2, N); } | LGOTO new_name { $$ = nod(OGOTO, $2, N); $$->sym = dclstack; // context, for goto restrictions } | LRETURN oexpr_list { $$ = nod(ORETURN, N, N); $$->list = $2; if($$->list == nil) { NodeList *l; for(l=curfn->dcl; l; l=l->next) { if(l->n->class == PPARAM) continue; if(l->n->class != PPARAMOUT) break; if(l->n->sym->def != l->n) yyerror("%s is shadowed during return", l->n->sym->name); } } } stmt_list: stmt { $$ = nil; if($1 != N) $$ = list1($1); } | stmt_list ';' stmt { $$ = $1; if($3 != N) $$ = list($$, $3); } new_name_list: new_name { $$ = list1($1); } | new_name_list ',' new_name { $$ = list($1, $3); } dcl_name_list: dcl_name { $$ = list1($1); } | dcl_name_list ',' dcl_name { $$ = list($1, $3); } expr_list: expr { $$ = list1($1); } | expr_list ',' expr { $$ = list($1, $3); } expr_or_type_list: expr_or_type { $$ = list1($1); } | expr_or_type_list ',' expr_or_type { $$ = list($1, $3); } /* * list of combo of keyval and val */ keyval_list: keyval { $$ = list1($1); } | complitexpr { $$ = list1($1); } | keyval_list ',' keyval { $$ = list($1, $3); } | keyval_list ',' complitexpr { $$ = list($1, $3); } braced_keyval_list: { $$ = nil; } | keyval_list ocomma { $$ = $1; } /* * optional things */ osemi: | ';' ocomma: | ',' oexpr: { $$ = N; } | expr oexpr_list: { $$ = nil; } | expr_list osimple_stmt: { $$ = N; } | simple_stmt ohidden_funarg_list: { $$ = nil; } | hidden_funarg_list ohidden_structdcl_list: { $$ = nil; } | hidden_structdcl_list ohidden_interfacedcl_list: { $$ = nil; } | hidden_interfacedcl_list oliteral: { $$.ctype = CTxxx; } | LLITERAL /* * import syntax from header of * an output package */ hidden_import: LIMPORT sym LLITERAL ';' { // Informational: record package name // associated with import path, for use in // human-readable messages. Pkg *p; p = mkpkg($3.u.sval); if(p->name == nil) { p->name = $2->name; pkglookup($2->name, nil)->npkg++; } else if(strcmp(p->name, $2->name) != 0) yyerror("conflicting names %s and %s for package \"%Z\"", p->name, $2->name, p->path); if(!incannedimport && myimportpath != nil && strcmp($3.u.sval->s, myimportpath) == 0) { yyerror("import \"%Z\": package depends on \"%Z\" (import cycle)", importpkg->path, $3.u.sval); errorexit(); } } | LVAR hidden_pkg_importsym hidden_type ';' { importvar($2, $3, PEXTERN); } | LCONST hidden_pkg_importsym '=' hidden_constant ';' { importconst($2, types[TIDEAL], $4); } | LCONST hidden_pkg_importsym hidden_type '=' hidden_constant ';' { importconst($2, $3, $5); } | LTYPE hidden_pkgtype hidden_type ';' { importtype($2, $3); } | LFUNC hidden_pkg_importsym '(' ohidden_funarg_list ')' ohidden_funres ';' { importvar($2, functype(N, $4, $6), PFUNC); } | LFUNC '(' hidden_funarg_list ')' sym '(' ohidden_funarg_list ')' ohidden_funres ';' { if($3->next != nil || $3->n->op != ODCLFIELD) { yyerror("bad receiver in method"); YYERROR; } importmethod($5, functype($3->n, $7, $9)); } hidden_pkgtype: hidden_pkg_importsym { $$ = pkgtype($1); importsym($1, OTYPE); } hidden_type: hidden_type_misc | hidden_type_recv_chan | hidden_type_func hidden_type_non_recv_chan: hidden_type_misc | hidden_type_func hidden_type_misc: hidden_importsym { $$ = pkgtype($1); } | LNAME { // predefined name like uint8 $1 = pkglookup($1->name, builtinpkg); if($1->def == N || $1->def->op != OTYPE) { yyerror("%s is not a type", $1->name); $$ = T; } else $$ = $1->def->type; } | '[' ']' hidden_type { $$ = aindex(N, $3); } | '[' LLITERAL ']' hidden_type { $$ = aindex(nodlit($2), $4); } | LMAP '[' hidden_type ']' hidden_type { $$ = maptype($3, $5); } | LSTRUCT '{' ohidden_structdcl_list '}' { $$ = tostruct($3); } | LINTERFACE '{' ohidden_interfacedcl_list '}' { $$ = tointerface($3); } | '*' hidden_type { $$ = ptrto($2); } | LCHAN hidden_type_non_recv_chan { $$ = typ(TCHAN); $$->type = $2; $$->chan = Cboth; } | LCHAN '(' hidden_type_recv_chan ')' { $$ = typ(TCHAN); $$->type = $3; $$->chan = Cboth; } | LCHAN LCOMM hidden_type { $$ = typ(TCHAN); $$->type = $3; $$->chan = Csend; } hidden_type_recv_chan: LCOMM LCHAN hidden_type { $$ = typ(TCHAN); $$->type = $3; $$->chan = Crecv; } hidden_type_func: LFUNC '(' ohidden_funarg_list ')' ohidden_funres { $$ = functype(nil, $3, $5); } hidden_opt_sym: sym { $$ = newname($1); } | '?' { $$ = N; } hidden_dcl: hidden_opt_sym hidden_type oliteral { $$ = nod(ODCLFIELD, $1, typenod($2)); $$->val = $3; } | hidden_opt_sym LDDD hidden_type oliteral { Type *t; t = typ(TARRAY); t->bound = -1; t->type = $3; $$ = nod(ODCLFIELD, $1, typenod(t)); $$->isddd = 1; $$->val = $4; } hidden_structdcl: sym hidden_type oliteral { $$ = nod(ODCLFIELD, newname($1), typenod($2)); $$->val = $3; } | '?' hidden_type oliteral { Sym *s; s = $2->sym; if(s == S && isptr[$2->etype]) s = $2->type->sym; if(s && s->pkg == builtinpkg) s = lookup(s->name); $$ = embedded(s); $$->right = typenod($2); $$->val = $3; } hidden_interfacedcl: sym '(' ohidden_funarg_list ')' ohidden_funres { $$ = nod(ODCLFIELD, newname($1), typenod(functype(fakethis(), $3, $5))); } ohidden_funres: { $$ = nil; } | hidden_funres hidden_funres: '(' ohidden_funarg_list ')' { $$ = $2; } | hidden_type { $$ = list1(nod(ODCLFIELD, N, typenod($1))); } hidden_literal: LLITERAL { $$ = nodlit($1); } | '-' LLITERAL { $$ = nodlit($2); switch($$->val.ctype){ case CTINT: mpnegfix($$->val.u.xval); break; case CTFLT: mpnegflt($$->val.u.fval); break; default: yyerror("bad negated constant"); } } | sym { $$ = oldname(pkglookup($1->name, builtinpkg)); if($$->op != OLITERAL) yyerror("bad constant %S", $$->sym); } hidden_constant: hidden_literal | '(' hidden_literal '+' hidden_literal ')' { $$ = nodcplxlit($2->val, $4->val); } hidden_pkg_importsym: hidden_importsym { $$ = $1; structpkg = $$->pkg; } hidden_import_list: | hidden_import_list hidden_import hidden_funarg_list: hidden_dcl { $$ = list1($1); } | hidden_funarg_list ',' hidden_dcl { $$ = list($1, $3); } hidden_structdcl_list: hidden_structdcl { $$ = list1($1); } | hidden_structdcl_list ';' hidden_structdcl { $$ = list($1, $3); } hidden_interfacedcl_list: hidden_interfacedcl { $$ = list1($1); } | hidden_interfacedcl_list ';' hidden_interfacedcl { $$ = list($1, $3); } %% static void fixlbrace(int lbr) { // If the opening brace was an LBODY, // set up for another one now that we're done. // See comment in lex.c about loophack. if(lbr == LBODY) loophack = 1; }