<commit_before>-----------------------------------------------------------------------------
--
-- (c) The University of Glasgow, 2004
--
-- Parser for concrete Cmm.
--
-----------------------------------------------------------------------------

{
module CmmParse ( parseCmmFile ) where

import CgMonad
import CgHeapery
import CgUtils
import CgProf
import CgTicky
import CgInfoTbls
import CgForeignCall
import CgTailCall	( pushUnboxedTuple )
import CgStackery	( emitPushUpdateFrame )
import ClosureInfo	( C_SRT(..) )
import CgCallConv	( smallLiveness )
import CgClosure	( emitBlackHoleCode )
import CostCentre	( dontCareCCS )

import Cmm
import PprCmm
import CmmUtils		( mkIntCLit )
import CmmLex
import CLabel
import MachOp
import SMRep		( fixedHdrSize, CgRep(..) )
import Lexer

import ForeignCall	( CCallConv(..) )
import Literal		( mkMachInt )
import Unique
import UniqFM
import SrcLoc
import DynFlags		( DynFlags, DynFlag(..) )
import Packages		( HomeModules )
import StaticFlags	( opt_SccProfilingOn )
import ErrUtils		( printError, dumpIfSet_dyn, showPass )
import StringBuffer	( hGetStringBuffer )
import FastString
import Panic		( panic )
import Constants	( wORD_SIZE )
import Outputable

import Monad		( when )

#include "HsVersions.h"
}

%token
	':'	{ L _ (CmmT_SpecChar ':') }
	';'	{ L _ (CmmT_SpecChar ';') }
	'{'	{ L _ (CmmT_SpecChar '{') }
	'}'	{ L _ (CmmT_SpecChar '}') }
	'['	{ L _ (CmmT_SpecChar '[') }
	']'	{ L _ (CmmT_SpecChar ']') }
	'('	{ L _ (CmmT_SpecChar '(') }
	')'	{ L _ (CmmT_SpecChar ')') }
	'='	{ L _ (CmmT_SpecChar '=') }
	'`'	{ L _ (CmmT_SpecChar '`') }
	'~'	{ L _ (CmmT_SpecChar '~') }
	'/'	{ L _ (CmmT_SpecChar '/') }
	'*'	{ L _ (CmmT_SpecChar '*') }
	'%'	{ L _ (CmmT_SpecChar '%') }
	'-'	{ L _ (CmmT_SpecChar '-') }
	'+'	{ L _ (CmmT_SpecChar '+') }
	'&'	{ L _ (CmmT_SpecChar '&') }
	'^'	{ L _ (CmmT_SpecChar '^') }
	'|'	{ L _ (CmmT_SpecChar '|') }
	'>'	{ L _ (CmmT_SpecChar '>') }
	'<'	{ L _ (CmmT_SpecChar '<') }
	','	{ L _ (CmmT_SpecChar ',') }
	'!'	{ L _ (CmmT_SpecChar '!') }

 	'..'	{ L _ (CmmT_DotDot) }
 	'::'	{ L _ (CmmT_DoubleColon) }
	'>>'	{ L _ (CmmT_Shr) }
	'<<'	{ L _ (CmmT_Shl) }
	'>='	{ L _ (CmmT_Ge) }
	'<='	{ L _ (CmmT_Le) }
	'=='	{ L _ (CmmT_Eq) }
	'!='	{ L _ (CmmT_Ne) }
        '&&'    { L _ (CmmT_BoolAnd) }
        '||'    { L _ (CmmT_BoolOr) }

	'CLOSURE'	{ L _ (CmmT_CLOSURE) }
	'INFO_TABLE'	{ L _ (CmmT_INFO_TABLE) }
	'INFO_TABLE_RET'{ L _ (CmmT_INFO_TABLE_RET) }
	'INFO_TABLE_FUN'{ L _ (CmmT_INFO_TABLE_FUN) }
	'INFO_TABLE_CONSTR'{ L _ (CmmT_INFO_TABLE_CONSTR) }
	'INFO_TABLE_SELECTOR'{ L _ (CmmT_INFO_TABLE_SELECTOR) }
	'else'		{ L _ (CmmT_else) }
	'export'	{ L _ (CmmT_export) }
	'section'	{ L _ (CmmT_section) }
	'align'		{ L _ (CmmT_align) }
	'goto'		{ L _ (CmmT_goto) }
	'if'		{ L _ (CmmT_if) }
	'jump'		{ L _ (CmmT_jump) }
	'foreign'	{ L _ (CmmT_foreign) }
	'import'	{ L _ (CmmT_import) }
	'switch'	{ L _ (CmmT_switch) }
	'case'		{ L _ (CmmT_case) }
	'default'	{ L _ (CmmT_default) }
	'bits8'		{ L _ (CmmT_bits8) }
	'bits16'	{ L _ (CmmT_bits16) }
	'bits32'	{ L _ (CmmT_bits32) }
	'bits64'	{ L _ (CmmT_bits64) }
	'float32'	{ L _ (CmmT_float32) }
	'float64'	{ L _ (CmmT_float64) }

	GLOBALREG	{ L _ (CmmT_GlobalReg   $$) }
  	NAME		{ L _ (CmmT_Name	$$) }
	STRING		{ L _ (CmmT_String	$$) }
	INT		{ L _ (CmmT_Int		$$) }
	FLOAT		{ L _ (CmmT_Float	$$) }

