// 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. %{ #include "go.h" %} %union { Node* node; Type* type; Sym* sym; struct Val val; int lint; } %token LLITERAL %token LASOP %token LNAME LBASETYPE LATYPE LPACK LACONST %token LPACKAGE LIMPORT LEXPORT %token LMAP LCHAN LINTERFACE LFUNC LSTRUCT %token LCOLAS LFALL LRETURN %token LNEW LLEN %token LVAR LTYPE LCONST LCONVERT LSELECT %token LFOR LIF LELSE LSWITCH LCASE LDEFAULT %token LBREAK LCONTINUE LGO LGOTO LRANGE %token LNIL LTRUE LFALSE LIOTA %token LPANIC LPRINT LIGNORE %token LOROR LANDAND LEQ LNE LLE LLT LGE LGT %token LLSH LRSH LINC LDEC LSEND LRECV %type sym sym1 sym2 key1 key2 laconst lname latype %type chandir %type xdcl xdcl_list_r oxdcl_list %type common_dcl Acommon_dcl Bcommon_dcl %type oarg_type_list arg_type_list_r arg_type %type else_stmt1 else_stmt2 inc_stmt noninc_stmt %type complex_stmt compound_stmt ostmt_list %type stmt_list_r Astmt_list_r Bstmt_list_r %type Astmt Bstmt Cstmt Dstmt %type for_stmt for_body for_header %type if_stmt if_body if_header %type range_header range_body range_stmt select_stmt %type simple_stmt osimple_stmt semi_stmt %type expr uexpr pexpr expr_list oexpr oexpr_list expr_list_r %type name name_name new_name new_name_list_r conexpr %type vardcl_list_r vardcl Avardcl Bvardcl %type interfacedcl_list_r interfacedcl %type structdcl_list_r structdcl %type hidden_importsym_list_r ohidden_importsym_list hidden_importsym isym %type hidden_importfield_list_r ohidden_importfield_list hidden_importfield %type fnres Afnres Bfnres fnliteral xfndcl fndcl fnbody %type keyval_list_r keyval %type typedcl Atypedcl Btypedcl %type fntype fnlitdcl intype new_type typeconv %type type Atype Btype fntypeh Afntypeh Bfntypeh %left LOROR %left LANDAND %left LSEND LRECV %left LEQ LNE LLE LGE LLT LGT %left '+' '-' '|' '^' %left '*' '/' '%' '&' LLSH LRSH %% file: package import_there imports oxdcl_list { if(debug['f']) frame(1); fninit($4); testdclstack(); } package: { yyerror("package statement must be first"); mkpackage("main"); cannedimports(); } | LPACKAGE sym { mkpackage($2->name); cannedimports(); } imports: | imports import import: LIMPORT import_stmt | LIMPORT '(' import_stmt_list_r osemi ')' import_stmt: import_here import_package import_there import_here: LLITERAL { // import with original name pkgmyname = S; importfile(&$1); } | sym LLITERAL { // import with given name pkgmyname = $1; pkgmyname->lexical = LPACK; importfile(&$2); } | '.' LLITERAL { // import with my name pkgmyname = lookup(package); importfile(&$2); } import_package: LPACKAGE sym { pkgimportname = $2; // if we are not remapping the package name // then the imported package name is LPACK if(pkgmyname == S) pkgimportname->lexical = LPACK; } import_there: hidden_import_list_r ')' ')' { unimportfile(); } | LIMPORT '(' '(' hidden_import_list_r ')' ')' /* * declarations */ xdcl: common_dcl | xfndcl { $$ = N; } | LEXPORT export_list_r { $$ = N; } | LEXPORT { exportadj = 1; } common_dcl { $$ = $3; exportadj = 0; } | LEXPORT '(' export_list_r ')' { $$ = N; } | LEXPORT xfndcl { if($2 != N && $2->nname != N) exportsym($2->nname->sym); $$ = N; } | ';' { $$ = N; } | error xdcl { $$ = $2; } common_dcl: Acommon_dcl | Bcommon_dcl Acommon_dcl: LVAR Avardcl { $$ = $2; } | LVAR '(' vardcl_list_r osemi ')' { $$ = rev($3); } | LCONST '(' constdcl_list_r osemi ')' { iota = 0; lastconst = N; $$ = N; } | LTYPE Atypedcl { $$ = N; } | LTYPE '(' typedcl_list_r osemi ')' { $$ = N; } Bcommon_dcl: LVAR Bvardcl { $$ = $2; } | LCONST constdcl { $$ = N; iota = 0; lastconst = N; } | LTYPE Btypedcl { $$ = N; } vardcl: Avardcl | Bvardcl Avardcl: new_name_list_r Atype { $$ = rev($1); dodclvar($$, $2); $$ = nod(OAS, $$, N); } Bvardcl: new_name_list_r Btype { $$ = rev($1); dodclvar($$, $2); $$ = nod(OAS, $$, N); } | new_name_list_r type '=' oexpr_list { $$ = rev($1); dodclvar($$, $2); $$ = nod(OAS, $$, $4); } | new_name '=' expr { walktype($3, Erv); // this is a little harry defaultlit($3); dodclvar($1, $3->type); $$ = nod(OAS, $1, $3); } constdcl: new_name conexpr { walktype($2, Erv); dodclconst($1, $2); } | new_name type conexpr { walktype($3, Erv); convlit($3, $2); dodclconst($1, $3); } conexpr: { if(lastconst == N) yyerror("first constant must evaluate an expression"); $$ = treecopy(lastconst); iota += 1; } | '=' expr { lastconst = $2; $$ = treecopy(lastconst); iota += 1; } typedcl: Atypedcl | Btypedcl Atypedcl: new_type Atype { dodcltype($1, $2); } Btypedcl: new_type Btype { dodcltype($1, $2); } else_stmt1: complex_stmt | compound_stmt else_stmt2: simple_stmt | semi_stmt | ';' { $$ = N; } simple_stmt: inc_stmt | noninc_stmt noninc_stmt: expr { $$ = $1; } | expr LASOP expr { $$ = nod(OASOP, $1, $3); $$->etype = $2; // rathole to pass opcode } | expr_list '=' expr_list { $$ = nod(OAS, $1, $3); } | expr_list LCOLAS expr_list { $$ = nod(OAS, colas($1, $3), $3); } inc_stmt: expr LINC { $$ = nod(OASOP, $1, literal(1)); $$->etype = OADD; } | expr LDEC { $$ = nod(OASOP, $1, literal(1)); $$->etype = OSUB; } complex_stmt: LFOR for_stmt { popdcl(); $$ = $2; } | LSWITCH if_stmt { popdcl(); $$ = $2; $$->op = OSWITCH; //if($$->ninit != N && $$->ntest == N) // yyerror("switch expression should not be missing"); } | LIF if_stmt { popdcl(); $$ = $2; //if($$->ninit != N && $$->ntest == N) // yyerror("if conditional should not be missing"); } | LIF if_stmt LELSE else_stmt1 { popdcl(); $$ = $2; $$->nelse = $4; //if($$->ninit != N && $$->ntest == N) // yyerror("if conditional should not be missing"); } | LSELECT select_stmt { popdcl(); $$ = $2; } | LRANGE range_stmt { popdcl(); $$ = $2; } | LCASE expr_list ':' { // will be converted to OCASE // right will point to next case // done in casebody() poptodcl(); $$ = nod(OXCASE, $2, N); } | LDEFAULT ':' { poptodcl(); $$ = nod(OXCASE, N, N); } semi_stmt: LFALL { // will be converted to OFALL $$ = nod(OXFALL, N, N); } | LBREAK oexpr { $$ = nod(OBREAK, $2, N); } | LCONTINUE oexpr { $$ = nod(OCONTINUE, $2, N); } | LGO pexpr '(' oexpr_list ')' { $$ = nod(OCALL, $2, $4); $$ = nod(OPROC, $$, N); } | LPRINT '(' oexpr_list ')' { $$ = nod(OPRINT, $3, N); } | LPANIC '(' oexpr_list ')' { $$ = nod(OPANIC, $3, N); } | LGOTO new_name { $$ = nod(OGOTO, $2, N); } | LRETURN oexpr_list { $$ = nod(ORETURN, $2, N); } | LIF if_stmt LELSE else_stmt2 { popdcl(); $$ = $2; $$->nelse = $4; //if($$->ninit != N && $$->ntest == N) // yyerror("if conditional should not be missing"); } compound_stmt: '{' { markdcl(); } ostmt_list '}' { $$ = $3; if($$ == N) $$ = nod(OEMPTY, N, N); popdcl(); } for_header: osimple_stmt ';' osimple_stmt ';' osimple_stmt { // init ; test ; incr $$ = nod(OFOR, N, N); $$->ninit = $1; $$->ntest = $3; $$->nincr = $5; } | osimple_stmt { // test $$ = nod(OFOR, N, N); $$->ninit = N; $$->ntest = $1; $$->nincr = N; } for_body: for_header compound_stmt { $$ = $1; $$->nbody = $2; } for_stmt: { markdcl(); } for_body { $$ = $2; } if_header: osimple_stmt { // test $$ = nod(OIF, N, N); $$->ninit = N; $$->ntest = $1; } | osimple_stmt ';' osimple_stmt { // init ; test $$ = nod(OIF, N, N); $$->ninit = $1; $$->ntest = $3; } if_body: if_header compound_stmt { $$ = $1; $$->nbody = $2; } if_stmt: { markdcl(); } if_body { $$ = $2; } range_header: new_name LCOLAS expr { $$ = N; } | new_name ',' new_name LCOLAS expr { $$ = N; } | new_name ',' new_name '=' expr { yyerror("range statement only allows := assignment"); $$ = N; } range_body: range_header compound_stmt { $$ = $1; $$->nbody = $2; } range_stmt: { markdcl(); } range_body { $$ = $2; } select_stmt: { markdcl(); } compound_stmt { $$ = nod(OSELECT, $2, N); } /* * 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 LLSH expr { $$ = nod(OLSH, $1, $3); } | expr LRSH expr { $$ = nod(ORSH, $1, $3); } | expr LSEND expr { $$ = nod(OSEND, $1, $3); } | expr LRECV expr { $$ = nod(ORECV, $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 OCOM operator is ^"); $$ = nod(OCOM, $2, N); } | '^' uexpr { $$ = nod(OCOM, $2, N); } | LRECV uexpr { $$ = nod(ORECV, $2, N); } pexpr: LLITERAL { $$ = nod(OLITERAL, N, N); $$->val = $1; } | laconst { $$ = nod(OLITERAL, N, N); $$->val = $1->oconst->val; $$->type = $1->oconst->type; } | LNIL { $$ = nod(OLITERAL, N, N); $$->val.ctype = CTNIL; } | LTRUE { $$ = booltrue; } | LFALSE { $$ = boolfalse; } | LIOTA { $$ = literal(iota); $$->iota = 1; // flag to reevaluate on copy } | name | '(' expr ')' { $$ = $2; } | pexpr '.' sym2 { $$ = nod(ODOT, $1, newname($3)); } | pexpr '.' '(' type ')' { $$ = nod(OCONV, $1, N); $$->type = $4; } | pexpr '[' expr ']' { $$ = nod(OINDEX, $1, $3); } | pexpr '[' keyval ']' { $$ = nod(OSLICE, $1, $3); } | pexpr '(' oexpr_list ')' { $$ = nod(OCALL, $1, $3); } | LLEN '(' expr ')' { $$ = nod(OLEN, $3, N); } | LNEW '(' type ')' { $$ = nod(ONEW, N, N); $$->type = ptrto($3); } | LNEW '(' type ',' expr_list ')' { $$ = nod(ONEW, $5, N); $$->type = ptrto($3); } | fnliteral | '[' expr_list ']' { // array literal $$ = N; } | '[' keyval_list_r ']' { // map literal $$ = N; } | typeconv '(' oexpr_list ')' { // struct literal and conversions $$ = nod(OCONV, $3, N); $$->type = $1; } | LCONVERT '(' type ',' expr ')' { $$ = nod(OCONV, $5, N); $$->type = $3; } /* * lexical symbols that can be * from other packages */ lpack: LPACK { context = $1->name; } laconst: LACONST | lpack '.' LACONST { $$ = $3; context = nil; } lname: LNAME | lpack '.' LNAME { $$ = $3; context = nil; } latype: LATYPE | lpack '.' LATYPE { $$ = $3; context = nil; } /* * names and types * newname is used before declared * oldname is used after declared */ name_name: LNAME { $$ = newname($1); } new_name: sym1 { $$ = newname($1); } new_type: sym1 { $$ = newtype($1); } sym: LATYPE | LNAME | LACONST | LPACK sym1: sym | key1 sym2: sym | key1 | key2 /* * keywords that we can * use as variable/type names */ key1: LNIL | LTRUE | LFALSE | LIOTA | LLEN | LPANIC | LPRINT | LNEW | LBASETYPE /* * keywords that we can * use as field names */ key2: LPACKAGE | LIMPORT | LEXPORT | LMAP | LCHAN | LINTERFACE | LFUNC | LSTRUCT | LFALL | LRETURN | LVAR | LTYPE | LCONST | LCONVERT | LSELECT | LFOR | LIF | LELSE | LSWITCH | LCASE | LDEFAULT | LBREAK | LCONTINUE | LGO | LGOTO | LRANGE | LIGNORE name: lname { $$ = oldname($1); } typeconv: latype { $$ = oldtype($1); } | '[' ']' typeconv { $$ = aindex(N, $3); } | LCHAN chandir typeconv { $$ = typ(TCHAN); $$->type = $3; $$->chan = $2; } | LMAP '[' typeconv ']' typeconv { $$ = typ(TMAP); $$->down = $3; $$->type = $5; } type: Atype | Btype Atype: latype { $$ = oldtype($1); } | '[' oexpr ']' Atype { $$ = aindex($2, $4); } | LCHAN chandir Atype { $$ = typ(TCHAN); $$->type = $3; $$->chan = $2; } | LMAP '[' type ']' Atype { $$ = typ(TMAP); $$->down = $3; $$->type = $5; } | LSTRUCT '{' structdcl_list_r osemi '}' { $$ = dostruct(rev($3), TSTRUCT); } | LSTRUCT '{' '}' { $$ = dostruct(N, TSTRUCT); } | LINTERFACE '{' interfacedcl_list_r osemi '}' { $$ = dostruct(rev($3), TINTER); $$ = sortinter($$); } | LINTERFACE '{' '}' { $$ = dostruct(N, TINTER); } | Afntypeh | '*' Atype { $$ = ptrto($2); } Btype: '[' oexpr ']' Btype { $$ = aindex($2, $4); } | LCHAN chandir Btype { $$ = typ(TCHAN); $$->type = $3; $$->chan = $2; } | LMAP '[' type ']' Btype { $$ = typ(TMAP); $$->down = $3; $$->type = $5; } | Bfntypeh | '*' Btype { $$ = ptrto($2); } | '*' lname { // dont know if this is an error or not if(dclcontext != PEXTERN) yyerror("forward type in function body %s", $2->name); $$ = forwdcl($2); } chandir: { $$ = Cboth; } | LRECV { $$ = Crecv; } | LSEND { $$ = Csend; } keyval: expr ':' expr { $$ = nod(OLIST, $1, $3); } /* * function stuff * all in one place to show how crappy it all is */ xfndcl: LFUNC { maxarg = 0; stksize = 0; } fndcl fnbody { $$ = $3; $$->nbody = $4; funcbody($$); } fndcl: new_name '(' oarg_type_list ')' fnres { b0stack = dclstack; // mark base for fn literals $$ = nod(ODCLFUNC, N, N); $$->nname = $1; if($3 == N && $5 == N) $$->nname = renameinit($1); $$->type = functype(N, $3, $5); funchdr($$); } | '(' oarg_type_list ')' new_name '(' oarg_type_list ')' fnres { b0stack = dclstack; // mark base for fn literals if($2 == N || $2->op == OLIST) yyerror("syntax error in method receiver"); $$ = nod(ODCLFUNC, N, N); $$->nname = methodname($4, $2->type); $$->type = functype($2, $6, $8); funchdr($$); } fntypeh: Afntypeh | Bfntypeh Afntypeh: LFUNC '(' oarg_type_list ')' Afnres { $$ = functype(N, $3, $5); funcnam($$, nil); } | LFUNC '(' oarg_type_list ')' '.' '(' oarg_type_list ')' Afnres /* i dont believe that this form is useful for anything */ { if($3 == N || $3->op == OLIST) yyerror("syntax error in method receiver"); $$ = functype($3, $7, $9); funcnam($$, nil); } Bfntypeh: LFUNC '(' oarg_type_list ')' Bfnres { $$ = functype(N, $3, $5); funcnam($$, nil); } | LFUNC '(' oarg_type_list ')' '.' '(' oarg_type_list ')' Bfnres /* i dont believe that this form is useful for anything */ { if($3 == N || $3->op == OLIST) yyerror("syntax error in method receiver"); $$ = functype($3, $7, $9); funcnam($$, nil); } fntype: fntypeh | latype { $$ = oldtype($1); if($$ == T || $$->etype != TFUNC) yyerror("illegal type for function literal"); } fnlitdcl: fntype { markdclstack(); // save dcl stack and revert to block0 $$ = $1; funcargs($$); } fnliteral: fnlitdcl '{' ostmt_list '}' { popdcl(); vargen++; snprint(namebuf, sizeof(namebuf), "_f%.3ld", vargen); $$ = newname(lookup(namebuf)); addvar($$, $1, PEXTERN); { Node *n; n = nod(ODCLFUNC, N, N); n->nname = $$; n->type = $1; n->nbody = $3; if(n->nbody == N) n->nbody = nod(ORETURN, N, N); compile(n); } $$ = nod(OADDR, $$, N); } fnbody: '{' ostmt_list '}' { $$ = $2; if($$ == N) $$ = nod(ORETURN, N, N); } | ';' { $$ = N; } fnres: Afnres | Bfnres Afnres: Atype { $$ = nod(ODCLFIELD, N, N); $$->type = $1; $$ = cleanidlist($$); } | '(' oarg_type_list ')' { $$ = $2; } Bfnres: { $$ = N; } | Btype { $$ = nod(ODCLFIELD, N, N); $$->type = $1; $$ = cleanidlist($$); } /* * lists of things * note that they are left recursive * to conserve yacc stack. they need to * be reversed to interpret correctly */ xdcl_list_r: xdcl | xdcl_list_r xdcl { $$ = list($1, $2); } vardcl_list_r: vardcl | vardcl_list_r ';' vardcl { $$ = nod(OLIST, $1, $3); } constdcl_list_r: constdcl | constdcl_list_r ';' constdcl typedcl_list_r: typedcl | typedcl_list_r ';' typedcl structdcl_list_r: structdcl { $$ = cleanidlist($1); } | structdcl_list_r ';' structdcl { $$ = cleanidlist($3); $$ = nod(OLIST, $1, $$); } interfacedcl_list_r: interfacedcl { $$ = cleanidlist($1); } | interfacedcl_list_r ';' interfacedcl { $$ = cleanidlist($3); $$ = nod(OLIST, $1, $$); } structdcl: new_name ',' structdcl { $$ = nod(ODCLFIELD, $1, N); $$ = nod(OLIST, $$, $3); } | new_name type { $$ = nod(ODCLFIELD, $1, N); $$->type = $2; } interfacedcl: new_name ',' interfacedcl { $$ = nod(ODCLFIELD, $1, N); $$ = nod(OLIST, $$, $3); } | new_name intype { $$ = nod(ODCLFIELD, $1, N); $$->type = $2; } intype: '(' oarg_type_list ')' fnres { // without func keyword $$ = functype(fakethis(), $2, $4); funcnam($$, nil); } | LFUNC '(' oarg_type_list ')' fnres { // with func keyword $$ = functype(fakethis(), $3, $5); funcnam($$, nil); } | latype { $$ = oldtype($1); if($$ == T || $$->etype != TFUNC) yyerror("illegal type for function literal"); } arg_type: name_name { $$ = nod(ODCLFIELD, $1, N); } | type { $$ = nod(ODCLFIELD, N, N); $$->type = $1; } | new_name type { $$ = nod(ODCLFIELD, $1, N); $$->type = $2; } arg_type_list_r: arg_type | arg_type_list_r ',' arg_type { $$ = nod(OLIST, $1, $3); } /* * need semi in front NO * need semi in back NO */ Astmt: complex_stmt | compound_stmt | Acommon_dcl | ';' { $$ = N; } | error Astmt { $$ = N; } /* * need semi in front NO * need semi in back YES */ Bstmt: semi_stmt | Bcommon_dcl | error Bstmt { $$ = N; } /* * need semi in front YES * need semi in back YES */ Cstmt: noninc_stmt /* * need semi in front YES * need semi in back NO */ Dstmt: inc_stmt | new_name ':' { $$ = nod(OLABEL, $1, N); } /* * statement list that ends AorD */ Astmt_list_r: Astmt | Dstmt | Astmt_list_r Astmt { $$ = list($1, $2); } | Astmt_list_r Dstmt { $$ = list($1, $2); } | Bstmt_list_r Astmt { $$ = list($1, $2); } /* * statement list that ends BorC */ Bstmt_list_r: Bstmt | Cstmt | Astmt_list_r Bstmt { $$ = list($1, $2); } | Astmt_list_r Cstmt { $$ = list($1, $2); } | Bstmt_list_r Bstmt { $$ = list($1, $2); } stmt_list_r: Astmt_list_r | Bstmt_list_r expr_list_r: expr | expr_list_r ',' expr { $$ = nod(OLIST, $1, $3); } new_name_list_r: new_name | new_name_list_r ',' new_name { $$ = nod(OLIST, $1, $3); } export_list_r: export | export_list_r ocomma export export: sym { exportsym($1); } | sym '.' sym2 { exportsym(pkglookup($3->name, $1->name)); } import_stmt_list_r: import_stmt | import_stmt_list_r osemi import_stmt hidden_import_list_r: hidden_import | hidden_import_list_r hidden_import hidden_importsym_list_r: hidden_importsym | hidden_importsym_list_r hidden_importsym { $$ = nod(OLIST, $1, $2); } hidden_importfield_list_r: hidden_importfield | hidden_importfield_list_r hidden_importfield { $$ = nod(OLIST, $1, $2); } keyval_list_r: keyval | keyval_list_r ',' keyval { $$ = nod(OLIST, $1, $3); } /* * the one compromise of a * non-reversed list */ expr_list: expr_list_r { $$ = rev($1); } /* * optional things */ osemi: | ';' ocomma: | ',' oexpr: { $$ = N; } | expr oexpr_list: { $$ = N; } | expr_list osimple_stmt: { $$ = N; } | simple_stmt ostmt_list: { $$ = N; } | stmt_list_r { $$ = rev($1); } oxdcl_list: { $$ = N; } | xdcl_list_r { $$ = rev($1); } ohidden_importsym_list: { $$ = N; } | hidden_importsym_list_r { $$ = rev($1); } ohidden_importfield_list: { $$ = N; } | hidden_importfield_list_r { $$ = rev($1); } oarg_type_list: { $$ = N; } | arg_type_list_r { $$ = cleanidlist(rev($1)); } /* * import syntax from header of * an output package */ hidden_import: /* leftover import ignored */ LPACKAGE sym /* variables */ | LVAR hidden_importsym hidden_importsym { // var doimportv1($2, $3); } /* constants */ | LCONST hidden_importsym LLITERAL { doimportc1($2, &$3); } | LCONST hidden_importsym hidden_importsym LLITERAL { doimportc2($2, $3, &$4); } /* types */ | LTYPE hidden_importsym '[' hidden_importsym ']' hidden_importsym { // type map doimport1($2, $4, $6); } | LTYPE hidden_importsym '[' LLITERAL ']' hidden_importsym { // type array doimport2($2, &$4, $6); } | LTYPE hidden_importsym '(' ohidden_importsym_list ')' { // type function doimport3($2, $4); } | LTYPE hidden_importsym '{' ohidden_importfield_list '}' { // type structure doimport4($2, $4); } | LTYPE hidden_importsym LLITERAL { // type basic doimport5($2, &$3); } | LTYPE hidden_importsym '*' hidden_importsym { // type pointer doimport6($2, $4); } | LTYPE hidden_importsym LLT ohidden_importfield_list LGT { // type interface doimport7($2, $4); } | LTYPE hidden_importsym LLITERAL hidden_importsym { // type interface doimport8($2, &$3, $4); } isym: sym '.' sym2 { $$ = nod(OIMPORT, N, N); $$->osym = $1; $$->psym = $1; $$->sym = $3; renamepkg($$); } | '(' sym ')' sym '.' sym2 { $$ = nod(OIMPORT, N, N); $$->osym = $2; $$->psym = $4; $$->sym = $6; renamepkg($$); } hidden_importsym: isym | '!' isym { $$ = $2; $$->etype = 1; } hidden_importfield: sym isym { $$ = $2; $$->fsym = $1; }