github.com/rsc/go@v0.0.0-20150416155037-e040fd465409/src/cmd/old5a/a.y (about)

     1  // Inferno utils/5a/a.y
     2  // http://code.google.com/p/inferno-os/source/browse/utils/5a/a.y
     3  //
     4  //	Copyright © 1994-1999 Lucent Technologies Inc.	All rights reserved.
     5  //	Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
     6  //	Portions Copyright © 1997-1999 Vita Nuova Limited
     7  //	Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
     8  //	Portions Copyright © 2004,2006 Bruce Ellis
     9  //	Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
    10  //	Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
    11  //	Portions Copyright © 2009 The Go Authors.  All rights reserved.
    12  //
    13  // Permission is hereby granted, free of charge, to any person obtaining a copy
    14  // of this software and associated documentation files (the "Software"), to deal
    15  // in the Software without restriction, including without limitation the rights
    16  // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
    17  // copies of the Software, and to permit persons to whom the Software is
    18  // furnished to do so, subject to the following conditions:
    19  //
    20  // The above copyright notice and this permission notice shall be included in
    21  // all copies or substantial portions of the Software.
    22  //
    23  // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
    24  // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
    25  // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
    26  // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
    27  // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
    28  // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
    29  // THE SOFTWARE.
    30  
    31  %{
    32  package main
    33  
    34  import (
    35  	"cmd/internal/asm"
    36  	"cmd/internal/obj"
    37  	. "cmd/internal/obj/arm"
    38  )
    39  %}
    40  
    41  %union {
    42  	sym *asm.Sym
    43  	lval int32
    44  	dval float64
    45  	sval string
    46  	addr obj.Addr
    47  }
    48  
    49  %left	'|'
    50  %left	'^'
    51  %left	'&'
    52  %left	'<' '>'
    53  %left	'+' '-'
    54  %left	'*' '/' '%'
    55  %token	<lval>	LTYPE1 LTYPE2 LTYPE3 LTYPE4 LTYPE5
    56  %token	<lval>	LTYPE6 LTYPE7 LTYPE8 LTYPE9 LTYPEA
    57  %token	<lval>	LTYPEB LTYPEC LTYPED LTYPEE
    58  %token	<lval>	LTYPEG LTYPEH LTYPEI LTYPEJ LTYPEK
    59  %token	<lval>	LTYPEL LTYPEM LTYPEN LTYPEBX LTYPEPLD
    60  %token	<lval>	LCONST LSP LSB LFP LPC
    61  %token	<lval>	LTYPEX LTYPEPC LTYPEF LR LREG LF LFREG LC LCREG LPSR LFCR
    62  %token	<lval>	LCOND LS LAT LGLOBL
    63  %token	<dval>	LFCONST
    64  %token	<sval>	LSCONST
    65  %token	<sym>	LNAME LLAB LVAR
    66  %type	<lval>	con expr oexpr pointer offset sreg spreg creg
    67  %type	<lval>	rcon cond reglist
    68  %type	<addr>	gen rel reg regreg freg shift fcon frcon textsize
    69  %type	<addr>	imm ximm name oreg ireg nireg ioreg imsr
    70  %%
    71  prog:
    72  |	prog
    73  	{
    74  		stmtline = asm.Lineno;
    75  	}
    76  	line
    77  
    78  line:
    79  	LNAME ':'
    80  	{
    81  		$1 = asm.LabelLookup($1);
    82  		if $1.Type == LLAB && $1.Value != int64(asm.PC) {
    83  			yyerror("redeclaration of %s", $1.Labelname)
    84  		}
    85  		$1.Type = LLAB;
    86  		$1.Value = int64(asm.PC)
    87  	}
    88  	line
    89  |	LNAME '=' expr ';'
    90  	{
    91  		$1.Type = LVAR;
    92  		$1.Value = int64($3);
    93  	}
    94  |	LVAR '=' expr ';'
    95  	{
    96  		if $1.Value != int64($3) {
    97  			yyerror("redeclaration of %s", $1.Name)
    98  		}
    99  		$1.Value = int64($3);
   100  	}
   101  |	';'
   102  |	inst ';'
   103  |	error ';'
   104  
   105  inst:
   106  /*
   107   * ADD
   108   */
   109  	LTYPE1 cond imsr ',' spreg ',' reg
   110  	{
   111  		outcode($1, $2, &$3, $5, &$7);
   112  	}
   113  |	LTYPE1 cond imsr ',' spreg ','
   114  	{
   115  		outcode($1, $2, &$3, $5, &nullgen);
   116  	}
   117  |	LTYPE1 cond imsr ',' reg
   118  	{
   119  		outcode($1, $2, &$3, 0, &$5);
   120  	}
   121  /*
   122   * MVN
   123   */
   124  |	LTYPE2 cond imsr ',' reg
   125  	{
   126  		outcode($1, $2, &$3, 0, &$5);
   127  	}
   128  /*
   129   * MOVW
   130   */
   131  |	LTYPE3 cond gen ',' gen
   132  	{
   133  		outcode($1, $2, &$3, 0, &$5);
   134  	}
   135  /*
   136   * B/BL
   137   */
   138  |	LTYPE4 cond comma rel
   139  	{
   140  		outcode($1, $2, &nullgen, 0, &$4);
   141  	}
   142  |	LTYPE4 cond comma nireg
   143  	{
   144  		outcode($1, $2, &nullgen, 0, &$4);
   145  	}
   146  /*
   147   * BX
   148   */
   149  |	LTYPEBX comma ireg
   150  	{
   151  		outcode($1, Always, &nullgen, 0, &$3);
   152  	}
   153  /*
   154   * BEQ
   155   */
   156  |	LTYPE5 comma rel
   157  	{
   158  		outcode($1, Always, &nullgen, 0, &$3);
   159  	}
   160  /*
   161   * SWI
   162   */
   163  |	LTYPE6 cond comma gen
   164  	{
   165  		outcode($1, $2, &nullgen, 0, &$4);
   166  	}
   167  /*
   168   * CMP
   169   */
   170  |	LTYPE7 cond imsr ',' spreg comma
   171  	{
   172  		outcode($1, $2, &$3, $5, &nullgen);
   173  	}
   174  /*
   175   * MOVM
   176   */
   177  |	LTYPE8 cond ioreg ',' '[' reglist ']'
   178  	{
   179  		var g obj.Addr
   180  
   181  		g = nullgen;
   182  		g.Type = obj.TYPE_REGLIST;
   183  		g.Offset = int64($6);
   184  		outcode($1, $2, &$3, 0, &g);
   185  	}
   186  |	LTYPE8 cond '[' reglist ']' ',' ioreg
   187  	{
   188  		var g obj.Addr
   189  
   190  		g = nullgen;
   191  		g.Type = obj.TYPE_REGLIST;
   192  		g.Offset = int64($4);
   193  		outcode($1, $2, &g, 0, &$7);
   194  	}
   195  /*
   196   * SWAP
   197   */
   198  |	LTYPE9 cond reg ',' ireg ',' reg
   199  	{
   200  		outcode($1, $2, &$5, int32($3.Reg), &$7);
   201  	}
   202  |	LTYPE9 cond reg ',' ireg comma
   203  	{
   204  		outcode($1, $2, &$5, int32($3.Reg), &$3);
   205  	}
   206  |	LTYPE9 cond comma ireg ',' reg
   207  	{
   208  		outcode($1, $2, &$4, int32($6.Reg), &$6);
   209  	}
   210  /*
   211   * RET
   212   */
   213  |	LTYPEA cond comma
   214  	{
   215  		outcode($1, $2, &nullgen, 0, &nullgen);
   216  	}
   217  /*
   218   * TEXT
   219   */
   220  |	LTYPEB name ',' '$' textsize
   221  	{
   222  		asm.Settext($2.Sym);
   223  		outcode($1, Always, &$2, 0, &$5);
   224  	}
   225  |	LTYPEB name ',' con ',' '$' textsize
   226  	{
   227  		asm.Settext($2.Sym);
   228  		outcode($1, Always, &$2, 0, &$7);
   229  		if asm.Pass > 1 {
   230  			lastpc.From3.Type = obj.TYPE_CONST;
   231  			lastpc.From3.Offset = int64($4)
   232  		}
   233  	}
   234  /*
   235   * GLOBL
   236   */
   237  |	LGLOBL name ',' imm
   238  	{
   239  		asm.Settext($2.Sym)
   240  		outcode($1, Always, &$2, 0, &$4)
   241  	}
   242  |	LGLOBL name ',' con ',' imm
   243  	{
   244  		asm.Settext($2.Sym)
   245  		outcode($1, Always, &$2, 0, &$6)
   246  		if asm.Pass > 1 {
   247  			lastpc.From3.Type = obj.TYPE_CONST
   248  			lastpc.From3.Offset = int64($4)
   249  		}
   250  	}
   251  
   252  /*
   253   * DATA
   254   */
   255  |	LTYPEC name '/' con ',' ximm
   256  	{
   257  		outcode($1, Always, &$2, 0, &$6)
   258  		if asm.Pass > 1 {
   259  			lastpc.From3.Type = obj.TYPE_CONST
   260  			lastpc.From3.Offset = int64($4)
   261  		}
   262  	}
   263  /*
   264   * CASE
   265   */
   266  |	LTYPED cond reg comma
   267  	{
   268  		outcode($1, $2, &$3, 0, &nullgen);
   269  	}
   270  /*
   271   * word
   272   */
   273  |	LTYPEH comma ximm
   274  	{
   275  		outcode($1, Always, &nullgen, 0, &$3);
   276  	}
   277  /*
   278   * floating-point coprocessor
   279   */
   280  |	LTYPEI cond freg ',' freg
   281  	{
   282  		outcode($1, $2, &$3, 0, &$5);
   283  	}
   284  |	LTYPEK cond frcon ',' freg
   285  	{
   286  		outcode($1, $2, &$3, 0, &$5);
   287  	}
   288  |	LTYPEK cond frcon ',' LFREG ',' freg
   289  	{
   290  		outcode($1, $2, &$3, $5, &$7);
   291  	}
   292  |	LTYPEL cond freg ',' freg comma
   293  	{
   294  		outcode($1, $2, &$3, int32($5.Reg), &nullgen);
   295  	}
   296  /*
   297   * MCR MRC
   298   */
   299  |	LTYPEJ cond con ',' expr ',' spreg ',' creg ',' creg oexpr
   300  	{
   301  		var g obj.Addr
   302  
   303  		g = nullgen;
   304  		g.Type = obj.TYPE_CONST;
   305  		g.Offset = int64(
   306  			(0xe << 24) |		/* opcode */
   307  			($1 << 20) |		/* MCR/MRC */
   308  			(($2^C_SCOND_XOR) << 28) |		/* scond */
   309  			(($3 & 15) << 8) |	/* coprocessor number */
   310  			(($5 & 7) << 21) |	/* coprocessor operation */
   311  			(($7 & 15) << 12) |	/* arm register */
   312  			(($9 & 15) << 16) |	/* Crn */
   313  			(($11 & 15) << 0) |	/* Crm */
   314  			(($12 & 7) << 5) |	/* coprocessor information */
   315  			(1<<4));			/* must be set */
   316  		outcode(AMRC, Always, &nullgen, 0, &g);
   317  	}
   318  /*
   319   * MULL r1,r2,(hi,lo)
   320   */
   321  |	LTYPEM cond reg ',' reg ',' regreg
   322  	{
   323  		outcode($1, $2, &$3, int32($5.Reg), &$7);
   324  	}
   325  /*
   326   * MULA r1,r2,r3,r4: (r1*r2+r3) & 0xffffffff . r4
   327   * MULAW{T,B} r1,r2,r3,r4
   328   */
   329  |	LTYPEN cond reg ',' reg ',' reg ',' spreg
   330  	{
   331  		$7.Type = obj.TYPE_REGREG2;
   332  		$7.Offset = int64($9);
   333  		outcode($1, $2, &$3, int32($5.Reg), &$7);
   334  	}
   335  /*
   336   * PLD
   337   */
   338  |	LTYPEPLD oreg
   339  	{
   340  		outcode($1, Always, &$2, 0, &nullgen);
   341  	}
   342  /*
   343   * PCDATA
   344   */
   345  |	LTYPEPC gen ',' gen
   346  	{
   347  		if $2.Type != obj.TYPE_CONST || $4.Type != obj.TYPE_CONST {
   348  			yyerror("arguments to PCDATA must be integer constants")
   349  		}
   350  		outcode($1, Always, &$2, 0, &$4);
   351  	}
   352  /*
   353   * FUNCDATA
   354   */
   355  |	LTYPEF gen ',' gen
   356  	{
   357  		if $2.Type != obj.TYPE_CONST {
   358  			yyerror("index for FUNCDATA must be integer constant")
   359  		}
   360  		if $4.Type != obj.NAME_EXTERN && $4.Type != obj.NAME_STATIC && $4.Type != obj.TYPE_MEM {
   361  			yyerror("value for FUNCDATA must be symbol reference")
   362  		}
   363   		outcode($1, Always, &$2, 0, &$4);
   364  	}
   365  /*
   366   * END
   367   */
   368  |	LTYPEE comma
   369  	{
   370  		outcode($1, Always, &nullgen, 0, &nullgen);
   371  	}
   372  
   373  textsize:
   374  	LCONST
   375  	{
   376  		$$ = nullgen;
   377  		$$.Type = obj.TYPE_TEXTSIZE;
   378  		$$.Offset = int64($1)
   379  		$$.Val = int32(obj.ArgsSizeUnknown)
   380  	}
   381  |	'-' LCONST
   382  	{
   383  		$$ = nullgen;
   384  		$$.Type = obj.TYPE_TEXTSIZE;
   385  		$$.Offset = -int64($2)
   386  		$$.Val = int32(obj.ArgsSizeUnknown)
   387  	}
   388  |	LCONST '-' LCONST
   389  	{
   390  		$$ = nullgen;
   391  		$$.Type = obj.TYPE_TEXTSIZE;
   392  		$$.Offset = int64($1)
   393  		$$.Val = int32($3);
   394  	}
   395  |	'-' LCONST '-' LCONST
   396  	{
   397  		$$ = nullgen;
   398  		$$.Type = obj.TYPE_TEXTSIZE;
   399  		$$.Offset = -int64($2)
   400  		$$.Val = int32($4);
   401  	}
   402  
   403  cond:
   404  	{
   405  		$$ = Always;
   406  	}
   407  |	cond LCOND
   408  	{
   409  		$$ = ($1 & ^ C_SCOND) | $2;
   410  	}
   411  |	cond LS
   412  	{
   413  		$$ = $1 | $2;
   414  	}
   415  
   416  comma:
   417  |	',' comma
   418  
   419  rel:
   420  	con '(' LPC ')'
   421  	{
   422  		$$ = nullgen;
   423  		$$.Type = obj.TYPE_BRANCH;
   424  		$$.Offset = int64($1) + int64(asm.PC);
   425  	}
   426  |	LNAME offset
   427  	{
   428  		$1 = asm.LabelLookup($1);
   429  		$$ = nullgen;
   430  		if asm.Pass == 2 && $1.Type != LLAB {
   431  			yyerror("undefined label: %s", $1.Labelname)
   432  		}
   433  		$$.Type = obj.TYPE_BRANCH;
   434  		$$.Offset = $1.Value + int64($2);
   435  	}
   436  
   437  ximm:	'$' con
   438  	{
   439  		$$ = nullgen;
   440  		$$.Type = obj.TYPE_CONST;
   441  		$$.Offset = int64($2);
   442  	}
   443  |	'$' oreg
   444  	{
   445  		$$ = $2;
   446  		$$.Type = obj.TYPE_ADDR;
   447  	}
   448  |	'$' LSCONST
   449  	{
   450  		$$ = nullgen;
   451  		$$.Type = obj.TYPE_SCONST;
   452  		$$.Val = $2
   453  	}
   454  |	fcon
   455  
   456  fcon:
   457  	'$' LFCONST
   458  	{
   459  		$$ = nullgen;
   460  		$$.Type = obj.TYPE_FCONST;
   461  		$$.Val = $2;
   462  	}
   463  |	'$' '-' LFCONST
   464  	{
   465  		$$ = nullgen;
   466  		$$.Type = obj.TYPE_FCONST;
   467  		$$.Val = -$3;
   468  	}
   469  
   470  reglist:
   471  	spreg
   472  	{
   473  		$$ = 1 << uint($1&15);
   474  	}
   475  |	spreg '-' spreg
   476  	{
   477  		$$=0;
   478  		for i:=$1; i<=$3; i++ {
   479  			$$ |= 1<<uint(i&15)
   480  		}
   481  		for i:=$3; i<=$1; i++ {
   482  			$$ |= 1<<uint(i&15)
   483  		}
   484  	}
   485  |	spreg comma reglist
   486  	{
   487  		$$ = (1<<uint($1&15)) | $3;
   488  	}
   489  
   490  gen:
   491  	reg
   492  |	ximm
   493  |	shift
   494  |	shift '(' spreg ')'
   495  	{
   496  		$$ = $1;
   497  		$$.Reg = int16($3);
   498  	}
   499  |	LPSR
   500  	{
   501  		$$ = nullgen;
   502  		$$.Type = obj.TYPE_REG
   503  		$$.Reg = int16($1);
   504  	}
   505  |	LFCR
   506  	{
   507  		$$ = nullgen;
   508  		$$.Type = obj.TYPE_REG
   509  		$$.Reg = int16($1);
   510  	}
   511  |	con
   512  	{
   513  		$$ = nullgen;
   514  		$$.Type = obj.TYPE_MEM;
   515  		$$.Offset = int64($1);
   516  	}
   517  |	oreg
   518  |	freg
   519  
   520  nireg:
   521  	ireg
   522  |	name
   523  	{
   524  		$$ = $1;
   525  		if($1.Name != obj.NAME_EXTERN && $1.Name != obj.NAME_STATIC) {
   526  		}
   527  	}
   528  
   529  ireg:
   530  	'(' spreg ')'
   531  	{
   532  		$$ = nullgen;
   533  		$$.Type = obj.TYPE_MEM;
   534  		$$.Reg = int16($2);
   535  		$$.Offset = 0;
   536  	}
   537  
   538  ioreg:
   539  	ireg
   540  |	con '(' sreg ')'
   541  	{
   542  		$$ = nullgen;
   543  		$$.Type = obj.TYPE_MEM;
   544  		$$.Reg = int16($3);
   545  		$$.Offset = int64($1);
   546  	}
   547  
   548  oreg:
   549  	name
   550  |	name '(' sreg ')'
   551  	{
   552  		$$ = $1;
   553  		$$.Type = obj.TYPE_MEM;
   554  		$$.Reg = int16($3);
   555  	}
   556  |	ioreg
   557  
   558  imsr:
   559  	reg
   560  |	imm
   561  |	shift
   562  
   563  imm:	'$' con
   564  	{
   565  		$$ = nullgen;
   566  		$$.Type = obj.TYPE_CONST;
   567  		$$.Offset = int64($2);
   568  	}
   569  
   570  reg:
   571  	spreg
   572  	{
   573  		$$ = nullgen;
   574  		$$.Type = obj.TYPE_REG;
   575  		$$.Reg = int16($1);
   576  	}
   577  
   578  regreg:
   579  	'(' spreg ',' spreg ')'
   580  	{
   581  		$$ = nullgen;
   582  		$$.Type = obj.TYPE_REGREG;
   583  		$$.Reg = int16($2);
   584  		$$.Offset = int64($4);
   585  	}
   586  
   587  shift:
   588  	spreg '<' '<' rcon
   589  	{
   590  		$$ = nullgen;
   591  		$$.Type = obj.TYPE_SHIFT;
   592  		$$.Offset = int64($1&15) | int64($4) | (0 << 5);
   593  	}
   594  |	spreg '>' '>' rcon
   595  	{
   596  		$$ = nullgen;
   597  		$$.Type = obj.TYPE_SHIFT;
   598  		$$.Offset = int64($1&15) | int64($4) | (1 << 5);
   599  	}
   600  |	spreg '-' '>' rcon
   601  	{
   602  		$$ = nullgen;
   603  		$$.Type = obj.TYPE_SHIFT;
   604  		$$.Offset = int64($1&15) | int64($4) | (2 << 5);
   605  	}
   606  |	spreg LAT '>' rcon
   607  	{
   608  		$$ = nullgen;
   609  		$$.Type = obj.TYPE_SHIFT;
   610  		$$.Offset = int64($1&15) | int64($4) | (3 << 5);
   611  	}
   612  
   613  rcon:
   614  	spreg
   615  	{
   616  		if $$ < REG_R0 || $$ > REG_R15 {
   617  			print("register value out of range\n")
   618  		}
   619  		$$ = (($1&15) << 8) | (1 << 4);
   620  	}
   621  |	con
   622  	{
   623  		if $$ < 0 || $$ >= 32 {
   624  			print("shift value out of range\n")
   625  		}
   626  		$$ = ($1&31) << 7;
   627  	}
   628  
   629  sreg:
   630  	LREG
   631  |	LPC
   632  	{
   633  		$$ = REGPC;
   634  	}
   635  |	LR '(' expr ')'
   636  	{
   637  		if $3 < 0 || $3 >= NREG {
   638  			print("register value out of range\n")
   639  		}
   640  		$$ = REG_R0 + $3;
   641  	}
   642  
   643  spreg:
   644  	sreg
   645  |	LSP
   646  	{
   647  		$$ = REGSP;
   648  	}
   649  
   650  creg:
   651  	LCREG
   652  |	LC '(' expr ')'
   653  	{
   654  		if $3 < 0 || $3 >= NREG {
   655  			print("register value out of range\n")
   656  		}
   657  		$$ = $3; // TODO(rsc): REG_C0+$3
   658  	}
   659  
   660  frcon:
   661  	freg
   662  |	fcon
   663  
   664  freg:
   665  	LFREG
   666  	{
   667  		$$ = nullgen;
   668  		$$.Type = obj.TYPE_REG;
   669  		$$.Reg = int16($1);
   670  	}
   671  |	LF '(' con ')'
   672  	{
   673  		$$ = nullgen;
   674  		$$.Type = obj.TYPE_REG;
   675  		$$.Reg = int16(REG_F0 + $3);
   676  	}
   677  
   678  name:
   679  	con '(' pointer ')'
   680  	{
   681  		$$ = nullgen;
   682  		$$.Type = obj.TYPE_MEM;
   683  		$$.Name = int8($3);
   684  		$$.Sym = nil;
   685  		$$.Offset = int64($1);
   686  	}
   687  |	LNAME offset '(' pointer ')'
   688  	{
   689  		$$ = nullgen;
   690  		$$.Type = obj.TYPE_MEM;
   691  		$$.Name = int8($4);
   692  		$$.Sym = obj.Linklookup(asm.Ctxt, $1.Name, 0);
   693  		$$.Offset = int64($2);
   694  	}
   695  |	LNAME '<' '>' offset '(' LSB ')'
   696  	{
   697  		$$ = nullgen;
   698  		$$.Type = obj.TYPE_MEM;
   699  		$$.Name = obj.NAME_STATIC;
   700  		$$.Sym = obj.Linklookup(asm.Ctxt, $1.Name, 1);
   701  		$$.Offset = int64($4);
   702  	}
   703  
   704  offset:
   705  	{
   706  		$$ = 0;
   707  	}
   708  |	'+' con
   709  	{
   710  		$$ = $2;
   711  	}
   712  |	'-' con
   713  	{
   714  		$$ = -$2;
   715  	}
   716  
   717  pointer:
   718  	LSB
   719  |	LSP
   720  |	LFP
   721  
   722  con:
   723  	LCONST
   724  |	LVAR
   725  	{
   726  		$$ = int32($1.Value);
   727  	}
   728  |	'-' con
   729  	{
   730  		$$ = -$2;
   731  	}
   732  |	'+' con
   733  	{
   734  		$$ = $2;
   735  	}
   736  |	'~' con
   737  	{
   738  		$$ = ^$2;
   739  	}
   740  |	'(' expr ')'
   741  	{
   742  		$$ = $2;
   743  	}
   744  
   745  oexpr:
   746  	{
   747  		$$ = 0;
   748  	}
   749  |	',' expr
   750  	{
   751  		$$ = $2;
   752  	}
   753  
   754  expr:
   755  	con
   756  |	expr '+' expr
   757  	{
   758  		$$ = $1 + $3;
   759  	}
   760  |	expr '-' expr
   761  	{
   762  		$$ = $1 - $3;
   763  	}
   764  |	expr '*' expr
   765  	{
   766  		$$ = $1 * $3;
   767  	}
   768  |	expr '/' expr
   769  	{
   770  		$$ = $1 / $3;
   771  	}
   772  |	expr '%' expr
   773  	{
   774  		$$ = $1 % $3;
   775  	}
   776  |	expr '<' '<' expr
   777  	{
   778  		$$ = $1 << uint($4);
   779  	}
   780  |	expr '>' '>' expr
   781  	{
   782  		$$ = $1 >> uint($4);
   783  	}
   784  |	expr '&' expr
   785  	{
   786  		$$ = $1 & $3;
   787  	}
   788  |	expr '^' expr
   789  	{
   790  		$$ = $1 ^ $3;
   791  	}
   792  |	expr '|' expr
   793  	{
   794  		$$ = $1 | $3;
   795  	}