%monad { P } { >>= } { return }
%lexer { cmmlex } { L _ CmmT_EOF }
%name cmmParse cmm
%tokentype { Located CmmToken }

-- C-- operator precedences, taken from the C-- spec
%right '||'	-- non-std extension, called %disjoin in C--
%right '&&'	-- non-std extension, called %conjoin in C--
%right '!'
%nonassoc '>=' '>' '<=' '<' '!=' '=='
%left '|'
%left '^'
%left '&'
%left '>>' '<<'
%left '-' '+'
%left '/' '*' '%'
%right '~'

%%

cmm	:: { ExtCode }
	: {- empty -}			{ return () }
	| cmmtop cmm			{ do $1; $2 }

cmmtop	:: { ExtCode }
	: cmmproc			{ $1 }
	| cmmdata			{ $1 }
	| decl				{ $1 } 
	| 'CLOSURE' '(' NAME ',' NAME lits ')' ';'  
		{ do lits <- sequence $6;
		     staticClosure $3 $5 (map getLit lits) }

-- The only static closures in the RTS are dummy closures like
-- stg_END_TSO_QUEUE_closure and stg_dummy_ret.  We don't need
-- to provide the full generality of static closures here.
-- In particular:
-- 	* CCS can always be CCS_DONT_CARE
-- 	* closure is always extern
-- 	* payload is always empty
--	* we can derive closure and info table labels from a single NAME

cmmdata :: { ExtCode }
	: 'section' STRING '{' statics '}' 
		{ do ss <- sequence $4;
		     code (emitData (section $2) (concat ss)) }

statics	:: { [ExtFCode [CmmStatic]] }
	: {- empty -}			{ [] }
	| static statics		{ $1 : $2 }

-- Strings aren't used much in the RTS HC code, so it doesn't seem
-- worth allowing inline strings.  C-- doesn't allow them anyway.
static 	:: { ExtFCode [CmmStatic] }
	: NAME ':'	{ return [CmmDataLabel (mkRtsDataLabelFS $1)] }
	| type expr ';'	{ do e <- $2;
			     return [CmmStaticLit (getLit e)] }
	| type ';'			{ return [CmmUninitialised
							(machRepByteWidth $1)] }
        | 'bits8' '[' ']' STRING ';'	{ return [CmmString $4] }
        | 'bits8' '[' INT ']' ';'	{ return [CmmUninitialised 
							(fromIntegral $3)] }
        | typenot8 '[' INT ']' ';'	{ return [CmmUninitialised 
						(machRepByteWidth $1 * 
							fromIntegral $3)] }
	| 'align' INT ';'		{ return [CmmAlign (fromIntegral $2)] }
	| 'CLOSURE' '(' NAME lits ')'
		{ do lits <- sequence $4;
		     return $ map CmmStaticLit $
		       mkStaticClosure (mkRtsInfoLabelFS $3) 
			 dontCareCCS (map getLit lits) [] [] [] }
	-- arrays of closures required for the CHARLIKE & INTLIKE arrays

