| // 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. | 
 |  */ | 
 |  | 
 | %{ | 
 | package gc | 
 |  | 
 | import ( | 
 | 	"strings" | 
 | ) | 
 | %} | 
 | %union	{ | 
 | 	node *Node | 
 | 	list *NodeList | 
 | 	typ *Type | 
 | 	sym *Sym | 
 | 	val Val | 
 | 	i int | 
 | } | 
 |  | 
 | // |sed 's/.*	//' |9 fmt -l1 |sort |9 fmt -l50 | sed 's/^/%xxx		/' | 
 |  | 
 | %token	<val>	LLITERAL | 
 | %token	<i>	LASOP LCOLAS | 
 | %token	<sym>	LBREAK LCASE LCHAN LCONST LCONTINUE LDDD | 
 | %token	<sym>	LDEFAULT LDEFER LELSE LFALL LFOR LFUNC LGO LGOTO | 
 | %token	<sym>	LIF LIMPORT LINTERFACE LMAP LNAME | 
 | %token	<sym>	LPACKAGE LRANGE LRETURN LSELECT LSTRUCT LSWITCH | 
 | %token	<sym>	LTYPE LVAR | 
 |  | 
 | %token		LANDAND LANDNOT LBODY LCOMM LDEC LEQ LGE LGT | 
 | %token		LIGNORE LINC LLE LLSH LLT LNE LOROR LRSH | 
 |  | 
 | %type	<i>	lbrace import_here | 
 | %type	<sym>	sym packname | 
 | %type	<val>	oliteral | 
 |  | 
 | %type	<node>	stmt ntype | 
 | %type	<node>	arg_type | 
 | %type	<node>	case caseblock | 
 | %type	<node>	compound_stmt dotname embed expr complitexpr bare_complitexpr | 
 | %type	<node>	expr_or_type | 
 | %type	<node>	fndcl hidden_fndcl fnliteral | 
 | %type	<node>	for_body for_header for_stmt if_header if_stmt non_dcl_stmt | 
 | %type	<node>	interfacedcl keyval labelname name | 
 | %type	<node>	name_or_type non_expr_type | 
 | %type	<node>	new_name dcl_name oexpr typedclname | 
 | %type	<node>	onew_name | 
 | %type	<node>	osimple_stmt pexpr pexpr_no_paren | 
 | %type	<node>	pseudocall range_stmt select_stmt | 
 | %type	<node>	simple_stmt | 
 | %type	<node>	switch_stmt uexpr | 
 | %type	<node>	xfndcl typedcl start_complit | 
 |  | 
 | %type	<list>	xdcl fnbody fnres 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>	oexpr_list caseblock_list elseif elseif_list else stmt_list oarg_type_list_ocomma arg_type_list | 
 | %type	<list>	interfacedcl_list vardcl vardcl_list structdcl structdcl_list | 
 | %type	<list>	common_dcl constdcl constdcl1 constdcl_list typedcl_list | 
 |  | 
 | %type	<node>	convtype comptype dotdotdot | 
 | %type	<node>	indcl interfacetype structtype ptrtype | 
 | %type	<node>	recvchantype non_recvchantype othertype fnret_type fntype | 
 |  | 
 | %type	<sym>	hidden_importsym hidden_pkg_importsym | 
 |  | 
 | %type	<node>	hidden_constant hidden_literal hidden_funarg | 
 | %type	<node>	hidden_interfacedcl hidden_structdcl | 
 |  | 
 | %type	<list>	hidden_funres | 
 | %type	<list>	ohidden_funres | 
 | %type	<list>	hidden_funarg_list ohidden_funarg_list | 
 | %type	<list>	hidden_interfacedcl_list ohidden_interfacedcl_list | 
 | %type	<list>	hidden_structdcl_list ohidden_structdcl_list | 
 |  | 
 | %type	<typ>	hidden_type hidden_type_misc hidden_pkgtype | 
 | %type	<typ>	hidden_type_func | 
 | %type	<typ>	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 | 
 |  | 
 | // TODO(rsc): Add %error-verbose | 
 |  | 
 | %% | 
 | file: | 
 | 	loadsys | 
 | 	package | 
 | 	imports | 
 | 	xdcl_list | 
 | 	{ | 
 | 		xtop = concat(xtop, $4); | 
 | 	} | 
 |  | 
 | package: | 
 | 	%prec NotPackage | 
 | 	{ | 
 | 		prevlineno = lineno; | 
 | 		Yyerror("package statement must be first"); | 
 | 		errorexit(); | 
 | 	} | 
 | |	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'] != 0 { | 
 | 			cannedimports("runtime.Builtin", "package runtime\n\n$$\n\n"); | 
 | 		} else { | 
 | 			cannedimports("runtime.Builtin", runtimeimport); | 
 | 		} | 
 | 		curio.importsafe = true | 
 | 	} | 
 | 	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 | 
 | 	{ | 
 | 		ipkg := importpkg; | 
 | 		my := importmyname; | 
 | 		importpkg = nil; | 
 | 		importmyname = nil; | 
 |  | 
 | 		if my == nil { | 
 | 			my = Lookup(ipkg.Name); | 
 | 		} | 
 |  | 
 | 		pack := Nod(OPACK, nil, nil); | 
 | 		pack.Sym = my; | 
 | 		pack.Pkg = ipkg; | 
 | 		pack.Lineno = int32($1); | 
 |  | 
 | 		if strings.HasPrefix(my.Name, ".") { | 
 | 			importdot(ipkg, pack); | 
 | 			break; | 
 | 		} | 
 | 		if my.Name == "init" { | 
 | 			Yyerror("cannot import package as init - init must be a func"); | 
 | 			break; | 
 | 		} | 
 | 		if my.Name == "_" { | 
 | 			break; | 
 | 		} | 
 | 		if my.Def != nil { | 
 | 			lineno = int32($1); | 
 | 			redeclare(my, "as imported package name"); | 
 | 		} | 
 | 		my.Def = pack; | 
 | 		my.Lastlineno = int32($1); | 
 | 		my.Block = 1;	// at top level | 
 | 	} | 
 | |	import_here import_there | 
 | 	{ | 
 | 		// When an invalid import path is passed to importfile, | 
 | 		// it calls Yyerror and then sets up a fake import with | 
 | 		// no package statement. This allows us to test more | 
 | 		// than one invalid import statement in a single file. | 
 | 		if nerrors == 0 { | 
 | 			Fatal("phase error in import"); | 
 | 		} | 
 | 	} | 
 |  | 
 | import_stmt_list: | 
 | 	import_stmt | 
 | |	import_stmt_list ';' import_stmt | 
 |  | 
 | import_here: | 
 | 	LLITERAL | 
 | 	{ | 
 | 		// import with original name | 
 | 		$$ = parserline(); | 
 | 		importmyname = nil; | 
 | 		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 LNAME import_safety ';' | 
 | 	{ | 
 | 		if importpkg.Name == "" { | 
 | 			importpkg.Name = $2.Name; | 
 | 			numImport[$2.Name]++ | 
 | 		} else if importpkg.Name != $2.Name { | 
 | 			Yyerror("conflicting names %s and %s for package %q", importpkg.Name, $2.Name, importpkg.Path); | 
 | 		} | 
 | 		importpkg.Direct = 1; | 
 | 		importpkg.Safe = curio.importsafe | 
 |  | 
 | 		if safemode != 0 && !curio.importsafe { | 
 | 			Yyerror("cannot import unsafe package %q", importpkg.Path); | 
 | 		} | 
 | 	} | 
 |  | 
 | import_safety: | 
 | |	LNAME | 
 | 	{ | 
 | 		if $1.Name == "safe" { | 
 | 			curio.importsafe = true | 
 | 		} | 
 | 	} | 
 |  | 
 | 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, nil, $3); | 
 | 	} | 
 |  | 
 | constdcl1: | 
 | 	constdcl | 
 | |	dcl_name_list ntype | 
 | 	{ | 
 | 		$$ = constiter($1, $2, nil); | 
 | 	} | 
 | |	dcl_name_list | 
 | 	{ | 
 | 		$$ = constiter($1, nil, 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, true); | 
 | 	} | 
 |  | 
 | simple_stmt: | 
 | 	expr | 
 | 	{ | 
 | 		$$ = $1; | 
 |  | 
 | 		// These nodes do not carry line numbers. | 
 | 		// Since a bare name used as an expression is an error, | 
 | 		// introduce a wrapper node to give the correct line. | 
 | 		switch($$.Op) { | 
 | 		case ONAME, ONONAME, OTYPE, OPACK, OLITERAL: | 
 | 			$$ = Nod(OPAREN, $$, nil); | 
 | 			$$.Implicit = true; | 
 | 			break; | 
 | 		} | 
 | 	} | 
 | |	expr LASOP expr | 
 | 	{ | 
 | 		$$ = Nod(OASOP, $1, $3); | 
 | 		$$.Etype = uint8($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, nil, nil); | 
 | 		$$.List = $1; | 
 | 		$$.Rlist = $3; | 
 | 	} | 
 | |	expr_list LCOLAS expr_list | 
 | 	{ | 
 | 		if $3.N.Op == OTYPESW { | 
 | 			$$ = Nod(OTYPESW, nil, $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) || isblank($1.N) { | 
 | 				Yyerror("invalid variable name %s in type switch", Nconv($1.N, 0)); | 
 | 			} else { | 
 | 				$$.Left = dclname($1.N.Sym); | 
 | 			}  // it's a colas, so must not re-use an oldname. | 
 | 			break; | 
 | 		} | 
 | 		$$ = colas($1, $3, int32($2)); | 
 | 	} | 
 | |	expr LINC | 
 | 	{ | 
 | 		$$ = Nod(OASOP, $1, Nodintconst(1)); | 
 | 		$$.Implicit = true; | 
 | 		$$.Etype = OADD; | 
 | 	} | 
 | |	expr LDEC | 
 | 	{ | 
 | 		$$ = Nod(OASOP, $1, Nodintconst(1)); | 
 | 		$$.Implicit = true; | 
 | 		$$.Etype = OSUB; | 
 | 	} | 
 |  | 
 | case: | 
 | 	LCASE expr_or_type_list ':' | 
 | 	{ | 
 | 		var n, nn *Node | 
 |  | 
 | 		// will be converted to OCASE | 
 | 		// right will point to next case | 
 | 		// done in casebody() | 
 | 		markdcl(); | 
 | 		$$ = Nod(OXCASE, nil, nil); | 
 | 		$$.List = $2; | 
 | 		if typesw != nil && typesw.Right != nil { | 
 | 			n = typesw.Right.Left | 
 | 			if n != nil { | 
 | 				// 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 ':' | 
 | 	{ | 
 | 		var n *Node | 
 |  | 
 | 		// will be converted to OCASE | 
 | 		// right will point to next case | 
 | 		// done in casebody() | 
 | 		markdcl(); | 
 | 		$$ = Nod(OXCASE, nil, nil); | 
 | 		if $2.Next == nil { | 
 | 			n = Nod(OAS, $2.N, $4); | 
 | 		} else { | 
 | 			n = Nod(OAS2, nil, nil); | 
 | 			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, nil, nil); | 
 | 		$$.List = list1(colas($2, list1($4), int32($3))); | 
 | 	} | 
 | |	LDEFAULT ':' | 
 | 	{ | 
 | 		var n, nn *Node | 
 |  | 
 | 		markdcl(); | 
 | 		$$ = Nod(OXCASE, nil, nil); | 
 | 		if typesw != nil && typesw.Right != nil { | 
 | 			n = typesw.Right.Left | 
 | 			if n != nil { | 
 | 				// 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 '}' | 
 | 	{ | 
 | 		if $3 == nil { | 
 | 			$$ = Nod(OEMPTY, nil, nil); | 
 | 		} else { | 
 | 			$$ = 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; | 
 | 		$1.Xoffset = int64(block); | 
 | 	} | 
 | 	stmt_list | 
 | 	{ | 
 | 		// 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, nil, $4); | 
 | 		$$.List = $1; | 
 | 		$$.Etype = 0;	// := flag | 
 | 	} | 
 | |	expr_list LCOLAS LRANGE expr | 
 | 	{ | 
 | 		$$ = Nod(ORANGE, nil, $4); | 
 | 		$$.List = $1; | 
 | 		$$.Colas = true; | 
 | 		colasdefn($1, $$); | 
 | 	} | 
 | |	LRANGE expr | 
 | 	{ | 
 | 		$$ = Nod(ORANGE, nil, $2); | 
 | 		$$.Etype = 0; // := flag | 
 | 	} | 
 |  | 
 | for_header: | 
 | 	osimple_stmt ';' osimple_stmt ';' osimple_stmt | 
 | 	{ | 
 | 		// init ; test ; incr | 
 | 		if $5 != nil && $5.Colas { | 
 | 			Yyerror("cannot declare in the for-increment"); | 
 | 		} | 
 | 		$$ = Nod(OFOR, nil, nil); | 
 | 		if $1 != nil { | 
 | 			$$.Ninit = list1($1); | 
 | 		} | 
 | 		$$.Ntest = $3; | 
 | 		$$.Nincr = $5; | 
 | 	} | 
 | |	osimple_stmt | 
 | 	{ | 
 | 		// normal test | 
 | 		$$ = Nod(OFOR, nil, nil); | 
 | 		$$.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, nil, nil); | 
 | 		$$.Ntest = $1; | 
 | 	} | 
 | |	osimple_stmt ';' osimple_stmt | 
 | 	{ | 
 | 		// init ; test | 
 | 		$$ = Nod(OIF, nil, nil); | 
 | 		if $1 != nil { | 
 | 			$$.Ninit = list1($1); | 
 | 		} | 
 | 		$$.Ntest = $3; | 
 | 	} | 
 |  | 
 | /* IF cond body (ELSE IF cond body)* (ELSE block)? */ | 
 | if_stmt: | 
 | 	LIF | 
 | 	{ | 
 | 		markdcl(); | 
 | 	} | 
 | 	if_header | 
 | 	{ | 
 | 		if $3.Ntest == nil { | 
 | 			Yyerror("missing condition in if statement"); | 
 | 		} | 
 | 	} | 
 | 	loop_body | 
 | 	{ | 
 | 		$3.Nbody = $5; | 
 | 	} | 
 | 	elseif_list else | 
 | 	{ | 
 | 		var n *Node | 
 | 		var nn *NodeList | 
 |  | 
 | 		$$ = $3; | 
 | 		n = $3; | 
 | 		popdcl(); | 
 | 		for nn = concat($7, $8); nn != nil; nn = nn.Next { | 
 | 			if nn.N.Op == OIF { | 
 | 				popdcl(); | 
 | 			} | 
 | 			n.Nelse = list1(nn.N); | 
 | 			n = nn.N; | 
 | 		} | 
 | 	} | 
 |  | 
 | elseif: | 
 | 	LELSE LIF  | 
 | 	{ | 
 | 		markdcl(); | 
 | 	} | 
 | 	if_header loop_body | 
 | 	{ | 
 | 		if $4.Ntest == nil { | 
 | 			Yyerror("missing condition in if statement"); | 
 | 		} | 
 | 		$4.Nbody = $5; | 
 | 		$$ = list1($4); | 
 | 	} | 
 |  | 
 | elseif_list: | 
 | 	{ | 
 | 		$$ = nil; | 
 | 	} | 
 | |	elseif_list elseif | 
 | 	{ | 
 | 		$$ = concat($1, $2); | 
 | 	} | 
 |  | 
 | else: | 
 | 	{ | 
 | 		$$ = nil; | 
 | 	} | 
 | |	LELSE compound_stmt | 
 | 	{ | 
 | 		l := &NodeList{N: $2} | 
 | 		l.End = l | 
 | 		$$ = l; | 
 | 	} | 
 |  | 
 | switch_stmt: | 
 | 	LSWITCH | 
 | 	{ | 
 | 		markdcl(); | 
 | 	} | 
 | 	if_header | 
 | 	{ | 
 | 		var n *Node | 
 | 		n = $3.Ntest; | 
 | 		if n != nil && n.Op != OTYPESW { | 
 | 			n = nil; | 
 | 		} | 
 | 		typesw = Nod(OXXX, typesw, n); | 
 | 	} | 
 | 	LBODY caseblock_list '}' | 
 | 	{ | 
 | 		$$ = $3; | 
 | 		$$.Op = OSWITCH; | 
 | 		$$.List = $6; | 
 | 		typesw = typesw.Left; | 
 | 		popdcl(); | 
 | 	} | 
 |  | 
 | select_stmt: | 
 | 	LSELECT | 
 | 	{ | 
 | 		typesw = Nod(OXXX, typesw, nil); | 
 | 	} | 
 | 	LBODY caseblock_list '}' | 
 | 	{ | 
 | 		$$ = Nod(OSELECT, nil, nil); | 
 | 		$$.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, nil); | 
 | 	} | 
 | |	'&' uexpr | 
 | 	{ | 
 | 		if $2.Op == OCOMPLIT { | 
 | 			// Special case for &T{...}: turn into (*T){...}. | 
 | 			$$ = $2; | 
 | 			$$.Right = Nod(OIND, $$.Right, nil); | 
 | 			$$.Right.Implicit = true; | 
 | 		} else { | 
 | 			$$ = Nod(OADDR, $2, nil); | 
 | 		} | 
 | 	} | 
 | |	'+' uexpr | 
 | 	{ | 
 | 		$$ = Nod(OPLUS, $2, nil); | 
 | 	} | 
 | |	'-' uexpr | 
 | 	{ | 
 | 		$$ = Nod(OMINUS, $2, nil); | 
 | 	} | 
 | |	'!' uexpr | 
 | 	{ | 
 | 		$$ = Nod(ONOT, $2, nil); | 
 | 	} | 
 | |	'~' uexpr | 
 | 	{ | 
 | 		Yyerror("the bitwise complement operator is ^"); | 
 | 		$$ = Nod(OCOM, $2, nil); | 
 | 	} | 
 | |	'^' uexpr | 
 | 	{ | 
 | 		$$ = Nod(OCOM, $2, nil); | 
 | 	} | 
 | |	LCOMM uexpr | 
 | 	{ | 
 | 		$$ = Nod(ORECV, $2, nil); | 
 | 	} | 
 |  | 
 | /* | 
 |  * call-like statements that | 
 |  * can be preceded by 'defer' and 'go' | 
 |  */ | 
 | pseudocall: | 
 | 	pexpr '(' ')' | 
 | 	{ | 
 | 		$$ = Nod(OCALL, $1, nil); | 
 | 	} | 
 | |	pexpr '(' expr_or_type_list ocomma ')' | 
 | 	{ | 
 | 		$$ = Nod(OCALL, $1, nil); | 
 | 		$$.List = $3; | 
 | 	} | 
 | |	pexpr '(' expr_or_type_list LDDD ocomma ')' | 
 | 	{ | 
 | 		$$ = Nod(OCALL, $1, nil); | 
 | 		$$.List = $3; | 
 | 		$$.Isddd = true; | 
 | 	} | 
 |  | 
 | pexpr_no_paren: | 
 | 	LLITERAL | 
 | 	{ | 
 | 		$$ = nodlit($1); | 
 | 	} | 
 | |	name | 
 | |	pexpr '.' sym | 
 | 	{ | 
 | 		if $1.Op == OPACK { | 
 | 			var s *Sym | 
 | 			s = restrictlookup($3.Name, $1.Pkg); | 
 | 			$1.Used = true; | 
 | 			$$ = oldname(s); | 
 | 			break; | 
 | 		} | 
 | 		$$ = Nod(OXDOT, $1, newname($3)); | 
 | 	} | 
 | |	pexpr '.' '(' expr_or_type ')' | 
 | 	{ | 
 | 		$$ = Nod(ODOTTYPE, $1, $4); | 
 | 	} | 
 | |	pexpr '.' '(' LTYPE ')' | 
 | 	{ | 
 | 		$$ = Nod(OTYPESW, nil, $1); | 
 | 	} | 
 | |	pexpr '[' expr ']' | 
 | 	{ | 
 | 		$$ = Nod(OINDEX, $1, $3); | 
 | 	} | 
 | |	pexpr '[' oexpr ':' oexpr ']' | 
 | 	{ | 
 | 		$$ = Nod(OSLICE, $1, Nod(OKEY, $3, $5)); | 
 | 	} | 
 | |	pexpr '[' oexpr ':' oexpr ':' oexpr ']' | 
 | 	{ | 
 | 		if $5 == nil { | 
 | 			Yyerror("middle index required in 3-index slice"); | 
 | 		} | 
 | 		if $7 == nil { | 
 | 			Yyerror("final index required in 3-index slice"); | 
 | 		} | 
 | 		$$ = Nod(OSLICE3, $1, Nod(OKEY, $3, Nod(OKEY, $5, $7))); | 
 | 	} | 
 | |	pseudocall | 
 | |	convtype '(' expr ocomma ')' | 
 | 	{ | 
 | 		// conversion | 
 | 		$$ = Nod(OCALL, $1, nil); | 
 | 		$$.List = list1($3); | 
 | 	} | 
 | |	comptype lbrace start_complit braced_keyval_list '}' | 
 | 	{ | 
 | 		$$ = $3; | 
 | 		$$.Right = $1; | 
 | 		$$.List = $4; | 
 | 		fixlbrace($2); | 
 | 	} | 
 | |	pexpr_no_paren '{' start_complit braced_keyval_list '}' | 
 | 	{ | 
 | 		$$ = $3; | 
 | 		$$.Right = $1; | 
 | 		$$.List = $4; | 
 | 	} | 
 | |	'(' expr_or_type ')' '{' start_complit braced_keyval_list '}' | 
 | 	{ | 
 | 		Yyerror("cannot parenthesize type in composite literal"); | 
 | 		$$ = $5; | 
 | 		$$.Right = $2; | 
 | 		$$.List = $6; | 
 | 	} | 
 | |	fnliteral | 
 |  | 
 | start_complit: | 
 | 	{ | 
 | 		// composite expression. | 
 | 		// make node early so we get the right line number. | 
 | 		$$ = Nod(OCOMPLIT, nil, nil); | 
 | 	} | 
 |  | 
 | keyval: | 
 | 	expr ':' complitexpr | 
 | 	{ | 
 | 		$$ = Nod(OKEY, $1, $3); | 
 | 	} | 
 |  | 
 | bare_complitexpr: | 
 | 	expr | 
 | 	{ | 
 | 		// These nodes do not carry line numbers. | 
 | 		// Since a composite literal commonly spans several lines, | 
 | 		// the line number on errors may be misleading. | 
 | 		// Introduce a wrapper node to give the correct line. | 
 | 		$$ = $1; | 
 | 		switch($$.Op) { | 
 | 		case ONAME, ONONAME, OTYPE, OPACK, OLITERAL: | 
 | 			$$ = Nod(OPAREN, $$, nil); | 
 | 			$$.Implicit = true; | 
 | 		} | 
 | 	} | 
 | |	'{' start_complit braced_keyval_list '}' | 
 | 	{ | 
 | 		$$ = $2; | 
 | 		$$.List = $3; | 
 | 	} | 
 |  | 
 | complitexpr: | 
 | 	expr | 
 | |	'{' start_complit braced_keyval_list '}' | 
 | 	{ | 
 | 		$$ = $2; | 
 | 		$$.List = $3; | 
 | 	} | 
 |  | 
 | 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, ONONAME, OPACK, OTYPE, OLITERAL, OTYPESW: | 
 | 			$$ = Nod(OPAREN, $$, nil); | 
 | 		} | 
 | 	} | 
 |  | 
 | 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 | 
 | 	{ | 
 | 		if $1 == nil { | 
 | 			$$ = nil; | 
 | 		} else { | 
 | 			$$ = newname($1); | 
 | 		} | 
 | 	} | 
 |  | 
 | dcl_name: | 
 | 	sym | 
 | 	{ | 
 | 		$$ = dclname($1); | 
 | 	} | 
 |  | 
 | onew_name: | 
 | 	{ | 
 | 		$$ = nil; | 
 | 	} | 
 | |	new_name | 
 |  | 
 | sym: | 
 | 	LNAME | 
 | 	{ | 
 | 		$$ = $1; | 
 | 		// during imports, unqualified non-exported identifiers are from builtinpkg | 
 | 		if importpkg != nil && !exportname($1.Name) { | 
 | 			$$ = Pkglookup($1.Name, builtinpkg); | 
 | 		} | 
 | 	} | 
 | |	hidden_importsym | 
 | |	'?' | 
 | 	{ | 
 | 		$$ = nil; | 
 | 	} | 
 |  | 
 | hidden_importsym: | 
 | 	'@' LLITERAL '.' LNAME | 
 | 	{ | 
 | 		var p *Pkg | 
 |  | 
 | 		if $2.U.Sval == "" { | 
 | 			p = importpkg; | 
 | 		} else { | 
 | 			if isbadimport($2.U.Sval) { | 
 | 				errorexit(); | 
 | 			} | 
 | 			p = mkpkg($2.U.Sval); | 
 | 		} | 
 | 		$$ = Pkglookup($4.Name, p); | 
 | 	} | 
 | |	'@' LLITERAL '.' '?' | 
 | 	{ | 
 | 		var p *Pkg | 
 |  | 
 | 		if $2.U.Sval == "" { | 
 | 			p = importpkg; | 
 | 		} else { | 
 | 			if isbadimport($2.U.Sval) { | 
 | 				errorexit(); | 
 | 			} | 
 | 			p = mkpkg($2.U.Sval); | 
 | 		} | 
 | 		$$ = Pkglookup("?", p); | 
 | 	} | 
 |  | 
 | name: | 
 | 	sym	%prec NotParen | 
 | 	{ | 
 | 		$$ = oldname($1); | 
 | 		if $$.Pack != nil { | 
 | 			$$.Pack.Used = true; | 
 | 		} | 
 | 	} | 
 |  | 
 | 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)), nil); | 
 | 	} | 
 | |	LDDD ntype | 
 | 	{ | 
 | 		$$ = Nod(ODDD, $2, nil); | 
 | 	} | 
 |  | 
 | ntype: | 
 | 	recvchantype | 
 | |	fntype | 
 | |	othertype | 
 | |	ptrtype | 
 | |	dotname | 
 | |	'(' ntype ')' | 
 | 	{ | 
 | 		$$ = $2; | 
 | 	} | 
 |  | 
 | non_expr_type: | 
 | 	recvchantype | 
 | |	fntype | 
 | |	othertype | 
 | |	'*' non_expr_type | 
 | 	{ | 
 | 		$$ = Nod(OIND, $2, nil); | 
 | 	} | 
 |  | 
 | non_recvchantype: | 
 | 	fntype | 
 | |	othertype | 
 | |	ptrtype | 
 | |	dotname | 
 | |	'(' ntype ')' | 
 | 	{ | 
 | 		$$ = $2; | 
 | 	} | 
 |  | 
 | convtype: | 
 | 	fntype | 
 | |	othertype | 
 |  | 
 | comptype: | 
 | 	othertype | 
 |  | 
 | fnret_type: | 
 | 	recvchantype | 
 | |	fntype | 
 | |	othertype | 
 | |	ptrtype | 
 | |	dotname | 
 |  | 
 | dotname: | 
 | 	name | 
 | |	name '.' sym | 
 | 	{ | 
 | 		if $1.Op == OPACK { | 
 | 			var s *Sym | 
 | 			s = restrictlookup($3.Name, $1.Pkg); | 
 | 			$1.Used = true; | 
 | 			$$ = 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, nil, nil), $4); | 
 | 	} | 
 | |	LCHAN non_recvchantype | 
 | 	{ | 
 | 		$$ = Nod(OTCHAN, $2, nil); | 
 | 		$$.Etype = Cboth; | 
 | 	} | 
 | |	LCHAN LCOMM ntype | 
 | 	{ | 
 | 		$$ = Nod(OTCHAN, $3, nil); | 
 | 		$$.Etype = Csend; | 
 | 	} | 
 | |	LMAP '[' ntype ']' ntype | 
 | 	{ | 
 | 		$$ = Nod(OTMAP, $3, $5); | 
 | 	} | 
 | |	structtype | 
 | |	interfacetype | 
 |  | 
 | ptrtype: | 
 | 	'*' ntype | 
 | 	{ | 
 | 		$$ = Nod(OIND, $2, nil); | 
 | 	} | 
 |  | 
 | recvchantype: | 
 | 	LCOMM LCHAN ntype | 
 | 	{ | 
 | 		$$ = Nod(OTCHAN, $3, nil); | 
 | 		$$.Etype = Crecv; | 
 | 	} | 
 |  | 
 | structtype: | 
 | 	LSTRUCT lbrace structdcl_list osemi '}' | 
 | 	{ | 
 | 		$$ = Nod(OTSTRUCT, nil, nil); | 
 | 		$$.List = $3; | 
 | 		fixlbrace($2); | 
 | 	} | 
 | |	LSTRUCT lbrace '}' | 
 | 	{ | 
 | 		$$ = Nod(OTSTRUCT, nil, nil); | 
 | 		fixlbrace($2); | 
 | 	} | 
 |  | 
 | interfacetype: | 
 | 	LINTERFACE lbrace interfacedcl_list osemi '}' | 
 | 	{ | 
 | 		$$ = Nod(OTINTER, nil, nil); | 
 | 		$$.List = $3; | 
 | 		fixlbrace($2); | 
 | 	} | 
 | |	LINTERFACE lbrace '}' | 
 | 	{ | 
 | 		$$ = Nod(OTINTER, nil, nil); | 
 | 		fixlbrace($2); | 
 | 	} | 
 |  | 
 | /* | 
 |  * function stuff | 
 |  * all in one place to show how crappy it all is | 
 |  */ | 
 | xfndcl: | 
 | 	LFUNC fndcl fnbody | 
 | 	{ | 
 | 		$$ = $2; | 
 | 		if $$ == nil { | 
 | 			break; | 
 | 		} | 
 | 		if noescape && $3 != nil { | 
 | 			Yyerror("can only use //go:noescape with external func implementations"); | 
 | 		} | 
 | 		$$.Nbody = $3; | 
 | 		$$.Func.Endlineno = lineno; | 
 | 		$$.Noescape = noescape; | 
 | 		$$.Func.Nosplit = nosplit; | 
 | 		$$.Func.Nowritebarrier = nowritebarrier; | 
 | 		funcbody($$); | 
 | 	} | 
 |  | 
 | fndcl: | 
 | 	sym '(' oarg_type_list_ocomma ')' fnres | 
 | 	{ | 
 | 		var t *Node | 
 |  | 
 | 		$$ = nil; | 
 | 		$3 = checkarglist($3, 1); | 
 |  | 
 | 		if $1.Name == "init" { | 
 | 			$1 = renameinit(); | 
 | 			if $3 != nil || $5 != nil { | 
 | 				Yyerror("func init must have no arguments and no return values"); | 
 | 			} | 
 | 		} | 
 | 		if localpkg.Name == "main" && $1.Name == "main" { | 
 | 			if $3 != nil || $5 != nil { | 
 | 				Yyerror("func main must have no arguments and no return values"); | 
 | 			} | 
 | 		} | 
 |  | 
 | 		t = Nod(OTFUNC, nil, nil); | 
 | 		t.List = $3; | 
 | 		t.Rlist = $5; | 
 |  | 
 | 		$$ = Nod(ODCLFUNC, nil, nil); | 
 | 		$$.Nname = newfuncname($1); | 
 | 		$$.Nname.Defn = $$; | 
 | 		$$.Nname.Ntype = t;		// TODO: check if nname already has an ntype | 
 | 		declare($$.Nname, PFUNC); | 
 |  | 
 | 		funchdr($$); | 
 | 	} | 
 | |	'(' oarg_type_list_ocomma ')' sym '(' oarg_type_list_ocomma ')' fnres | 
 | 	{ | 
 | 		var rcvr, t *Node | 
 |  | 
 | 		$$ = nil; | 
 | 		$2 = checkarglist($2, 0); | 
 | 		$6 = checkarglist($6, 1); | 
 |  | 
 | 		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; | 
 | 		} | 
 |  | 
 | 		t = Nod(OTFUNC, rcvr, nil); | 
 | 		t.List = $6; | 
 | 		t.Rlist = $8; | 
 |  | 
 | 		$$ = Nod(ODCLFUNC, nil, nil); | 
 | 		$$.Func.Shortname = newfuncname($4); | 
 | 		$$.Nname = methodname1($$.Func.Shortname, rcvr.Right); | 
 | 		$$.Nname.Defn = $$; | 
 | 		$$.Nname.Ntype = t; | 
 | 		$$.Nname.Nointerface = nointerface; | 
 | 		declare($$.Nname, PFUNC); | 
 |  | 
 | 		funchdr($$); | 
 | 	} | 
 |  | 
 | hidden_fndcl: | 
 | 	hidden_pkg_importsym '(' ohidden_funarg_list ')' ohidden_funres | 
 | 	{ | 
 | 		var s *Sym | 
 | 		var t *Type | 
 |  | 
 | 		$$ = nil; | 
 |  | 
 | 		s = $1; | 
 | 		t = functype(nil, $3, $5); | 
 |  | 
 | 		importsym(s, ONAME); | 
 | 		if s.Def != nil && s.Def.Op == ONAME { | 
 | 			if Eqtype(t, s.Def.Type) { | 
 | 				dclcontext = PDISCARD;  // since we skip funchdr below | 
 | 				break; | 
 | 			} | 
 | 			Yyerror("inconsistent definition for func %v during import\n\t%v\n\t%v", Sconv(s, 0), Tconv(s.Def.Type, 0), Tconv(t, 0)); | 
 | 		} | 
 |  | 
 | 		$$ = newfuncname(s); | 
 | 		$$.Type = t; | 
 | 		declare($$, PFUNC); | 
 |  | 
 | 		funchdr($$); | 
 | 	} | 
 | |	'(' hidden_funarg_list ')' sym '(' ohidden_funarg_list ')' ohidden_funres | 
 | 	{ | 
 | 		$$ = methodname1(newname($4), $2.N.Right);  | 
 | 		$$.Type = functype($2.N, $6, $8); | 
 |  | 
 | 		checkwidth($$.Type); | 
 | 		addmethod($4, $$.Type, false, nointerface); | 
 | 		nointerface = false | 
 | 		funchdr($$); | 
 | 		 | 
 | 		// inl.C's inlnode in on a dotmeth node expects to find the inlineable body as | 
 | 		// (dotmeth's type).Nname.Inl, and dotmeth's type has been pulled | 
 | 		// out by typecheck's lookdot as this $$.ttype.  So by providing | 
 | 		// this back link here we avoid special casing there. | 
 | 		$$.Type.Nname = $$; | 
 | 	} | 
 |  | 
 | fntype: | 
 | 	LFUNC '(' oarg_type_list_ocomma ')' fnres | 
 | 	{ | 
 | 		$3 = checkarglist($3, 1); | 
 | 		$$ = Nod(OTFUNC, nil, nil); | 
 | 		$$.List = $3; | 
 | 		$$.Rlist = $5; | 
 | 	} | 
 |  | 
 | fnbody: | 
 | 	{ | 
 | 		$$ = nil; | 
 | 	} | 
 | |	'{' stmt_list '}' | 
 | 	{ | 
 | 		$$ = $2; | 
 | 		if $$ == nil { | 
 | 			$$ = list1(Nod(OEMPTY, nil, nil)); | 
 | 		} | 
 | 	} | 
 |  | 
 | fnres: | 
 | 	%prec NotParen | 
 | 	{ | 
 | 		$$ = nil; | 
 | 	} | 
 | |	fnret_type | 
 | 	{ | 
 | 		$$ = list1(Nod(ODCLFIELD, nil, $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(); | 
 | 		} | 
 | 		nointerface = false | 
 | 		noescape = false | 
 | 		nosplit = false | 
 | 		nowritebarrier = false | 
 | 	} | 
 |  | 
 | 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 | 
 | 	{ | 
 | 		var l *NodeList | 
 |  | 
 | 		var n *Node | 
 | 		l = $1; | 
 | 		if l == nil { | 
 | 			// ? symbol, during import (list1(nil) == nil) | 
 | 			n = $2; | 
 | 			if n.Op == OIND { | 
 | 				n = n.Left; | 
 | 			} | 
 | 			n = embedded(n.Sym, importpkg); | 
 | 			n.Right = $2; | 
 | 			n.Val = $3; | 
 | 			$$ = list1(n); | 
 | 			break; | 
 | 		} | 
 |  | 
 | 		for l=$1; l != nil; 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, nil); | 
 | 		$2.Val = $3; | 
 | 		$$ = list1($2); | 
 | 	} | 
 | |	'(' '*' embed ')' oliteral | 
 | 	{ | 
 | 		$3.Right = Nod(OIND, $3.Right, nil); | 
 | 		$3.Val = $5; | 
 | 		$$ = list1($3); | 
 | 		Yyerror("cannot parenthesize embedded type"); | 
 | 	} | 
 | |	'*' '(' embed ')' oliteral | 
 | 	{ | 
 | 		$3.Right = Nod(OIND, $3.Right, nil); | 
 | 		$3.Val = $5; | 
 | 		$$ = list1($3); | 
 | 		Yyerror("cannot parenthesize embedded type"); | 
 | 	} | 
 |  | 
 | packname: | 
 | 	LNAME | 
 | 	{ | 
 | 		var n *Node | 
 |  | 
 | 		$$ = $1; | 
 | 		n = oldname($1); | 
 | 		if n.Pack != nil { | 
 | 			n.Pack.Used = true; | 
 | 		} | 
 | 	} | 
 | |	LNAME '.' sym | 
 | 	{ | 
 | 		var pkg *Pkg | 
 |  | 
 | 		if $1.Def == nil || $1.Def.Op != OPACK { | 
 | 			Yyerror("%v is not a package", Sconv($1, 0)); | 
 | 			pkg = localpkg; | 
 | 		} else { | 
 | 			$1.Def.Used = true; | 
 | 			pkg = $1.Def.Pkg; | 
 | 		} | 
 | 		$$ = restrictlookup($3.Name, pkg); | 
 | 	} | 
 |  | 
 | embed: | 
 | 	packname | 
 | 	{ | 
 | 		$$ = embedded($1, localpkg); | 
 | 	} | 
 |  | 
 | interfacedcl: | 
 | 	new_name indcl | 
 | 	{ | 
 | 		$$ = Nod(ODCLFIELD, $1, $2); | 
 | 		ifacedcl($$); | 
 | 	} | 
 | |	packname | 
 | 	{ | 
 | 		$$ = Nod(ODCLFIELD, nil, oldname($1)); | 
 | 	} | 
 | |	'(' packname ')' | 
 | 	{ | 
 | 		$$ = Nod(ODCLFIELD, nil, oldname($2)); | 
 | 		Yyerror("cannot parenthesize embedded type"); | 
 | 	} | 
 |  | 
 | indcl: | 
 | 	'(' oarg_type_list_ocomma ')' fnres | 
 | 	{ | 
 | 		// without func keyword | 
 | 		$2 = checkarglist($2, 1); | 
 | 		$$ = Nod(OTFUNC, fakethis(), nil); | 
 | 		$$.List = $2; | 
 | 		$$.Rlist = $4; | 
 | 	} | 
 |  | 
 | /* | 
 |  * function arguments. | 
 |  */ | 
 | arg_type: | 
 | 	name_or_type | 
 | |	sym name_or_type | 
 | 	{ | 
 | 		$$ = Nod(ONONAME, nil, nil); | 
 | 		$$.Sym = $1; | 
 | 		$$ = Nod(OKEY, $$, $2); | 
 | 	} | 
 | |	sym dotdotdot | 
 | 	{ | 
 | 		$$ = Nod(ONONAME, nil, nil); | 
 | 		$$.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: | 
 | 	{ | 
 | 		$$ = nil; | 
 | 	} | 
 | |	compound_stmt | 
 | |	common_dcl | 
 | 	{ | 
 | 		$$ = liststmt($1); | 
 | 	} | 
 | |	non_dcl_stmt | 
 | |	error | 
 | 	{ | 
 | 		$$ = nil; | 
 | 	} | 
 |  | 
 | non_dcl_stmt: | 
 | 	simple_stmt | 
 | |	for_stmt | 
 | |	switch_stmt | 
 | |	select_stmt | 
 | |	if_stmt | 
 | |	labelname ':' | 
 | 	{ | 
 | 		$1 = Nod(OLABEL, $1, nil); | 
 | 		$1.Sym = dclstack;  // context, for goto restrictions | 
 | 	} | 
 | 	stmt | 
 | 	{ | 
 | 		var l *NodeList | 
 |  | 
 | 		$1.Defn = $4; | 
 | 		l = list1($1); | 
 | 		if $4 != nil { | 
 | 			l = list(l, $4); | 
 | 		} | 
 | 		$$ = liststmt(l); | 
 | 	} | 
 | |	LFALL | 
 | 	{ | 
 | 		// will be converted to OFALL | 
 | 		$$ = Nod(OXFALL, nil, nil); | 
 | 		$$.Xoffset = int64(block); | 
 | 	} | 
 | |	LBREAK onew_name | 
 | 	{ | 
 | 		$$ = Nod(OBREAK, $2, nil); | 
 | 	} | 
 | |	LCONTINUE onew_name | 
 | 	{ | 
 | 		$$ = Nod(OCONTINUE, $2, nil); | 
 | 	} | 
 | |	LGO pseudocall | 
 | 	{ | 
 | 		$$ = Nod(OPROC, $2, nil); | 
 | 	} | 
 | |	LDEFER pseudocall | 
 | 	{ | 
 | 		$$ = Nod(ODEFER, $2, nil); | 
 | 	} | 
 | |	LGOTO new_name | 
 | 	{ | 
 | 		$$ = Nod(OGOTO, $2, nil); | 
 | 		$$.Sym = dclstack;  // context, for goto restrictions | 
 | 	} | 
 | |	LRETURN oexpr_list | 
 | 	{ | 
 | 		$$ = Nod(ORETURN, nil, nil); | 
 | 		$$.List = $2; | 
 | 		if $$.List == nil && Curfn != nil { | 
 | 			var l *NodeList | 
 |  | 
 | 			for l=Curfn.Func.Dcl; l != nil; 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 != nil { | 
 | 			$$ = list1($1); | 
 | 		} | 
 | 	} | 
 | |	stmt_list ';' stmt | 
 | 	{ | 
 | 		$$ = $1; | 
 | 		if $3 != nil { | 
 | 			$$ = 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); | 
 | 	} | 
 | |	bare_complitexpr | 
 | 	{ | 
 | 		$$ = list1($1); | 
 | 	} | 
 | |	keyval_list ',' keyval | 
 | 	{ | 
 | 		$$ = list($1, $3); | 
 | 	} | 
 | |	keyval_list ',' bare_complitexpr | 
 | 	{ | 
 | 		$$ = list($1, $3); | 
 | 	} | 
 |  | 
 | braced_keyval_list: | 
 | 	{ | 
 | 		$$ = nil; | 
 | 	} | 
 | |	keyval_list ocomma | 
 | 	{ | 
 | 		$$ = $1; | 
 | 	} | 
 |  | 
 | /* | 
 |  * optional things | 
 |  */ | 
 | osemi: | 
 | |	';' | 
 |  | 
 | ocomma: | 
 | |	',' | 
 |  | 
 | oexpr: | 
 | 	{ | 
 | 		$$ = nil; | 
 | 	} | 
 | |	expr | 
 |  | 
 | oexpr_list: | 
 | 	{ | 
 | 		$$ = nil; | 
 | 	} | 
 | |	expr_list | 
 |  | 
 | osimple_stmt: | 
 | 	{ | 
 | 		$$ = nil; | 
 | 	} | 
 | |	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 package header | 
 |  */ | 
 | hidden_import: | 
 | 	LIMPORT LNAME LLITERAL ';' | 
 | 	{ | 
 | 		importimport($2, $3.U.Sval); | 
 | 	} | 
 | |	LVAR hidden_pkg_importsym hidden_type ';' | 
 | 	{ | 
 | 		importvar($2, $3); | 
 | 	} | 
 | |	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_fndcl fnbody ';' | 
 | 	{ | 
 | 		if $2 == nil { | 
 | 			dclcontext = PEXTERN;  // since we skip the funcbody below | 
 | 			break; | 
 | 		} | 
 |  | 
 | 		$2.Func.Inl = $3; | 
 |  | 
 | 		funcbody($2); | 
 | 		importlist = list(importlist, $2); | 
 |  | 
 | 		if Debug['E'] > 0 { | 
 | 			print("import [%q] func %lN \n", importpkg.Path, $2); | 
 | 			if Debug['m'] > 2 && $2.Func.Inl != nil { | 
 | 				print("inl body:%+H\n", $2.Func.Inl); | 
 | 			} | 
 | 		} | 
 | 	} | 
 |  | 
 | hidden_pkg_importsym: | 
 | 	hidden_importsym | 
 | 	{ | 
 | 		$$ = $1; | 
 | 		structpkg = $$.Pkg; | 
 | 	} | 
 |  | 
 | hidden_pkgtype: | 
 | 	hidden_pkg_importsym | 
 | 	{ | 
 | 		$$ = pkgtype($1); | 
 | 		importsym($1, OTYPE); | 
 | 	} | 
 |  | 
 | /* | 
 |  *  importing types | 
 |  */ | 
 |  | 
 | 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 == nil || $1.Def.Op != OTYPE { | 
 | 			Yyerror("%s is not a type", $1.Name); | 
 | 			$$ = nil; | 
 | 		} else { | 
 | 			$$ = $1.Def.Type; | 
 | 		} | 
 | 	} | 
 | |	'[' ']' hidden_type | 
 | 	{ | 
 | 		$$ = aindex(nil, $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_funarg: | 
 | 	sym hidden_type oliteral | 
 | 	{ | 
 | 		$$ = Nod(ODCLFIELD, nil, typenod($2)); | 
 | 		if $1 != nil { | 
 | 			$$.Left = newname($1); | 
 | 		} | 
 | 		$$.Val = $3; | 
 | 	} | 
 | |	sym LDDD hidden_type oliteral | 
 | 	{ | 
 | 		var t *Type | 
 | 	 | 
 | 		t = typ(TARRAY); | 
 | 		t.Bound = -1; | 
 | 		t.Type = $3; | 
 |  | 
 | 		$$ = Nod(ODCLFIELD, nil, typenod(t)); | 
 | 		if $1 != nil { | 
 | 			$$.Left = newname($1); | 
 | 		} | 
 | 		$$.Isddd = true; | 
 | 		$$.Val = $4; | 
 | 	} | 
 |  | 
 | hidden_structdcl: | 
 | 	sym hidden_type oliteral | 
 | 	{ | 
 | 		var s *Sym | 
 | 		var p *Pkg | 
 |  | 
 | 		if $1 != nil && $1.Name != "?" { | 
 | 			$$ = Nod(ODCLFIELD, newname($1), typenod($2)); | 
 | 			$$.Val = $3; | 
 | 		} else { | 
 | 			s = $2.Sym; | 
 | 			if s == nil && Isptr[$2.Etype] { | 
 | 				s = $2.Type.Sym; | 
 | 			} | 
 | 			p = importpkg; | 
 | 			if $1 != nil { | 
 | 				p = $1.Pkg; | 
 | 			} | 
 | 			$$ = embedded(s, p); | 
 | 			$$.Right = typenod($2); | 
 | 			$$.Val = $3; | 
 | 		} | 
 | 	} | 
 |  | 
 | hidden_interfacedcl: | 
 | 	sym '(' ohidden_funarg_list ')' ohidden_funres | 
 | 	{ | 
 | 		$$ = Nod(ODCLFIELD, newname($1), typenod(functype(fakethis(), $3, $5))); | 
 | 	} | 
 | |	hidden_type | 
 | 	{ | 
 | 		$$ = Nod(ODCLFIELD, nil, typenod($1)); | 
 | 	} | 
 |  | 
 | ohidden_funres: | 
 | 	{ | 
 | 		$$ = nil; | 
 | 	} | 
 | |	hidden_funres | 
 |  | 
 | hidden_funres: | 
 | 	'(' ohidden_funarg_list ')' | 
 | 	{ | 
 | 		$$ = $2; | 
 | 	} | 
 | |	hidden_type | 
 | 	{ | 
 | 		$$ = list1(Nod(ODCLFIELD, nil, typenod($1))); | 
 | 	} | 
 |  | 
 | /* | 
 |  *  importing constants | 
 |  */ | 
 |  | 
 | hidden_literal: | 
 | 	LLITERAL | 
 | 	{ | 
 | 		$$ = nodlit($1); | 
 | 	} | 
 | |	'-' LLITERAL | 
 | 	{ | 
 | 		$$ = nodlit($2); | 
 | 		switch($$.Val.Ctype){ | 
 | 		case CTINT, CTRUNE: | 
 | 			mpnegfix($$.Val.U.Xval); | 
 | 			break; | 
 | 		case CTFLT: | 
 | 			mpnegflt($$.Val.U.Fval); | 
 | 			break; | 
 | 		case CTCPLX: | 
 | 			mpnegflt(&$$.Val.U.Cval.Real); | 
 | 			mpnegflt(&$$.Val.U.Cval.Imag); | 
 | 			break; | 
 | 		default: | 
 | 			Yyerror("bad negated constant"); | 
 | 		} | 
 | 	} | 
 | |	sym | 
 | 	{ | 
 | 		$$ = oldname(Pkglookup($1.Name, builtinpkg)); | 
 | 		if $$.Op != OLITERAL { | 
 | 			Yyerror("bad constant %v", Sconv($$.Sym, 0)); | 
 | 		} | 
 | 	} | 
 |  | 
 | hidden_constant: | 
 | 	hidden_literal | 
 | |	'(' hidden_literal '+' hidden_literal ')' | 
 | 	{ | 
 | 		if $2.Val.Ctype == CTRUNE && $4.Val.Ctype == CTINT { | 
 | 			$$ = $2; | 
 | 			mpaddfixfix($2.Val.U.Xval, $4.Val.U.Xval, 0); | 
 | 			break; | 
 | 		} | 
 | 		$4.Val.U.Cval.Real = $4.Val.U.Cval.Imag; | 
 | 		Mpmovecflt(&$4.Val.U.Cval.Imag, 0.0); | 
 | 		$$ = nodcplxlit($2.Val, $4.Val); | 
 | 	} | 
 |  | 
 | hidden_import_list: | 
 | |	hidden_import_list hidden_import | 
 |  | 
 | hidden_funarg_list: | 
 | 	hidden_funarg | 
 | 	{ | 
 | 		$$ = list1($1); | 
 | 	} | 
 | |	hidden_funarg_list ',' hidden_funarg | 
 | 	{ | 
 | 		$$ = 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); | 
 | 	} | 
 |  | 
 | %% | 
 | func fixlbrace(lbr int) { | 
 | 	// 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 | 
 | 	} | 
 | } |