lits	:: { [ExtFCode CmmExpr] }
	: {- empty -}		{ [] }
	| ',' expr lits		{ $2 : $3 }

cmmproc :: { ExtCode }
	: info '{' body '}'
		{ do  (info_lbl, info1, info2) <- $1;
		      stmts <- getCgStmtsEC (loopDecls $3)
		      blks <- code (cgStmtsToBlocks stmts)
		      code (emitInfoTableAndCode info_lbl info1 info2 [] blks) }

	| info ';'
		{ do (info_lbl, info1, info2) <- $1;
		     code (emitInfoTableAndCode info_lbl info1 info2 [] []) }

	| NAME '{' body '}'
		{ do stmts <- getCgStmtsEC (loopDecls $3);
		     blks <- code (cgStmtsToBlocks stmts)
		     code (emitProc [] (mkRtsCodeLabelFS $1) [] blks) }

info	:: { ExtFCode (CLabel, [CmmLit],[CmmLit]) }
	: 'INFO_TABLE' '(' NAME ',' INT ',' INT ',' INT ',' STRING ',' STRING ')'
		-- ptrs, nptrs, closure type, description, type
		{ stdInfo $3 $5 $7 0 $9 $11 $13 }
	
	| 'INFO_TABLE_FUN' '(' NAME ',' INT ',' INT ',' INT ',' STRING ',' STRING ',' INT ')'
		-- ptrs, nptrs, closure type, description, type, fun type
		{ funInfo $3 $5 $7 $9 $11 $13 $15 }
	
	| 'INFO_TABLE_CONSTR' '(' NAME ',' INT ',' INT ',' INT ',' INT ',' STRING ',' STRING ')'
		-- ptrs, nptrs, tag, closure type, description, type
		{ stdInfo $3 $5 $7 $9 $11 $13 $15 }
	
	| 'INFO_TABLE_SELECTOR' '(' NAME ',' INT ',' INT ',' STRING ',' STRING ')'
		-- selector, closure type, description, type
		{ basicInfo $3 (mkIntCLit (fromIntegral $5)) 0 $7 $9 $11 }

	| 'INFO_TABLE_RET' '(' NAME ',' INT ',' INT ',' INT maybe_vec ')'
		{ retInfo $3 $5 $7 $9 $10 }

maybe_vec :: { [CmmLit] }
	: {- empty -}			{ [] }
	| ',' NAME maybe_vec		{ CmmLabel (mkRtsCodeLabelFS $2) : $3 }

body	:: { ExtCode }
	: {- empty -}			{ return () }
	| decl body			{ do $1; $2 }
	| stmt body			{ do $1; $2 }

decl	:: { ExtCode }
	: type names ';'		{ mapM_ (newLocal $1) $2 }
	| 'import' names ';'		{ return () }  -- ignore imports
	| 'export' names ';'		{ return () }  -- ignore exports

names 	:: { [FastString] }
	: NAME			{ [$1] }
	| NAME ',' names	{ $1 : $3 }

stmt	:: { ExtCode }
	: ';'					{ nopEC }

	| block_id ':'				{ code (labelC $1) }

	| lreg '=' expr ';'			
		{ do reg <- $1; e <- $3; stmtEC (CmmAssign reg e) }
	| type '[' expr ']' '=' expr ';'
		{ doStore $1 $3 $6 }
	| 'foreign' STRING expr '(' hint_exprs0 ')' vols ';'
		{% foreignCall $2 [] $3 $5 $7 }
	| lreg '=' 'foreign' STRING expr '(' hint_exprs0 ')' vols ';'
		{% let result = do r <- $1; return (r,NoHint) in
		   foreignCall $4 [result] $5 $7 $9 }
	| STRING lreg '=' 'foreign' STRING expr '(' hint_exprs0 ')' vols ';'
		{% do h <- parseHint $1;
		      let result = do r <- $2; return (r,h) in
		      foreignCall $5 [result] $6 $8 $10 }
	-- stmt-level macros, stealing syntax from ordinary C-- function calls.
	-- Perhaps we ought to use the %%-form?
	| NAME '(' exprs0 ')' ';'
		{% stmtMacro $1 $3  }
	| 'switch' maybe_range expr '{' arms default '}'
		{ doSwitch $2 $3 $5 $6 }
	| 'goto' block_id ';'
		{ stmtEC (CmmBranch $2) }
	| 'jump' expr {-maybe_actuals-} ';'
		{ do e <- $2; stmtEC (CmmJump e []) }
	| 'if' bool_expr '{' body '}' else 	
		{ ifThenElse $2 $4 $6 }

bool_expr :: { ExtFCode BoolExpr }
	: bool_op			{ $1 }
	| expr				{ do e <- $1; return (BoolTest e) }

bool_op :: { ExtFCode BoolExpr }
	: bool_expr '&&' bool_expr 	{ do e1 <- $1; e2 <- $3; 
					  return (BoolAnd e1 e2) }
	| bool_expr '||' bool_expr	{ do e1 <- $1; e2 <- $3; 
					  return (BoolOr e1 e2)  }
	| '!' bool_expr			{ do e <- $2; return (BoolNot e) }
	| '(' bool_op ')'		{ $2 }

-- This is not C-- syntax.  What to do?
vols 	:: { Maybe [GlobalReg] }
	: {- empty -}			{ Nothing }
	| '[' globals ']'		{ Just $2 }

globals :: { [GlobalReg] }
	: GLOBALREG			{ [$1] }
	| GLOBALREG ',' globals		{ $1 : $3 }

maybe_range :: { Maybe (Int,Int) }
	: '[' INT '..' INT ']'	{ Just (fromIntegral $2, fromIntegral $4) }
	| {- empty -}		{ Nothing }

arms	:: { [([Int],ExtCode)] }
	: {- empty -}			{ [] }
	| arm arms			{ $1 : $2 }<commit_msg>[project @ 2005-08-02 12:01:57 by simonmar] Allow an empty list of volatile regs on a call<commit_after>-----------------------------------------------------------------------------
--
-- (c) The University of Glasgow, 2004
--
-- Parser for concrete Cmm.
--
-----------------------------------------------------------------------------

{
module CmmParse ( parseCmmFile ) where

import CgMonad
import CgHeapery
import CgUtils
import CgProf
import CgTicky
import CgInfoTbls
import CgForeignCall
import CgTailCall	( pushUnboxedTuple )
import CgStackery	( emitPushUpdateFrame )
import ClosureInfo	( C_SRT(..) )
import CgCallConv	( smallLiveness )
import CgClosure	( emitBlackHoleCode )
import CostCentre	( dontCareCCS )

import Cmm
import PprCmm
import CmmUtils		( mkIntCLit )
import CmmLex
import CLabel
import MachOp
import SMRep		( fixedHdrSize, CgRep(..) )
import Lexer

import ForeignCall	( CCallConv(..) )
import Literal		( mkMachInt )
import Unique
import UniqFM
import SrcLoc
import DynFlags		( DynFlags, DynFlag(..) )
import Packages		( HomeModules )
import StaticFlags	( opt_SccProfilingOn )
import ErrUtils		( printError, dumpIfSet_dyn, showPass )
import StringBuffer	( hGetStringBuffer )
import FastString
import Panic		( panic )
import Constants	( wORD_SIZE )
import Outputable

import Monad		( when )

#include "HsVersions.h"
}

%token
	':'	{ L _ (CmmT_SpecChar ':') }
	';'	{ L _ (CmmT_SpecChar ';') }
	'{'	{ L _ (CmmT_SpecChar '{') }
	'}'	{ L _ (CmmT_SpecChar '}') }
	'['	{ L _ (CmmT_SpecChar '[') }
	']'	{ L _ (CmmT_SpecChar ']') }
	'('	{ L _ (CmmT_SpecChar '(') }
	')'	{ L _ (CmmT_SpecChar ')') }
	'='	{ L _ (CmmT_SpecChar '=') }
	'`'	{ L _ (CmmT_SpecChar '`') }
	'~'	{ L _ (CmmT_SpecChar '~') }
	'/'	{ L _ (CmmT_SpecChar '/') }
	'*'	{ L _ (CmmT_SpecChar '*') }
	'%'	{ L _ (CmmT_SpecChar '%') }
	'-'	{ L _ (CmmT_SpecChar '-') }
	'+'	{ L _ (CmmT_SpecChar '+') }
	'&'	{ L _ (CmmT_SpecChar '&') }
	'^'	{ L _ (CmmT_SpecChar '^') }
	'|'	{ L _ (CmmT_SpecChar '|') }
	'>'	{ L _ (CmmT_SpecChar '>') }
	'<'	{ L _ (CmmT_SpecChar '<') }
	','	{ L _ (CmmT_SpecChar ',') }
	'!'	{ L _ (CmmT_SpecChar '!') }

 	'..'	{ L _ (CmmT_DotDot) }
 	'::'	{ L _ (CmmT_DoubleColon) }
	'>>'	{ L _ (CmmT_Shr) }
	'<<'	{ L _ (CmmT_Shl) }
	'>='	{ L _ (CmmT_Ge) }
	'<='	{ L _ (CmmT_Le) }
	'=='	{ L _ (CmmT_Eq) }
	'!='	{ L _ (CmmT_Ne) }
        '&&'    { L _ (CmmT_BoolAnd) }
        '||'    { L _ (CmmT_BoolOr) }

	'CLOSURE'	{ L _ (CmmT_CLOSURE) }
	'INFO_TABLE'	{ L _ (CmmT_INFO_TABLE) }
	'INFO_TABLE_RET'{ L _ (CmmT_INFO_TABLE_RET) }
	'INFO_TABLE_FUN'{ L _ (CmmT_INFO_TABLE_FUN) }
	'INFO_TABLE_CONSTR'{ L _ (CmmT_INFO_TABLE_CONSTR) }
	'INFO_TABLE_SELECTOR'{ L _ (CmmT_INFO_TABLE_SELECTOR) }
	'else'		{ L _ (CmmT_else) }
	'export'	{ L _ (CmmT_export) }
	'section'	{ L _ (CmmT_section) }
	'align'		{ L _ (CmmT_align) }
	'goto'		{ L _ (CmmT_goto) }
	'if'		{ L _ (CmmT_if) }
	'jump'		{ L _ (CmmT_jump) }
	'foreign'	{ L _ (CmmT_foreign) }
	'import'	{ L _ (CmmT_import) }
	'switch'	{ L _ (CmmT_switch) }
	'case'		{ L _ (CmmT_case) }
	'default'	{ L _ (CmmT_default) }
	'bits8'		{ L _ (CmmT_bits8) }
	'bits16'	{ L _ (CmmT_bits16) }
	'bits32'	{ L _ (CmmT_bits32) }
	'bits64'	{ L _ (CmmT_bits64) }
	'float32'	{ L _ (CmmT_float32) }
	'float64'	{ L _ (CmmT_float64) }

	GLOBALREG	{ L _ (CmmT_GlobalReg   $$) }
  	NAME		{ L _ (CmmT_Name	$$) }
	STRING		{ L _ (CmmT_String	$$) }
	INT		{ L _ (CmmT_Int		$$) }
	FLOAT		{ L _ (CmmT_Float	$$) }

%monad { P } { >>= } { return }
%lexer { cmmlex } { L _ CmmT_EOF }
%name cmmParse cmm
%tokentype { Located CmmToken }

-- C-- operator precedences, taken from the C-- spec
%right '||'	-- non-std extension, called %disjoin in C--
%right '&&'	-- non-std extension, called %conjoin in C--
%right '!'
%nonassoc '>=' '>' '<=' '<' '!=' '=='
%left '|'
%left '^'
%left '&'
%left '>>' '<<'
%left '-' '+'
%left '/' '*' '%'
%right '~'

%%

cmm	:: { ExtCode }
	: {- empty -}			{ return () }
	| cmmtop cmm			{ do $1; $2 }

cmmtop	:: { ExtCode }
	: cmmproc			{ $1 }
	| cmmdata			{ $1 }
	| decl				{ $1 } 
	| 'CLOSURE' '(' NAME ',' NAME lits ')' ';'  
		{ do lits <- sequence $6;
		     staticClosure $3 $5 (map getLit lits) }

-- The only static closures in the RTS are dummy closures like
-- stg_END_TSO_QUEUE_closure and stg_dummy_ret.  We don't need
-- to provide the full generality of static closures here.
-- In particular:
-- 	* CCS can always be CCS_DONT_CARE
-- 	* closure is always extern
-- 	* payload is always empty
--	* we can derive closure and info table labels from a single NAME

cmmdata :: { ExtCode }
	: 'section' STRING '{' statics '}' 
		{ do ss <- sequence $4;
		     code (emitData (section $2) (concat ss)) }

statics	:: { [ExtFCode [CmmStatic]] }
	: {- empty -}			{ [] }
	| static statics		{ $1 : $2 }

-- Strings aren't used much in the RTS HC code, so it doesn't seem
-- worth allowing inline strings.  C-- doesn't allow them anyway.
static 	:: { ExtFCode [CmmStatic] }
	: NAME ':'	{ return [CmmDataLabel (mkRtsDataLabelFS $1)] }
	| type expr ';'	{ do e <- $2;
			     return [CmmStaticLit (getLit e)] }
	| type ';'			{ return [CmmUninitialised
							(machRepByteWidth $1)] }
        | 'bits8' '[' ']' STRING ';'	{ return [CmmString $4] }
        | 'bits8' '[' INT ']' ';'	{ return [CmmUninitialised 
							(fromIntegral $3)] }
        | typenot8 '[' INT ']' ';'	{ return [CmmUninitialised 
						(machRepByteWidth $1 * 
							fromIntegral $3)] }
	| 'align' INT ';'		{ return [CmmAlign (fromIntegral $2)] }
	| 'CLOSURE' '(' NAME lits ')'
		{ do lits <- sequence $4;
		     return $ map CmmStaticLit $
		       mkStaticClosure (mkRtsInfoLabelFS $3) 
			 dontCareCCS (map getLit lits) [] [] [] }
	-- arrays of closures required for the CHARLIKE & INTLIKE arrays

lits	:: { [ExtFCode CmmExpr] }
	: {- empty -}		{ [] }
	| ',' expr lits		{ $2 : $3 }

cmmproc :: { ExtCode }
	: info '{' body '}'
		{ do  (info_lbl, info1, info2) <- $1;
		      stmts <- getCgStmtsEC (loopDecls $3)
		      blks <- code (cgStmtsToBlocks stmts)
		      code (emitInfoTableAndCode info_lbl info1 info2 [] blks) }

	| info ';'
		{ do (info_lbl, info1, info2) <- $1;
		     code (emitInfoTableAndCode info_lbl info1 info2 [] []) }

	| NAME '{' body '}'
		{ do stmts <- getCgStmtsEC (loopDecls $3);
		     blks <- code (cgStmtsToBlocks stmts)
		     code (emitProc [] (mkRtsCodeLabelFS $1) [] blks) }

info	:: { ExtFCode (CLabel, [CmmLit],[CmmLit]) }
	: 'INFO_TABLE' '(' NAME ',' INT ',' INT ',' INT ',' STRING ',' STRING ')'
		-- ptrs, nptrs, closure type, description, type
		{ stdInfo $3 $5 $7 0 $9 $11 $13 }
	
	| 'INFO_TABLE_FUN' '(' NAME ',' INT ',' INT ',' INT ',' STRING ',' STRING ',' INT ')'
		-- ptrs, nptrs, closure type, description, type, fun type
		{ funInfo $3 $5 $7 $9 $11 $13 $15 }
	
	| 'INFO_TABLE_CONSTR' '(' NAME ',' INT ',' INT ',' INT ',' INT ',' STRING ',' STRING ')'
		-- ptrs, nptrs, tag, closure type, description, type
		{ stdInfo $3 $5 $7 $9 $11 $13 $15 }
	
	| 'INFO_TABLE_SELECTOR' '(' NAME ',' INT ',' INT ',' STRING ',' STRING ')'
		-- selector, closure type, description, type
		{ basicInfo $3 (mkIntCLit (fromIntegral $5)) 0 $7 $9 $11 }

	| 'INFO_TABLE_RET' '(' NAME ',' INT ',' INT ',' INT maybe_vec ')'
		{ retInfo $3 $5 $7 $9 $10 }

maybe_vec :: { [CmmLit] }
	: {- empty -}			{ [] }
	| ',' NAME maybe_vec		{ CmmLabel (mkRtsCodeLabelFS $2) : $3 }

body	:: { ExtCode }
	: {- empty -}			{ return () }
	| decl body			{ do $1; $2 }
	| stmt body			{ do $1; $2 }

decl	:: { ExtCode }
	: type names ';'		{ mapM_ (newLocal $1) $2 }
	| 'import' names ';'		{ return () }  -- ignore imports
	| 'export' names ';'		{ return () }  -- ignore exports

names 	:: { [FastString] }
	: NAME			{ [$1] }
	| NAME ',' names	{ $1 : $3 }

stmt	:: { ExtCode }
	: ';'					{ nopEC }

	| block_id ':'				{ code (labelC $1) }

	| lreg '=' expr ';'			
		{ do reg <- $1; e <- $3; stmtEC (CmmAssign reg e) }
	| type '[' expr ']' '=' expr ';'
		{ doStore $1 $3 $6 }
	| 'foreign' STRING expr '(' hint_exprs0 ')' vols ';'
		{% foreignCall $2 [] $3 $5 $7 }
	| lreg '=' 'foreign' STRING expr '(' hint_exprs0 ')' vols ';'
		{% let result = do r <- $1; return (r,NoHint) in
		   foreignCall $4 [result] $5 $7 $9 }
	| STRING lreg '=' 'foreign' STRING expr '(' hint_exprs0 ')' vols ';'
		{% do h <- parseHint $1;
		      let result = do r <- $2; return (r,h) in
		      foreignCall $5 [result] $6 $8 $10 }
	-- stmt-level macros, stealing syntax from ordinary C-- function calls.
	-- Perhaps we ought to use the %%-form?
	| NAME '(' exprs0 ')' ';'
		{% stmtMacro $1 $3  }
	| 'switch' maybe_range expr '{' arms default '}'
		{ doSwitch $2 $3 $5 $6 }
	| 'goto' block_id ';'
		{ stmtEC (CmmBranch $2) }
	| 'jump' expr {-maybe_actuals-} ';'
		{ do e <- $2; stmtEC (CmmJump e []) }
	| 'if' bool_expr '{' body '}' else 	
		{ ifThenElse $2 $4 $6 }

bool_expr :: { ExtFCode BoolExpr }
	: bool_op			{ $1 }
	| expr				{ do e <- $1; return (BoolTest e) }

bool_op :: { ExtFCode BoolExpr }
	: bool_expr '&&' bool_expr 	{ do e1 <- $1; e2 <- $3; 
					  return (BoolAnd e1 e2) }
	| bool_expr '||' bool_expr	{ do e1 <- $1; e2 <- $3; 
					  return (BoolOr e1 e2)  }
	| '!' bool_expr			{ do e <- $2; return (BoolNot e) }
	| '(' bool_op ')'		{ $2 }

-- This is not C-- syntax.  What to do?
vols 	:: { Maybe [GlobalReg] }
	: {- empty -}			{ Nothing }
	| '[' ']'		        { Just [] }
	| '[' globals ']'		{ Just $2 }

globals :: { [GlobalReg] }
	: GLOBALREG			{ [$1] }
	| GLOBALREG ',' globals		{ $1 : $3 }

maybe_range :: { Maybe (Int,Int) }
	: '[' INT '..' INT ']'	{ Just (fromIntegral $2, fromIntegral $4) }
	| {- empty -}		{ Nothing }

arms	:: { [([Int],ExtCode)] }
	: {- empty -}			{ [] }
	| arm arms			{ $1 : $2 }
{'fraction_non_alphanumeric': 0.206473272832188, 'fraction_numerical': 0.019619157530294286, 'mean_word_length': 2.7358416617675876, 'pattern_counts': {'":': 0, '<': 65, '<?xml version=': 0, '>': 25, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 2, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4092324', 'n_tokens_mistral': 8818, 'n_tokens_neox': 8268, 'n_words': 1903}