chapel-lang / chapel

a Productive Parallel Programming Language
https://chapel-lang.org
Other
1.78k stars 418 forks source link

Grammar railroad diagram #18051

Open mingodad opened 3 years ago

mingodad commented 3 years ago

Using this tool https://www.bottlecaps.de/convert/ and manually adding the tokens from main/compiler/parser/chapel.lex we can see a railroad diagram for the grammar in main/compiler/parser/chapel.ypp copy and paste the EBNF shown bellow on https://www.bottlecaps.de/rr/ui in the tab Edit Grammar then switching to the tab View Diagram.

/*
From https://raw.githubusercontent.com/chapel-lang/chapel/main/compiler/parser/chapel.ypp
*/

/* converted on Mon Jul 12, 2021, 11:00 (UTC+02) by bison-to-w3c v0.51 which is Copyright (c) 2011-2021 by Gunther Rademacher <grd@gmx.net> */

program  ::= toplevel_stmt*
toplevel_stmt
         ::= pragma_ls? stmt
pragma_ls
         ::= ( TPRAGMA STRINGLITERAL )+
stmt     ::= ( TATOMIC | TBEGIN opt_task_intent_ls | TLABEL ident_def | TSYNC )* ( deprecated_decl_stmt | include_module_stmt | ( TCOBEGIN opt_task_intent_ls )? block_stmt | use_stmt | import_stmt | require_stmt | assignment_stmt | extern_block_stmt | if_stmt | implements_stmt | interface_stmt | loop_stmt | select_stmt | defer_stmt | try_stmt | throw_stmt | return_stmt | ( stmt_level_expr | ( TBREAK | TCONTINUE ) opt_label_ident | ( TDELETE ( expr TCOMMA )* | TYIELD ) expr | error ) TSEMI | ( ( TLOCAL | TSERIAL ) expr? | TON expr ) do_stmt )
deprecated_decl_stmt
         ::= ( TDEPRECATED STRINGLITERAL? )? deprecated_decl_base
deprecated_decl_base
         ::= module_decl_stmt
           | class_level_stmt
module_decl_start
         ::= access_control opt_prototype TMODULE ident_def
module_decl_stmt
         ::= module_decl_start TLCBR ( stmt_ls | error )? TRCBR
access_control
         ::= ( TPUBLIC | TPRIVATE )?
opt_prototype
         ::= TPROTOTYPE?
include_access_control
         ::= ( TPUBLIC | TPRIVATE )?
include_module_stmt
         ::= TINCLUDE include_access_control opt_prototype TMODULE ident_def TSEMI
block_stmt
         ::= TLCBR ( stmt_ls | error )? TRCBR
stmt_ls  ::= toplevel_stmt+
renames_ls
         ::= expr ( TAS expr )? ( TCOMMA expr ( TAS expr )? )*
opt_only_ls
         ::= renames_ls?
except_ls
         ::= TSTAR
           | renames_ls
use_access_control
         ::= ( TPUBLIC | TPRIVATE )?
use_stmt ::= use_access_control TUSE expr ( TAS ( expr | TUNDERSCORE ) )? ( ( TCOMMA expr ( TAS ( expr | TUNDERSCORE ) )? )* | TEXCEPT except_ls | TONLY opt_only_ls ) TSEMI
import_stmt
         ::= use_access_control TIMPORT import_expr ( TCOMMA import_expr )* TSEMI
import_expr
         ::= expr ( TAS ident_use | TDOT TLCBR renames_ls TRCBR )?
require_stmt
         ::= TREQUIRE expr_ls TSEMI
assignment_stmt
         ::= lhs_expr ( ( assignop_ident | TSWAP | TASSIGNREDUCE | TASSIGNLAND | TASSIGNLOR ) opt_try_expr | TASSIGN TNOINIT ) TSEMI
opt_label_ident
         ::= TIDENT?
ident_fn_def
         ::= TIDENT
           | TNONE
           | TTHIS
           | TFALSE
           | TTRUE
           | internal_type_ident_def
ident_def
         ::= TIDENT
           | TNONE
           | TTHIS
           | TFALSE
           | TTRUE
           | internal_type_ident_def
ident_use
         ::= TIDENT
           | TTHIS
internal_type_ident_def
         ::= TBOOL
           | TINT
           | TUINT
           | TREAL
           | TIMAG
           | TCOMPLEX
           | TBYTES
           | TSTRING
           | TSYNC
           | TSINGLE
           | TOWNED
           | TSHARED
           | TBORROWED
           | TUNMANAGED
           | TDOMAIN
           | TINDEX
           | TLOCALE
           | TNOTHING
           | TVOID
scalar_type
         ::= TBOOL
           | TENUM
           | TINT
           | TUINT
           | TREAL
           | TIMAG
           | TCOMPLEX
           | TBYTES
           | TSTRING
           | TLOCALE
           | TNOTHING
           | TVOID
reserved_type_ident_use
         ::= TSYNC
           | TSINGLE
           | TDOMAIN
           | TINDEX
do_stmt  ::= TDO stmt
           | block_stmt
return_stmt
         ::= TRETURN opt_try_expr? TSEMI
deprecated_class_level_stmt
         ::= ( TDEPRECATED STRINGLITERAL? )? class_level_stmt
class_level_stmt
         ::= TSEMI
           | ( TPUBLIC | TPRIVATE )? private_decl
private_decl
         ::= fn_decl_stmt
           | var_decl_stmt
           | enum_decl_stmt
           | type_alias_decl_stmt
           | class_decl_stmt
           | forwarding_stmt
           | extern_export_decl_stmt
forwarding_stmt
         ::= TFORWARDING ( expr ( TEXCEPT except_ls | TONLY opt_only_ls )? TSEMI | var_decl_stmt )
extern_export_decl_stmt
         ::= TEXTERN ( STRINGLITERAL? ( TRECORD | TUNION ) ident_def opt_inherit TLCBR class_level_stmt_ls TRCBR | opt_expr ( fn_decl_stmt | var_decl_type var_decl_stmt_inner_ls TSEMI ) )
           | TEXPORT ( STRINGLITERAL? TRECORD ident_def opt_inherit TLCBR class_level_stmt_ls TRCBR | opt_expr ( fn_decl_stmt | var_decl_type var_decl_stmt_inner_ls TSEMI ) )
extern_block_stmt
         ::= TEXTERN EXTERNCODE
loop_stmt
         ::= TDO stmt TWHILE expr TSEMI
           | ( TWHILE ( expr | ifvar ) | TCOFORALL expr ( TIN ( expr | zippered_iterator ) )? opt_task_intent_ls | TFOR ( expr ( TIN ( expr | zippered_iterator ) )? | zippered_iterator | TPARAM ident_def TIN expr ) | ( TFORALL | TFOREACH ) ( expr ( TIN ( expr | zippered_iterator ) )? | zippered_iterator ) forall_intent_clause? ) do_stmt
           | TLSBR ( expr_ls ( TIN ( expr | zippered_iterator ) )? | zippered_iterator ) forall_intent_clause? TRSBR stmt
zippered_iterator
         ::= TZIP TLP expr_ls TRP
if_stmt  ::= TIF ( expr ( assignop_ident expr )? | ifvar ) ( TTHEN stmt | block_stmt ) ( TELSE stmt )?
ifvar    ::= ( TVAR | TCONST ) ident_def TASSIGN expr
interface_stmt
         ::= TINTERFACE ident_def ( TLP ifc_formal ( TCOMMA ifc_formal )* TRP )? block_stmt
ifc_formal
         ::= ident_def
implements_type_ident
         ::= TIDENT
           | TBOOL
           | TINT
           | TUINT
           | TREAL
           | TIMAG
           | TCOMPLEX
           | TBYTES
           | TSTRING
           | TLOCALE
           | TNOTHING
           | TVOID
           | implements_type_error_ident
implements_type_error_ident
         ::= TNONE
           | TTHIS
           | TFALSE
           | TTRUE
           | TDOMAIN
           | TINDEX
implements_stmt
         ::= ( TIMPLEMENTS ident_def TLP actual_ls TRP | implements_type_ident TIMPLEMENTS ident_def ( TLP actual_ls TRP )? ) TSEMI
ifc_constraint
         ::= TIMPLEMENTS ident_def TLP actual_ls TRP
           | implements_type_ident TIMPLEMENTS ident_def ( TLP actual_ls TRP )?
defer_stmt
         ::= TDEFER stmt
try_stmt ::= ( TTRY | TTRYBANG ) ( expr TSEMI | assignment_stmt | block_stmt catch_stmt_ls )
catch_stmt_ls
         ::= catch_stmt*
catch_stmt
         ::= TCATCH ( catch_expr | TLP catch_expr TRP )? block_stmt
catch_expr
         ::= ident_def ( TCOLON expr )?
throw_stmt
         ::= TTHROW expr TSEMI
select_stmt
         ::= TSELECT expr TLCBR ( when_stmt* | error ) TRCBR
when_stmt
         ::= TWHEN expr_ls do_stmt
           | TOTHERWISE TDO? stmt
class_decl_stmt
         ::= class_tag ident_def opt_inherit TLCBR ( class_level_stmt_ls | error ) TRCBR
class_tag
         ::= TCLASS
           | TRECORD
           | TUNION
opt_inherit
         ::= ( TCOLON expr_ls )?
class_level_stmt_ls
         ::= ( pragma_ls? deprecated_class_level_stmt )*
enum_decl_stmt
         ::= enum_header ident_def TLCBR ( deprecated_enum_item ( TCOMMA deprecated_enum_item? )* | error ) TRCBR
enum_header
         ::= TENUM
deprecated_enum_item
         ::= ( TDEPRECATED STRINGLITERAL? )? enum_item
enum_item
         ::= ident_def ( TASSIGN expr )?
lambda_decl_expr
         ::= TLAMBDA req_formal_ls opt_ret_tag opt_type opt_lifetime_where function_body_stmt
linkage_spec
         ::= ( TINLINE | TOVERRIDE )?
fn_decl_stmt
         ::= linkage_spec proc_iter_or_op fn_decl_stmt_inner opt_ret_tag opt_ret_type opt_throws_error opt_lifetime_where opt_function_body_stmt
fn_decl_stmt_inner
         ::= opt_this_intent_tag ( ( fn_decl_receiver_expr TDOT )? ( fn_ident | assignop_ident ) | error ) opt_formal_ls
fn_decl_receiver_expr
         ::= ident_expr
           | TLP expr TRP
fn_ident ::= ident_fn_def
           | TBAND
           | TBOR
           | TBXOR
           | TBNOT
           | TEQUAL
           | TNOTEQUAL
           | TLESSEQUAL
           | TGREATEREQUAL
           | TLESS
           | TGREATER
           | TPLUS
           | TMINUS
           | TSTAR
           | TDIVIDE
           | TSHIFTLEFT
           | TSHIFTRIGHT
           | TMOD
           | TEXP
           | ident_def? TBANG
           | TBY
           | THASH
           | TALIGN
           | TSWAP
           | TIO
           | TINITEQUALS
           | TCOLON
assignop_ident
         ::= TASSIGN
           | TASSIGNPLUS
           | TASSIGNMINUS
           | TASSIGNMULTIPLY
           | TASSIGNDIVIDE
           | TASSIGNMOD
           | TASSIGNEXP
           | TASSIGNBAND
           | TASSIGNBOR
           | TASSIGNBXOR
           | TASSIGNSR
           | TASSIGNSL
opt_formal_ls
         ::= ( TLP formal_ls TRP )?
req_formal_ls
         ::= TLP formal_ls TRP
formal_ls
         ::= ( formal ( TCOMMA formal )* )?
formal   ::= ( opt_intent_tag ( ident_def | TLP tuple_var_decl_stmt_inner_ls TRP ) | pragma_ls opt_intent_tag ident_def ) opt_formal_type ( opt_init_expr | var_arg_expr )
opt_intent_tag
         ::= required_intent_tag?
required_intent_tag
         ::= TIN
           | TINOUT
           | TOUT
           | TCONST ( TIN | TREF )?
           | TPARAM
           | TREF
           | TTYPE
opt_this_intent_tag
         ::= TCONST? TREF?
           | TPARAM
           | TTYPE
proc_iter_or_op
         ::= TPROC
           | TITER
           | TOPERATOR
opt_ret_tag
         ::= TCONST? TREF?
           | TPARAM
           | TTYPE
opt_throws_error
         ::= TTHROWS?
opt_function_body_stmt
         ::= TSEMI
           | function_body_stmt
function_body_stmt
         ::= block_stmt
           | return_stmt
query_expr
         ::= TQUERIEDIDENT
var_arg_expr
         ::= TDOTDOTDOT ( expr | query_expr )?
opt_lifetime_where
         ::= ( TWHERE expr ( TLIFETIME lifetime_components_expr )? | TLIFETIME lifetime_components_expr ( TWHERE expr )? )?
lifetime_components_expr
         ::= lifetime_expr ( TCOMMA lifetime_expr )*
lifetime_expr
         ::= ( lifetime_ident ( TASSIGN | TLESS | TLESSEQUAL | TEQUAL | TGREATER | TGREATEREQUAL ) | TRETURN ) lifetime_ident
lifetime_ident
         ::= TIDENT
           | TTHIS
type_alias_decl_stmt
         ::= ( TCONFIG | TEXTERN )? TTYPE type_alias_decl_stmt_inner TSEMI
type_alias_decl_stmt_inner
         ::= ident_def opt_init_type ( TCOMMA ident_def opt_init_type )*
opt_init_type
         ::= ( TASSIGN ( type_level_expr | array_type ) )?
var_decl_type
         ::= TPARAM
           | TCONST TREF?
           | TREF
           | TVAR
var_decl_stmt
         ::= TCONFIG? var_decl_type var_decl_stmt_inner_ls TSEMI
var_decl_stmt_inner_ls
         ::= var_decl_stmt_inner ( TCOMMA var_decl_stmt_inner )*
var_decl_stmt_inner
         ::= ( ident_def | TLP tuple_var_decl_stmt_inner_ls TRP ) opt_type opt_init_expr
tuple_var_decl_component
         ::= TUNDERSCORE
           | ident_def
           | TLP tuple_var_decl_stmt_inner_ls TRP
tuple_var_decl_stmt_inner_ls
         ::= tuple_var_decl_component ( TCOMMA tuple_var_decl_component )* TCOMMA?
opt_init_expr
         ::= ( TASSIGN ( TNOINIT | opt_try_expr ) )?
opt_ret_type
         ::= ( TCOLON ( type_level_expr | TLSBR ( expr_ls? TRSBR TLSBR )* ( expr_ls? TRSBR type_level_expr? | error TRSBR ) | reserved_type_ident_use ) | error )?
opt_type ::= ( TCOLON ( type_level_expr | array_type | reserved_type_ident_use ) | error )?
array_type
         ::= TLSBR ( expr_ls TRSBR TLSBR )* ( expr_ls ( TIN expr )? TRSBR type_level_expr | error TRSBR )
opt_formal_array_elt_type
         ::= ( type_level_expr | query_expr )?
opt_formal_type
         ::= ( TCOLON ( type_level_expr | query_expr | reserved_type_ident_use | TLSBR ( expr_ls? TRSBR TLSBR )* ( expr_ls ( TIN expr )? )? TRSBR opt_formal_array_elt_type ) )?
expr_ls  ::= ( expr | query_expr ) ( TCOMMA ( expr | query_expr ) )*
tuple_component
         ::= TUNDERSCORE
           | opt_try_expr
           | query_expr
tuple_expr_ls
         ::= tuple_component ( TCOMMA tuple_component )+
opt_actual_ls
         ::= actual_ls?
actual_ls
         ::= actual_expr ( TCOMMA actual_expr )*
actual_expr
         ::= ( ident_use TASSIGN )? ( query_expr | opt_try_expr )
ident_expr
         ::= ident_use
           | scalar_type
type_level_expr
         ::= sub_type_level_expr TQUESTION?
           | TQUESTION
sub_type_level_expr
         ::= nil_expr
           | lhs_expr
           | cond_expr
           | unary_op_expr
           | binary_op_expr
           | ( TSINGLE | TATOMIC | TSYNC ) expr
           | ( ( TINDEX | TDOMAIN | TSUBDOMAIN ) TLP opt_actual_ls | TSPARSE TSUBDOMAIN TLP actual_expr ) TRP
           | ( TOWNED | TUNMANAGED | TSHARED | TBORROWED ) expr?
           | TCLASS
           | TRECORD
for_expr ::= ( ( TFOR | TFORALL ) expr ( TIN ( expr | zippered_iterator ) )? TDO ( TIF expr TTHEN )? | TLSBR expr_ls ( TRSBR | TIN ( expr | zippered_iterator ) TRSBR ( TIF expr TTHEN )? ) ) expr
cond_expr
         ::= TIF expr TTHEN expr TELSE expr
nil_expr ::= TNIL
stmt_level_expr
         ::= nil_expr
           | ident_expr
           | dot_expr
           | call_expr
           | lambda_decl_expr
           | new_expr
           | let_expr
           | lhs_expr ( TIO expr )+
opt_task_intent_ls
         ::= task_intent_clause?
task_intent_clause
         ::= TWITH TLP intent_expr ( TCOMMA intent_expr )* TRP
forall_intent_clause
         ::= TWITH TLP intent_expr ( TCOMMA intent_expr )* TRP
intent_expr
         ::= shadow_var_prefix ident_expr opt_type opt_init_expr
           | ( reduce_scan_op_expr | expr ) TREDUCE ident_expr
shadow_var_prefix
         ::= TCONST ( TIN | TREF )?
           | TIN
           | TREF
           | TVAR
new_maybe_decorated
         ::= TNEW ( TOWNED | TSHARED | TUNMANAGED | TBORROWED )?
new_expr ::= new_maybe_decorated expr
           | TNEW ( TOWNED | TSHARED ) TLP expr TRP TLP opt_actual_ls TRP TQUESTION?
let_expr ::= TLET var_decl_stmt_inner_ls TIN expr
expr     ::= literal_expr
           | type_level_expr
           | for_expr
           | reduce_expr
           | scan_expr
           | lambda_decl_expr
           | new_expr
           | let_expr
           | ifc_constraint
           | TLP TDOTDOTDOT expr TRP
           | expr ( ( TCOLON | TDOTDOTOPENHIGH ) expr | TDOTDOT expr? )
           | TDOTDOT expr?
           | TDOTDOTOPENHIGH expr
opt_expr ::= expr?
opt_try_expr
         ::= ( TTRY | TTRYBANG )? expr
lhs_expr ::= ident_expr
           | call_expr
           | dot_expr
           | parenthesized_expr
call_base_expr
         ::= lhs_expr
           | expr TBANG
           | sub_type_level_expr TQUESTION
           | lambda_decl_expr
           | str_bytes_literal
call_expr
         ::= call_base_expr ( TLP opt_actual_ls TRP | TLSBR opt_actual_ls TRSBR )
           | TPRIMITIVE TLP opt_actual_ls TRP
dot_expr ::= expr TDOT ( ident_use | TTYPE | TDOMAIN | TLOCALE | TBYTES TLP TRP )
parenthesized_expr
         ::= TLP ( tuple_component | tuple_expr_ls ) TCOMMA? TRP
bool_literal
         ::= TFALSE
           | TTRUE
str_bytes_literal
         ::= STRINGLITERAL
           | BYTESLITERAL
literal_expr
         ::= bool_literal
           | str_bytes_literal
           | INTLITERAL
           | REALLITERAL
           | IMAGLITERAL
           | CSTRINGLITERAL
           | TNONE
           | TLCBR expr_ls TCOMMA? TRCBR
           | TLSBR ( expr_ls | assoc_expr_ls ) TCOMMA? TRSBR
assoc_expr_ls
         ::= expr TALIAS expr ( TCOMMA expr TALIAS expr )*
binary_op_expr
         ::= expr ( TPLUS | TMINUS | TSTAR | TDIVIDE | TSHIFTLEFT | TSHIFTRIGHT | TMOD | TEQUAL | TNOTEQUAL | TLESSEQUAL | TGREATEREQUAL | TLESS | TGREATER | TBAND | TBOR | TBXOR | TAND | TOR | TEXP | TBY | TALIGN | THASH | TDMAPPED ) expr
unary_op_expr
         ::= ( TPLUS | TMINUS | TMINUSMINUS | TPLUSPLUS | TBANG | TBNOT ) expr
           | expr TBANG
reduce_expr
         ::= ( expr | reduce_scan_op_expr ) TREDUCE ( expr | zippered_iterator )
scan_expr
         ::= ( expr | reduce_scan_op_expr ) TSCAN ( expr | zippered_iterator )
reduce_scan_op_expr
         ::= TPLUS
           | TSTAR
           | TAND
           | TOR
           | TBAND
           | TBOR
           | TBXOR

// Tokens from https://github.com/chapel-lang/chapel/blob/main/compiler/parser/chapel.lex

TALIGN ::= "align"
TAS ::= "as"
TATOMIC ::= "atomic"
TBEGIN ::= "begin"
TBOOL ::= "bool"
TBORROWED ::= "borrowed"
TBREAK ::= "break"
TBY ::= "by"
TBYTES ::= "bytes"
TCATCH ::= "catch"
TCLASS ::= "class"
TCOBEGIN ::= "cobegin"
TCOFORALL ::= "coforall"
TCOMPLEX ::= "complex"
TCONFIG ::= "config"
TCONST ::= "const"
TCONTINUE ::= "continue"
TDEFER ::= "defer"
TDELETE ::= "delete"
TDEPRECATED ::= "deprecated"
TDMAPPED ::= "dmapped"
TDO ::= "do"
TDOMAIN ::= "domain"
TELSE ::= "else"
TENUM ::= "enum"
TEXPORT ::= "export"
TEXCEPT ::= "except"
TFALSE ::= "false"
TFOR ::= "for"
TFORALL ::= "forall"
TFOREACH ::= "foreach"
TFORWARDING ::= "forwarding"
TIF ::= "if"
TIMAG ::= "imag"
TIMPORT ::= "import"
TIN ::= "in"
TINCLUDE ::= "include"
TINDEX ::= "index"
TINLINE ::= "inline"
TINOUT ::= "inout"
TINT ::= "int"
TIMPLEMENTS ::= "implements"
TINTERFACE ::= "interface"
TITER ::= "iter"
TLABEL ::= "label"
TLAMBDA ::= "lambda"
TLET ::= "let"
TLIFETIME ::= "lifetime"
TLOCAL ::= "local"
TLOCALE ::= "locale"
TMODULE ::= "module"
TNEW ::= "new"
TNIL ::= "nil"
TNOINIT ::= "noinit"
TNONE ::= "none"
TNOTHING ::= "nothing"
TON ::= "on"
TONLY ::= "only"
TOPERATOR ::= "operator"
TOTHERWISE ::= "otherwise"
TOUT ::= "out"
TOVERRIDE ::= "override"
TOWNED ::= "owned"
TPARAM ::= "param"
TPRAGMA ::= "pragma"
TPRIMITIVE ::= "__primitive"
TPRIVATE ::= "private"
TPROC ::= "proc"
TPROTOTYPE ::= "prototype"
TPUBLIC ::= "public"
TREAL ::= "real"
TRECORD ::= "record"
TREDUCE ::= "reduce"
TREF ::= "ref"
TREQUIRE ::= "require"
TRETURN ::= "return"
TSCAN ::= "scan"
TSELECT ::= "select"
TSERIAL ::= "serial"
TSHARED ::= "shared"
TSINGLE ::= "single"
TSPARSE ::= "sparse"
TSTRING ::= "string"
TSUBDOMAIN ::= "subdomain"
TSYNC ::= "sync"
TTHEN ::= "then"
TTHIS ::= "this"
TTHROW ::= "throw"
TTHROWS ::= "throws"
TTRUE ::= "true"
TTRY ::= "try"
TTRYBANG ::= "try!"
TTYPE ::= "type"
TUINT ::= "uint"
TUNION ::= "union"
TUNMANAGED ::= "unmanaged"
TUSE ::= "use"
TVAR ::= "var"
TVOID ::= "void"
TWHEN ::= "when"
TWHERE ::= "where"
TWHILE ::= "while"
TWITH ::= "with"
TYIELD ::= "yield"
TZIP ::= "zip"

TUNDERSCORE ::= "_"

TASSIGN ::= "="
TASSIGNPLUS ::= "+="
TASSIGNMINUS ::= "-="
TASSIGNMULTIPLY ::= "*="
TASSIGNDIVIDE ::= "/="
TASSIGNEXP ::= "**="
TASSIGNMOD ::= "%="
TASSIGNBAND ::= "&="
TASSIGNBOR ::= "|="
TASSIGNBXOR ::= "^="
TASSIGNLAND ::= "&&="
TASSIGNLOR ::= "||="
TASSIGNSL ::= "<<="
TASSIGNSR ::= ">>="
TASSIGNREDUCE ::= "reduce="

TINITEQUALS ::= "init="

TALIAS ::= "=>"

TSWAP ::= "<=>"

THASH ::= "#"
TDOTDOT ::= ".."
TDOTDOTOPENHIGH ::= "..<"
TDOTDOTDOT ::= "..."

TAND ::= "&&"
TOR ::= "||"
TBANG ::= "!"

TBAND ::= "&"
TBOR ::= "|"
TBXOR ::= "^"
TBNOT ::= "~"

TSHIFTLEFT ::= "<<"
TSHIFTRIGHT ::= ">>"

TEQUAL ::= "=="
TNOTEQUAL ::= "!="
TLESSEQUAL ::= "<="
TGREATEREQUAL ::= ">="
TLESS ::= "<"
TGREATER ::= ">"

TPLUS ::= "+"
TMINUS ::= "-"
TSTAR ::= "*"
TDIVIDE ::= "/"
TMOD ::= "%"
TMINUSMINUS ::= "--"
TPLUSPLUS ::= "++"

TEXP ::= "**"

TCOLON ::= ":"
TSEMI ::= ";"
TCOMMA ::= ","
TDOT ::= "."
TLP ::= "("
TRP ::= ")"
TLSBR ::= "["
TRSBR ::= "]"
TLCBR ::= "{"
TRCBR ::= "}"
TIO ::= "<~>"
TQUESTION ::= "?"
mppf commented 3 years ago

hi @mingodad - it's great that you figured out how to do this but it's posted here as a GitHub issue which normally means there's some further step that is needed?

Is this informational or is there some next step you are asking for help with?

mingodad commented 3 years ago

It's informational, possible further steps would be to add missing tokens definitions for completeness.

INTLITERAL
REALLITERAL
IMAGLITERAL
CSTRINGLITERAL
COMMENTS
mppf commented 3 years ago

@mingodad - alright. If it's informational then I think it'd make sense to close the issue (to indicate it's not something that needs further work from the project). It will remain available to find when searching issues etc. Thanks.

mingodad commented 3 years ago

I think that adding it to the documentation could help new users have a global view of the language.

mppf commented 3 years ago

Are you asking to have the graphical grammar / railroad diagram added to the documentation, or are you asking that the instructions to create it be added?

If you are hoping that the graphical grammar be added to the documentation -- I'm not sure how big the graphical grammar representation is but we'd need it to be some kind of image to include it in the documentation. Another concern would be updating these images when the grammar changes (supposing that it is a manual process). Would you be able to produce and share an image / images in order to facilitate discussion? You could add it to a github gist for now, for example.

mingodad commented 3 years ago

On the https://www.bottlecaps.de/rr/ui there is a button to export it as self contained xhtml in fact what we are seeing there is the generated xhtml in a frame.

We can have the graphical grammar with basically no manual work if we left the Tokens definition out.

There is ways to automate with sed scripts (or perl, python, ...). But Normally the grammar doesn't change drastically frequently.

mppf commented 3 years ago

Ah, I've tried pasting it in that website and it looks like a reasonable improvement over just the grammar listings. I'm curious what others think though. I'll paste a screen shot to enable discussion.

Screen Shot 2021-07-12 at 10 34 21 AM

bradcray commented 3 years ago

I agree that this looks like it could be an attractive addition to (or possible replacement for?) our current syntax summary at https://chapel-lang.org/docs/language/spec/syntax.html. I think we'd need this to be auto-generated on each build of the spec/docs, though, not something that requires a developer to be in the loop for (or it'd definitely fall out of date quickly).

mppf commented 3 years ago

Looks like the railroad diagram generator is open source, written in Java, and Apache 2 licensed.

I think the next step on this issue would be to create some scripts to generate the railroad diagrams and integrate these into our rendered language specification. Ideally make docs would do everything needed here (including possibly downloading the dependency).

mingodad commented 3 years ago

Also I did a script to replace positional references by named references see bellow applying it to chaperl.ypp:

program:
    toplevel_stmt_ls    { yyblock = $program; }
;

toplevel_stmt_ls:
        { $toplevel_stmt_ls = new BlockStmt(); resetTempID(); }
    | toplevel_stmt_ls[rhs_1] toplevel_stmt { $rhs_1->appendChapelStmt($toplevel_stmt); context->generatedStmt = $rhs_1; resetTempID(); }
;

toplevel_stmt:
    stmt
|  pragma_ls stmt   { $toplevel_stmt = buildPragmaStmt( $pragma_ls, $stmt ); }
;

pragma_ls:
    TPRAGMA STRINGLITERAL   { $pragma_ls = new Vec<const char*>(); $pragma_ls->add(astr($STRINGLITERAL)); }
    | pragma_ls[rhs_1] TPRAGMA STRINGLITERAL    { $rhs_1->add(astr($STRINGLITERAL)); }
;

stmt:
    module_decl_stmt
| include_module_stmt
| block_stmt
| use_stmt
| import_stmt
| require_stmt
| class_level_stmt
| assignment_stmt
| extern_block_stmt
| if_stmt
| implements_stmt
| interface_stmt
| loop_stmt
| select_stmt
| defer_stmt
| try_stmt
| throw_stmt
| return_stmt
| stmt_level_expr TSEMI { $stmt = buildChapelStmt($stmt_level_expr); }
    | TATOMIC stmt[rhs_1]   { $$ /* stmt */ = buildAtomicStmt($rhs_1); }
    | TBEGIN opt_task_intent_ls stmt[rhs_1] { $$ /* stmt */ = buildBeginStmt($opt_task_intent_ls, $rhs_1); }
    | TBREAK opt_label_ident TSEMI  { $stmt = buildGotoStmt(GOTO_BREAK, $opt_label_ident); }
    | TCOBEGIN opt_task_intent_ls block_stmt    { $stmt = buildCobeginStmt($opt_task_intent_ls, $block_stmt);  }
    | TCONTINUE opt_label_ident TSEMI   { $stmt = buildGotoStmt(GOTO_CONTINUE, $opt_label_ident); }
    | TDELETE simple_expr_ls TSEMI  { $stmt = buildDeleteStmt($simple_expr_ls); }
    | TLABEL ident_def stmt[rhs_1]  { $$ /* stmt */ = buildLabelStmt($ident_def, $rhs_1); }
    | TLOCAL expr do_stmt   { $stmt = buildLocalStmt($expr, $do_stmt); }
    | TLOCAL do_stmt    { $stmt = buildLocalStmt($do_stmt); }
    | TON expr do_stmt  { $stmt = buildOnStmt($expr, $do_stmt); }
    | TSERIAL expr do_stmt  { $stmt = buildSerialStmt($expr, $do_stmt); }
    | TSERIAL do_stmt   { $stmt = buildSerialStmt(new SymExpr(gTrue), $do_stmt); }
    | TSYNC stmt[rhs_1] { $$ /* stmt */ = buildSyncStmt($rhs_1); }
    | TYIELD expr TSEMI { $stmt = buildPrimitiveStmt(PRIM_YIELD, $expr); }
    | error TSEMI   { $stmt = buildErrorStandin(); }
;

module_decl_start:
    access_control opt_prototype TMODULE ident_def  {
      $module_decl_start = buildModule($ident_def, currentModuleType, NULL, yyfilename, $access_control, $opt_prototype, @access_control.comment);
      // store previous module name in order to restore it once we're
      // done with this module in module_decl_stmt below.  Ultimately,
      // we will need to store a stack of module names in order to
      // support full module path resolution of -s config flags.
      @$.prevModule = currentModuleName;
      currentModuleName = $ident_def;
    }
;

module_decl_stmt:
    module_decl_start TLCBR TRCBR   { $module_decl_start->block = new BlockStmt();
      $module_decl_stmt = buildChapelStmt(new DefExpr($module_decl_start));
      currentModuleName = @module_decl_start.prevModule;  // restore previous module name
    }
    | module_decl_start TLCBR stmt_ls TRCBR { $module_decl_start->block = $stmt_ls;
      $module_decl_stmt = buildChapelStmt(new DefExpr($module_decl_start));
      currentModuleName = @module_decl_start.prevModule;  // restore previous module name
    }
    | module_decl_start TLCBR error TRCBR   { $module_decl_start->block = buildErrorStandin();
      $module_decl_stmt = buildChapelStmt(new DefExpr($module_decl_start));
      currentModuleName = @module_decl_start.prevModule;  // restore previous module name
    }
;

access_control:
        { $access_control = false; @$.comment = context->latestComment; context->latestComment = NULL; }
    // public
| TPUBLIC   { $access_control = false; @$.comment = context->latestComment; context->latestComment = NULL; }
    // also public
| TPRIVATE  { $access_control = true; @$.comment = context->latestComment; context->latestComment = NULL; } // private
;

opt_prototype:
        { $opt_prototype = false; }
    | TPROTOTYPE    { $opt_prototype = true;  }
;

include_access_control:
        { $include_access_control = false; }
    | TPUBLIC   { $include_access_control = false; }
    | TPRIVATE  { $include_access_control = true; }
;

include_module_stmt:
    TINCLUDE    {
    @TINCLUDE.comment = context->latestComment;
    context->latestComment = NULL;
  }
    include_access_control opt_prototype TMODULE ident_def TSEMI    {
   $include_module_stmt = buildIncludeModule($ident_def, $include_access_control, $opt_prototype, @TINCLUDE.comment);
 }
;

block_stmt:
    TLCBR         TRCBR { $block_stmt = new BlockStmt(); }
    | TLCBR stmt_ls TRCBR   { $block_stmt = $stmt_ls;              }
    | TLCBR error   TRCBR   { $block_stmt = buildErrorStandin(); }
;

stmt_ls:
    toplevel_stmt   { $stmt_ls = new BlockStmt(); $stmt_ls->appendChapelStmt($toplevel_stmt); }
    | stmt_ls[rhs_1] toplevel_stmt  { $rhs_1->appendChapelStmt($toplevel_stmt); }
;

renames_ls:
    expr    { $renames_ls = new std::vector<PotentialRename*>();
                                         PotentialRename* cur = new PotentialRename();
                                         cur->tag = PotentialRename::SINGLE;
                                         cur->elem = $expr;
                                         $renames_ls->push_back(cur); }
    | expr TAS expr { $renames_ls = new std::vector<PotentialRename*>();
                                         PotentialRename* cur = new PotentialRename();
                                         cur->tag = PotentialRename::DOUBLE;
                                         cur->renamed = new std::pair<Expr*, Expr*>($1 /* expr_1 */, $3 /* expr_3 */);
                                         $renames_ls->push_back(cur); }
    | renames_ls[rhs_1] TCOMMA expr { PotentialRename* cur = new PotentialRename();
                                         cur->tag = PotentialRename::SINGLE;
                                         cur->elem = $expr;
                                         $rhs_1->push_back(cur); }
    | renames_ls[rhs_1] TCOMMA expr TAS expr    { PotentialRename* cur = new PotentialRename();
                                         cur->tag = PotentialRename::DOUBLE;
                                         cur->renamed = new std::pair<Expr*, Expr*>($3 /* expr_3 */, $5 /* expr_5 */);
                                         $rhs_1->push_back(cur); }
;

use_renames_ls:
    expr    { $use_renames_ls = new std::vector<PotentialRename*>();
                                         PotentialRename* cur = new PotentialRename();
                                         cur->tag = PotentialRename::SINGLE;
                                         cur->elem = $expr;
                                         $use_renames_ls->push_back(cur); }
    | expr TAS expr { $use_renames_ls = new std::vector<PotentialRename*>();
                                         PotentialRename* cur = new PotentialRename();
                                         cur->tag = PotentialRename::DOUBLE;
                                         cur->renamed = new std::pair<Expr*, Expr*>($1 /* expr_1 */, $3 /* expr_3 */);
                                         $use_renames_ls->push_back(cur); }
    | expr TAS TUNDERSCORE  { $use_renames_ls = new std::vector<PotentialRename*>();
                                         PotentialRename* cur = new PotentialRename();
                                         cur->tag = PotentialRename::DOUBLE;
                                         cur->renamed = new std::pair<Expr*, Expr*>($expr, new UnresolvedSymExpr("_"));
                                         $use_renames_ls->push_back(cur); }
    | use_renames_ls[rhs_1] TCOMMA expr { PotentialRename* cur = new PotentialRename();
                                         cur->tag = PotentialRename::SINGLE;
                                         cur->elem = $expr;
                                         $rhs_1->push_back(cur); }
    | use_renames_ls[rhs_1] TCOMMA expr TAS expr    { PotentialRename* cur = new PotentialRename();
                                         cur->tag = PotentialRename::DOUBLE;
                                         cur->renamed = new std::pair<Expr*, Expr*>($3 /* expr_3 */, $5 /* expr_5 */);
                                         $rhs_1->push_back(cur); }
    | use_renames_ls[rhs_1] TCOMMA expr TAS TUNDERSCORE { PotentialRename* cur = new PotentialRename();
                                         cur->tag = PotentialRename::DOUBLE;
                                         cur->renamed = new std::pair<Expr*, Expr*>($expr, new UnresolvedSymExpr("_"));
                                         $rhs_1->push_back(cur); }
;

opt_only_ls:
    /* nothing */   { $opt_only_ls = new std::vector<PotentialRename*>();
                                         PotentialRename* cur = new PotentialRename();
                                         cur->tag = PotentialRename::SINGLE;
                                         cur->elem = new UnresolvedSymExpr("");
                                         $opt_only_ls->push_back(cur); }
| renames_ls
;

except_ls:
    TSTAR   { $except_ls = new std::vector<PotentialRename*>();
                                         PotentialRename* cur = new PotentialRename();
                                         cur->tag = PotentialRename::SINGLE;
                                         cur->elem = new UnresolvedSymExpr("");
                                         $except_ls->push_back(cur); }
| renames_ls
;

use_access_control:
        { $use_access_control = true; }
    // private
| TPUBLIC   { $use_access_control = false; }
    // public
| TPRIVATE  { $use_access_control = true; } // private
;

use_stmt:
    use_access_control TUSE use_renames_ls TSEMI    { $use_stmt = buildUseStmt($use_renames_ls, $use_access_control); }
    | use_access_control TUSE expr TEXCEPT except_ls TSEMI  { $use_stmt = buildUseStmt($expr, "", $except_ls, true, $use_access_control); }
    | use_access_control TUSE expr TAS expr TEXCEPT except_ls TSEMI { $use_stmt = buildUseStmt($3 /* expr_3 */, $5 /* expr_5 */, $except_ls, true, $use_access_control); }
    | use_access_control TUSE expr TAS TUNDERSCORE TEXCEPT except_ls TSEMI  { $use_stmt = buildUseStmt($expr, new UnresolvedSymExpr("_"), $except_ls, true, $use_access_control); }
    | use_access_control TUSE expr TONLY opt_only_ls TSEMI  { $use_stmt = buildUseStmt($expr, "", $opt_only_ls, false, $use_access_control); }
    | use_access_control TUSE expr TAS expr TONLY opt_only_ls TSEMI { $use_stmt = buildUseStmt($3 /* expr_3 */, $5 /* expr_5 */, $opt_only_ls, false, $use_access_control); }
    | use_access_control TUSE expr TAS TUNDERSCORE TONLY opt_only_ls TSEMI  { $use_stmt = buildUseStmt($expr, new UnresolvedSymExpr("_"), $opt_only_ls, false, $use_access_control); }
;

import_stmt:
    use_access_control TIMPORT import_ls TSEMI  { $import_stmt = $import_ls;
                                               setImportPrivacy($import_stmt, $use_access_control);}
;

import_expr:
    expr    { $import_expr = buildImportStmt($expr); }
    | expr TAS ident_use    { $import_expr = buildImportStmt($expr, $ident_use); }
    | expr TDOT TLCBR renames_ls TRCBR  { $import_expr = buildImportStmt($expr, $renames_ls); }
;

import_ls:
    import_expr { $import_ls = buildChapelStmt($import_expr); }
    | import_ls[rhs_1] TCOMMA import_expr   { $$ /* import_ls */ = $rhs_1; $$ /* import_ls */->insertAtTail($import_expr); }
;

require_stmt:
    TREQUIRE expr_ls TSEMI  { $require_stmt = buildRequireStmt($expr_ls); }
;

assignment_stmt:
    lhs_expr assignop_ident opt_try_expr TSEMI  { $assignment_stmt = buildAssignment($lhs_expr, $opt_try_expr, $assignop_ident);   }
    | lhs_expr TSWAP           opt_try_expr TSEMI   { $assignment_stmt = buildAssignment($lhs_expr, $opt_try_expr, "<=>"); }
    | lhs_expr TASSIGNREDUCE   opt_try_expr TSEMI   { $assignment_stmt = buildAssignment($lhs_expr, $opt_try_expr, PRIM_REDUCE_ASSIGN); }
    | lhs_expr TASSIGNLAND     opt_try_expr TSEMI   { $assignment_stmt = buildLAndAssignment($lhs_expr, $opt_try_expr);    }
    | lhs_expr TASSIGNLOR      opt_try_expr TSEMI   { $assignment_stmt = buildLOrAssignment($lhs_expr, $opt_try_expr);     }
    | lhs_expr TASSIGN         TNOINIT TSEMI    { $assignment_stmt = buildAssignment($lhs_expr, new SymExpr(gNoInit), "="); }
;

opt_label_ident:
        { $opt_label_ident = NULL; }
    | TIDENT    { $opt_label_ident = $TIDENT; }
;

ident_fn_def:
    TIDENT  { $ident_fn_def = $TIDENT; }
    | TNONE { $ident_fn_def = "none"; redefiningReservedWordError($ident_fn_def); }
    | TTHIS { $ident_fn_def = "this"; }
    | TFALSE    { $ident_fn_def = "false"; redefiningReservedWordError($ident_fn_def); }
    | TTRUE { $ident_fn_def = "true"; redefiningReservedWordError($ident_fn_def); }
    | internal_type_ident_def   { $ident_fn_def = $internal_type_ident_def; redefiningReservedTypeError($internal_type_ident_def); }
;

ident_def:
    TIDENT  { $ident_def = $TIDENT; }
    | TNONE { $ident_def = "none"; redefiningReservedWordError($ident_def); }
    | TTHIS { $ident_def = "this"; redefiningReservedWordError($ident_def); }
    | TFALSE    { $ident_def = "false"; redefiningReservedWordError($ident_def); }
    | TTRUE { $ident_def = "true"; redefiningReservedWordError($ident_def); }
    | internal_type_ident_def   { $ident_def = $internal_type_ident_def; redefiningReservedTypeError($internal_type_ident_def); }
;

ident_use:
    TIDENT  { $ident_use = $TIDENT; }
    | TTHIS { $ident_use = "this"; }
;

internal_type_ident_def:
    /* These reserved words should generate an error if an attempt
    is made to redefine them. The name returned from this nonterminal
    will be used in the error message.

    Uses of these types are parsed differently.
    See scalar_type and reserved_type_ident_use.
  */
  TBOOL { $internal_type_ident_def = "bool"; }
    | TINT  { $internal_type_ident_def = "int"; }
    | TUINT { $internal_type_ident_def = "uint"; }
    | TREAL { $internal_type_ident_def = "real"; }
    | TIMAG { $internal_type_ident_def = "imag"; }
    | TCOMPLEX  { $internal_type_ident_def = "complex"; }
    | TBYTES    { $internal_type_ident_def = "bytes"; }
    | TSTRING   { $internal_type_ident_def = "string"; }
    | TSYNC { $internal_type_ident_def = "sync"; }
    | TSINGLE   { $internal_type_ident_def = "single"; }
    | TOWNED    { $internal_type_ident_def = "owned"; }
    | TSHARED   { $internal_type_ident_def = "shared"; }
    | TBORROWED { $internal_type_ident_def = "borrowed"; }
    | TUNMANAGED    { $internal_type_ident_def = "unmanaged"; }
    | TDOMAIN   { $internal_type_ident_def = "domain"; }
    | TINDEX    { $internal_type_ident_def = "index"; }
    | TLOCALE   { $internal_type_ident_def = "locale"; }
    | TNOTHING  { $internal_type_ident_def = "nothing"; }
    | TVOID { $internal_type_ident_def = "void"; }
;

scalar_type:
    TBOOL   { $scalar_type = new SymExpr(dtBools[BOOL_SIZE_DEFAULT]->symbol); }
    | TENUM { $scalar_type = new SymExpr(dtAnyEnumerated->symbol); }
    | TINT  { $scalar_type = new SymExpr(dtInt[INT_SIZE_DEFAULT]->symbol); }
    | TUINT { $scalar_type = new SymExpr(dtUInt[INT_SIZE_DEFAULT]->symbol); }
    | TREAL { $scalar_type = new SymExpr(dtReal[FLOAT_SIZE_DEFAULT]->symbol); }
    | TIMAG { $scalar_type = new SymExpr(dtImag[FLOAT_SIZE_DEFAULT]->symbol); }
    | TCOMPLEX  { $scalar_type = new SymExpr(dtComplex[COMPLEX_SIZE_DEFAULT]->symbol); }
    | TBYTES    { $scalar_type = new SymExpr(dtBytes->symbol); }
    | TSTRING   { $scalar_type = new SymExpr(dtString->symbol); }
    | TLOCALE   { $scalar_type = new SymExpr(dtLocale->symbol); }
    | TNOTHING  { $scalar_type = new SymExpr(dtNothing->symbol); }
    | TVOID { $scalar_type = new SymExpr(dtVoid->symbol); }
;

reserved_type_ident_use:
    /* These reserved words can also be used as types but in fewer
     places in the parser. Additionally their type versions have
     different names. */
  TSYNC { $reserved_type_ident_use = "_syncvar"; }
    | TSINGLE   { $reserved_type_ident_use = "_singlevar"; }
    | TDOMAIN   { $reserved_type_ident_use = "_domain"; }
    | TINDEX    { $reserved_type_ident_use = "_index"; }
;

do_stmt:
    TDO stmt    { $do_stmt = $stmt; }
    | block_stmt    { $do_stmt = $block_stmt; }
;

return_stmt:
    TRETURN TSEMI   { $return_stmt = buildPrimitiveStmt(PRIM_RETURN); }
    | TRETURN opt_try_expr TSEMI    { $return_stmt = buildPrimitiveStmt(PRIM_RETURN, $opt_try_expr); }
;

class_level_stmt:
    TSEMI   { $class_level_stmt = buildChapelStmt(new BlockStmt()); }
    | private_decl
| TPUBLIC private_decl  { $class_level_stmt = $private_decl; }
    /* the following rule saves the current state of `parsingPrivate`,
   then sets it to true when parsing the `private_decl` rule; it then
   restores the original value before completing.  Note that this is
   not sufficient to reason about nestings of public and private
   declarations, but that the current use of `parsingPrivate` (to
   distinguish private configs) does not require that.  For such
   cases, we'd need to do similar save/set-to-false/restore actions in
   the public rules above, but doing this in the most straightforward
   way results in conflicts. */
| TPRIVATE  { $<b>$ = parsingPrivate; parsingPrivate=true;}
    private_decl    { parsingPrivate=$<b>2; applyPrivateToBlock($private_decl); $class_level_stmt = $private_decl; }
;

private_decl:
  fn_decl_stmt
| var_decl_stmt
| enum_decl_stmt
| type_alias_decl_stmt
| class_decl_stmt
| forwarding_stmt
| extern_export_decl_stmt
;

forwarding_stmt:
    TFORWARDING expr TSEMI  { $forwarding_stmt = buildForwardingStmt($expr); }
    | TFORWARDING expr TEXCEPT except_ls TSEMI  { $forwarding_stmt = buildForwardingStmt($expr, $except_ls, true); }
    | TFORWARDING expr TONLY opt_only_ls TSEMI  { $forwarding_stmt = buildForwardingStmt($expr, $opt_only_ls, false); }
    | TFORWARDING var_decl_stmt { $forwarding_stmt = buildForwardingDeclStmt($var_decl_stmt); }
;

extern_export_decl_stmt:
    TEXTERN TRECORD {
      @TRECORD.comment = context->latestComment;
      context->latestComment = NULL;
    }
    ident_def opt_inherit TLCBR class_level_stmt_ls TRCBR   {
      $extern_export_decl_stmt = buildChapelStmt(buildClassDefExpr($ident_def,
                                             NULL,
                                             AGGREGATE_RECORD,
                                             $opt_inherit,
                                             $class_level_stmt_ls,
                                             FLAG_EXTERN,
                                             @TRECORD.comment));
    }
    | TEXTERN STRINGLITERAL TRECORD {
      @TRECORD.comment = context->latestComment;
      context->latestComment = NULL;
    }
    ident_def opt_inherit TLCBR class_level_stmt_ls TRCBR   {

      $extern_export_decl_stmt = buildChapelStmt(buildClassDefExpr($ident_def,
                                             $STRINGLITERAL,
                                             AGGREGATE_RECORD,
                                             $opt_inherit,
                                             $class_level_stmt_ls,
                                             FLAG_EXTERN,
                                             @TRECORD.comment));
    }
    | TEXPORT TRECORD   {
      @TRECORD.comment = context->latestComment;
      context->latestComment = NULL;
    }
    ident_def opt_inherit TLCBR class_level_stmt_ls TRCBR   {
      $extern_export_decl_stmt = buildChapelStmt(buildClassDefExpr($ident_def,
                                             NULL,
                                             AGGREGATE_RECORD,
                                             $opt_inherit,
                                             $class_level_stmt_ls,
                                             FLAG_EXPORT,
                                             @TRECORD.comment));
    }
    | TEXPORT STRINGLITERAL TRECORD {
      @TRECORD.comment = context->latestComment;
      context->latestComment = NULL;
    }
    ident_def opt_inherit TLCBR class_level_stmt_ls TRCBR   {
      $extern_export_decl_stmt = buildChapelStmt(buildClassDefExpr($ident_def,
                                             $STRINGLITERAL,
                                             AGGREGATE_RECORD,
                                             $opt_inherit,
                                             $class_level_stmt_ls,
                                             FLAG_EXPORT,
                                             @TRECORD.comment));
    }
    | TEXTERN opt_expr fn_decl_stmt {
      $extern_export_decl_stmt = buildExternExportFunctionDecl(FLAG_EXTERN, $opt_expr, $fn_decl_stmt);
    }
    | TEXPORT opt_expr fn_decl_stmt {
      $extern_export_decl_stmt = buildExternExportFunctionDecl(FLAG_EXPORT, $opt_expr, $fn_decl_stmt);
    }
    | TEXTERN opt_expr var_decl_type var_decl_stmt_inner_ls TSEMI   {
      const char* comment = context->latestComment;
      context->latestComment = NULL;

      $var_decl_type->insert(FLAG_EXTERN);
      $extern_export_decl_stmt = buildVarDecls($var_decl_stmt_inner_ls, comment, $var_decl_type, $opt_expr);
    }
    | TEXPORT opt_expr var_decl_type var_decl_stmt_inner_ls TSEMI   {
      const char* comment = context->latestComment;
      context->latestComment = NULL;

      $var_decl_type->insert(FLAG_EXPORT);
      $extern_export_decl_stmt = buildVarDecls($var_decl_stmt_inner_ls, comment, $var_decl_type, $opt_expr);
    }
;

extern_block_stmt:
    TEXTERN EXTERNCODE  {
      $extern_block_stmt = buildExternBlockStmt(astr($EXTERNCODE));
    }
;

loop_stmt:
    TDO stmt TWHILE expr TSEMI  { $loop_stmt = DoWhileStmt::build($expr, $stmt); }
    | TWHILE expr do_stmt   { $loop_stmt = WhileDoStmt::build($expr, $do_stmt); }
    | TWHILE ifvar do_stmt  { $loop_stmt = WhileDoStmt::build($ifvar, $do_stmt); }
    | TCOFORALL expr TIN expr opt_task_intent_ls do_stmt    { $loop_stmt = buildCoforallLoopStmt($2 /* expr_2 */, $4 /* expr_4 */, $opt_task_intent_ls, $do_stmt);       }
    | TCOFORALL expr TIN zippered_iterator opt_task_intent_ls do_stmt   { $loop_stmt = buildCoforallLoopStmt($expr, $zippered_iterator, $opt_task_intent_ls, $do_stmt, true); }
    | TCOFORALL expr opt_task_intent_ls do_stmt { $loop_stmt = buildCoforallLoopStmt(NULL, $expr, $opt_task_intent_ls, $do_stmt);     }
    | TFOR expr TIN expr do_stmt    { $loop_stmt = ForLoop::buildForLoop(  $2 /* expr_2 */, $4 /* expr_4 */, $do_stmt, false, false); }
    | TFOR expr TIN zippered_iterator do_stmt   { $loop_stmt = ForLoop::buildForLoop(  $expr, $zippered_iterator, $do_stmt, true, false); }
    | TFOR expr do_stmt { $loop_stmt = ForLoop::buildForLoop(NULL, $expr, $do_stmt, false, false); }
    | TFOR zippered_iterator do_stmt    { $loop_stmt = ForLoop::buildForLoop(NULL, $zippered_iterator, $do_stmt, true, false); }
    | TFOR TPARAM ident_def TIN expr do_stmt    { $loop_stmt = buildParamForLoopStmt($ident_def, $expr, $do_stmt); }
    | TFORALL expr TIN expr                                   do_stmt   { $loop_stmt = ForallStmt::build($2 /* expr_2 */,   $4 /* expr_4 */, NULL, $do_stmt, false, false); }
    | TFORALL expr TIN expr              forall_intent_clause do_stmt   { $loop_stmt = ForallStmt::build($2 /* expr_2 */,   $4 /* expr_4 */, $forall_intent_clause,   $do_stmt, false, false); }
    | TFORALL expr TIN zippered_iterator                      do_stmt   { $loop_stmt = ForallStmt::build($expr,   $zippered_iterator, NULL, $do_stmt, true,  false); }
    | TFORALL expr TIN zippered_iterator forall_intent_clause do_stmt   { $loop_stmt = ForallStmt::build($expr,   $zippered_iterator, $forall_intent_clause,   $do_stmt, true,  false); }
    | TFORALL          expr                                   do_stmt   { $loop_stmt = ForallStmt::build(NULL, $expr, NULL, $do_stmt, false, false); }
    | TFORALL          expr              forall_intent_clause do_stmt   { $loop_stmt = ForallStmt::build(NULL, $expr, $forall_intent_clause,   $do_stmt, false, false); }
    | TFORALL          zippered_iterator                      do_stmt   { $loop_stmt = ForallStmt::build(NULL, $zippered_iterator, NULL, $do_stmt, true,  false); }
    | TFORALL          zippered_iterator forall_intent_clause do_stmt   { $loop_stmt = ForallStmt::build(NULL, $zippered_iterator, $forall_intent_clause,   $do_stmt, true,  false); }
    | TFOREACH expr TIN expr                                   do_stmt  { $loop_stmt = foreachNotImplementedError(); }
    | TFOREACH expr TIN expr              forall_intent_clause do_stmt  { $loop_stmt = foreachNotImplementedError(); }
    | TFOREACH expr TIN zippered_iterator                      do_stmt  { $loop_stmt = foreachNotImplementedError(); }
    | TFOREACH expr TIN zippered_iterator forall_intent_clause do_stmt  { $loop_stmt = foreachNotImplementedError(); }
    | TFOREACH          expr                                   do_stmt  { $loop_stmt = foreachNotImplementedError(); }
    | TFOREACH          expr              forall_intent_clause do_stmt  { $loop_stmt = foreachNotImplementedError(); }
    | TFOREACH          zippered_iterator                      do_stmt  { $loop_stmt = foreachNotImplementedError(); }
    | TFOREACH          zippered_iterator forall_intent_clause do_stmt  { $loop_stmt = foreachNotImplementedError(); }
    | TLSBR expr_ls TIN expr TRSBR stmt {
      if ($expr_ls->argList.length != 1)
        USR_FATAL($expr, "invalid index expression");
      $loop_stmt = ForallStmt::build($expr_ls->get(1)->remove(), $expr, NULL, new BlockStmt($stmt), false, true);
    }
    | TLSBR expr_ls TIN expr forall_intent_clause TRSBR stmt    {
      if ($expr_ls->argList.length != 1)
        USR_FATAL($expr, "invalid index expression");
      $loop_stmt = ForallStmt::build($expr_ls->get(1)->remove(), $expr, $forall_intent_clause,   new BlockStmt($stmt), false, true);
    }
    | TLSBR expr_ls TIN zippered_iterator TRSBR stmt    {
      if ($expr_ls->argList.length != 1)
        USR_FATAL($zippered_iterator, "invalid index expression");
      $loop_stmt = ForallStmt::build($expr_ls->get(1)->remove(), $zippered_iterator, NULL, new BlockStmt($stmt), true,  true);
    }
    | TLSBR expr_ls TIN zippered_iterator forall_intent_clause TRSBR stmt   {
      if ($expr_ls->argList.length != 1)
        USR_FATAL($zippered_iterator, "invalid index expression");
      $loop_stmt = ForallStmt::build($expr_ls->get(1)->remove(), $zippered_iterator, $forall_intent_clause,   new BlockStmt($stmt), true,  true);
    }
    | TLSBR expr_ls TRSBR stmt  {
      if ($expr_ls->argList.length > 1)
        $loop_stmt = ForallStmt::build(NULL, new CallExpr("chpl__ensureDomainExpr", $expr_ls), NULL, new BlockStmt($stmt), false, true);
      else
        $loop_stmt = ForallStmt::build(NULL, $expr_ls->get(1)->remove(),                       NULL, new BlockStmt($stmt), false, true);
    }
    | TLSBR expr_ls forall_intent_clause TRSBR stmt {
      if ($expr_ls->argList.length > 1)
        $loop_stmt = ForallStmt::build(NULL, new CallExpr("chpl__ensureDomainExpr", $expr_ls), $forall_intent_clause, new BlockStmt($stmt), false, true);
      else
        $loop_stmt = ForallStmt::build(NULL, $expr_ls->get(1)->remove(),                       $forall_intent_clause, new BlockStmt($stmt), false, true);
    }
    | TLSBR zippered_iterator TRSBR stmt    {
      $loop_stmt = ForallStmt::build(NULL, $zippered_iterator, NULL, new BlockStmt($stmt), true,  true);
    }
    | TLSBR zippered_iterator forall_intent_clause TRSBR stmt   {
      $loop_stmt = ForallStmt::build(NULL, $zippered_iterator, $forall_intent_clause,   new BlockStmt($stmt), true,  true);
    }
;

zippered_iterator:
    TZIP TLP expr_ls TRP    { $zippered_iterator = new CallExpr(PRIM_ZIP, $expr_ls); }
;

if_stmt:
    TIF expr TTHEN stmt %prec TNOELSE   { $if_stmt = buildIfStmt($expr, $stmt); }
    | TIF expr block_stmt %prec TNOELSE { $if_stmt = buildIfStmt($expr, $block_stmt); }
    | TIF expr TTHEN stmt TELSE stmt    { $if_stmt = buildIfStmt($expr, $4 /* stmt_4 */, $6 /* stmt_6 */); }
    | TIF expr block_stmt TELSE stmt    { $if_stmt = buildIfStmt($expr, $block_stmt, $stmt); }
    | TIF ifvar TTHEN stmt %prec TNOELSE    { $if_stmt = buildIfStmt($ifvar, $stmt); }
    | TIF ifvar block_stmt %prec TNOELSE    { $if_stmt = buildIfStmt($ifvar, $block_stmt); }
    | TIF ifvar TTHEN stmt TELSE stmt   { $if_stmt = buildIfStmt($ifvar, $4 /* stmt_4 */, $6 /* stmt_6 */); }
    | TIF ifvar block_stmt TELSE stmt   { $if_stmt = buildIfStmt($ifvar, $block_stmt, $stmt); }
    | TIF expr assignop_ident expr TTHEN stmt %prec TNOELSE {
$if_stmt = buildIfStmt(convertAssignmentAndWarn($2 /* expr_2 */,$assignop_ident,$4 /* expr_4 */), $stmt); }
    | TIF expr assignop_ident expr block_stmt %prec TNOELSE {
$if_stmt = buildIfStmt(convertAssignmentAndWarn($2 /* expr_2 */,$assignop_ident,$4 /* expr_4 */), $block_stmt); }
    | TIF expr assignop_ident expr TTHEN stmt TELSE stmt    {
$if_stmt = buildIfStmt(convertAssignmentAndWarn($2 /* expr_2 */,$assignop_ident,$4 /* expr_4 */), $6 /* stmt_6 */, $8 /* stmt_8 */); }
    | TIF expr assignop_ident expr block_stmt TELSE stmt    {
$if_stmt = buildIfStmt(convertAssignmentAndWarn($2 /* expr_2 */,$assignop_ident,$4 /* expr_4 */), $block_stmt, $stmt); }
;

ifvar:
    TVAR   ident_def TASSIGN expr   { $ifvar = buildIfVar($ident_def, $expr, false); }
    | TCONST ident_def TASSIGN expr { $ifvar = buildIfVar($ident_def, $expr, true);  }
;

interface_stmt:
    TINTERFACE ident_def TLP ifc_formal_ls TRP block_stmt   { $interface_stmt = buildChapelStmt(InterfaceSymbol::buildDef($ident_def, $ifc_formal_ls, $block_stmt)); }
    | TINTERFACE ident_def                       block_stmt { // mimick ifc_formal_ls for a single formal "Self"
    DefExpr*  formal = InterfaceSymbol::buildFormal("Self", INTENT_TYPE);
    CallExpr* ls     = new CallExpr(PRIM_ACTUALS_LIST, formal);
    $interface_stmt = buildChapelStmt(InterfaceSymbol::buildDef($ident_def, ls, $block_stmt)); }
;

ifc_formal_ls:
    ifc_formal  { $ifc_formal_ls = new CallExpr(PRIM_ACTUALS_LIST, $ifc_formal); }
    | ifc_formal_ls[rhs_1] TCOMMA ifc_formal    { $rhs_1->insertAtTail($ifc_formal); }
;

ifc_formal:
    // implicitly 'type' intent, could specify explicitly - see #16966
  ident_def { $ifc_formal = InterfaceSymbol::buildFormal($//, INTENT_TYPE); }
;

implements_type_ident:
    TIDENT  { $implements_type_ident = $TIDENT; }
    | TBOOL { $implements_type_ident = "bool"; }
    | TINT  { $implements_type_ident = "int"; }
    | TUINT { $implements_type_ident = "uint"; }
    | TREAL { $implements_type_ident = "real"; }
    | TIMAG { $implements_type_ident = "imag"; }
    | TCOMPLEX  { $implements_type_ident = "complex"; }
    | TBYTES    { $implements_type_ident = "bytes"; }
    | TSTRING   { $implements_type_ident = "string"; }
    | TLOCALE   { $implements_type_ident = "locale"; }
    | TNOTHING  { $implements_type_ident = "nothing"; }
    | TVOID { $implements_type_ident = "void"; }
    | implements_type_error_ident   { $implements_type_ident = $implements_type_error_ident;
    USR_FATAL_CONT("'%s' is not allowed to \"implement\" an interface", $implements_type_error_ident); }
;

implements_type_error_ident:
    TNONE   { $implements_type_error_ident = "none"; }
    | TTHIS { $implements_type_error_ident = "this"; }
    | TFALSE    { $implements_type_error_ident = "false"; }
    | TTRUE { $implements_type_error_ident = "true"; }
    /* it would be nice to include these, alas they cause shift/reduce conflicts:
| TSYNC      { $$ = "sync"; }
| TSINGLE    { $$ = "single"; }
| TOWNED     { $$ = "owned"; }
| TSHARED    { $$ = "shared"; }
| TBORROWED  { $$ = "borrowed"; }
| TUNMANAGED { $$ = "unmanaged"; }
*/
| TDOMAIN   { $implements_type_error_ident = "domain"; }
    | TINDEX    { $implements_type_error_ident = "index"; }
;

implements_stmt:
    TIMPLEMENTS ident_def TLP actual_ls TRP TSEMI   { $implements_stmt = buildChapelStmt(ImplementsStmt::build($ident_def, $actual_ls, NULL)); }
    | implements_type_ident TIMPLEMENTS ident_def TSEMI { CallExpr* act = new CallExpr(PRIM_ACTUALS_LIST, new UnresolvedSymExpr($implements_type_ident));
    $implements_stmt = buildChapelStmt(ImplementsStmt::build($ident_def, act, NULL)); }
    | implements_type_ident TIMPLEMENTS ident_def TLP actual_ls TRP TSEMI   { $actual_ls->insertAtHead(new UnresolvedSymExpr($implements_type_ident));
    $implements_stmt = buildChapelStmt(ImplementsStmt::build($ident_def, $actual_ls, NULL)); }
;

ifc_constraint:
    TIMPLEMENTS ident_def TLP actual_ls TRP { $ifc_constraint = IfcConstraint::build($ident_def, $actual_ls); }
    | implements_type_ident TIMPLEMENTS ident_def   { CallExpr* act = new CallExpr(PRIM_ACTUALS_LIST, new UnresolvedSymExpr($implements_type_ident));
    $ifc_constraint = IfcConstraint::build($ident_def, act); }
    | implements_type_ident TIMPLEMENTS ident_def TLP actual_ls TRP { $actual_ls->insertAtHead(new UnresolvedSymExpr($implements_type_ident));
    $ifc_constraint = IfcConstraint::build($ident_def, $actual_ls); }
;

defer_stmt:
    TDEFER stmt { $defer_stmt = DeferStmt::build($stmt); }
;

try_stmt:
    TTRY     expr            TSEMI  { $try_stmt = TryStmt::build(false, $expr); }
    | TTRYBANG expr            TSEMI    { $try_stmt = TryStmt::build(true,  $expr); }
    | TTRY     assignment_stmt  { $try_stmt = TryStmt::build(false, $assignment_stmt); }
    | TTRYBANG assignment_stmt  { $try_stmt = TryStmt::build(true,  $assignment_stmt); }
    | TTRY     block_stmt      catch_stmt_ls    { $try_stmt = TryStmt::build(false, $block_stmt, $catch_stmt_ls); }
    | TTRYBANG block_stmt      catch_stmt_ls    { $try_stmt = TryStmt::build(true,  $block_stmt, $catch_stmt_ls); }
;

catch_stmt_ls:
        { $catch_stmt_ls = buildChapelStmt(); }
    | catch_stmt_ls[rhs_1] catch_stmt   { $rhs_1->insertAtTail($catch_stmt); }
;

catch_stmt:
    TCATCH                    block_stmt    { $catch_stmt = CatchStmt::build($block_stmt); }
    | TCATCH     catch_expr     block_stmt  { $catch_stmt = CatchStmt::build($catch_expr, $block_stmt); }
    | TCATCH TLP catch_expr TRP block_stmt  { $catch_stmt = CatchStmt::build($catch_expr, $block_stmt); }
;

catch_expr:
    ident_def   { $catch_expr = new DefExpr(new VarSymbol($ident_def), NULL, new UnresolvedSymExpr("Error")); }
    | ident_def TCOLON expr { $catch_expr = new DefExpr(new VarSymbol($ident_def), NULL, $expr);   }
;

throw_stmt:
    TTHROW expr TSEMI   { $throw_stmt = buildPrimitiveStmt(PRIM_THROW, $expr); }
;

select_stmt:
    TSELECT expr TLCBR when_stmt_ls TRCBR   { $select_stmt = buildChapelStmt(buildSelectStmt($expr, $when_stmt_ls)); }
    | TSELECT expr TLCBR error TRCBR    { $select_stmt = buildErrorStandin(); }
;

when_stmt_ls:
        { $when_stmt_ls = buildChapelStmt(); }
    | when_stmt_ls[rhs_1] when_stmt { $rhs_1->insertAtTail($when_stmt); }
;

when_stmt:
    TWHEN expr_ls do_stmt   { $when_stmt = new CondStmt(new CallExpr(PRIM_WHEN, $expr_ls), $do_stmt); }
    | TOTHERWISE stmt   { $when_stmt = new CondStmt(new CallExpr(PRIM_WHEN), $stmt); }
    | TOTHERWISE TDO stmt   { $when_stmt = new CondStmt(new CallExpr(PRIM_WHEN), $stmt); }
;

class_decl_stmt:
    class_tag ident_def opt_inherit TLCBR class_level_stmt_ls TRCBR {
      $class_decl_stmt = buildChapelStmt(buildClassDefExpr($ident_def,
                                             NULL,
                                             $class_tag,
                                             $opt_inherit,
                                             $class_level_stmt_ls,
                                             FLAG_UNKNOWN,
                                             @class_tag.comment));
    }
    | class_tag ident_def opt_inherit TLCBR error TRCBR {
      $class_decl_stmt = buildChapelStmt(buildClassDefExpr($ident_def,
                                             NULL,
                                             $class_tag,
                                             $opt_inherit,
                                             new BlockStmt(),
                                             FLAG_UNKNOWN,
                                             @class_tag.comment));
    }
  /* see also extern_decl_stmt */
;

class_tag:
    TCLASS  {
             $class_tag                     = AGGREGATE_CLASS;
             @$.comment             = context->latestComment;
             context->latestComment = NULL;
           }
    | TRECORD   {
             $class_tag                     = AGGREGATE_RECORD;
             @$.comment             = context->latestComment;
             context->latestComment = NULL;
           }
    | TUNION    {
             $class_tag                     = AGGREGATE_UNION;
             @$.comment             = context->latestComment;
             context->latestComment = NULL;
           }
;

opt_inherit:
        { $opt_inherit = NULL; }
    | TCOLON expr_ls    { $opt_inherit = $expr_ls; }
;

class_level_stmt_ls:
    /* nothing */   { $class_level_stmt_ls = new BlockStmt(); }
    | class_level_stmt_ls[rhs_1] class_level_stmt   { $rhs_1->insertAtTail($class_level_stmt); }
    | class_level_stmt_ls[rhs_1] pragma_ls class_level_stmt { $rhs_1->insertAtTail(buildPragmaStmt($pragma_ls, $class_level_stmt)); }
;

enum_decl_stmt:
    enum_header ident_def TLCBR enum_ls TRCBR   {
      EnumType* pdt = $enum_header;
      for_vector(DefExpr, ec, *$enum_ls) {
        ec->sym->type = pdt;
        pdt->constants.insertAtTail(ec);
        if (pdt->defaultValue == NULL) {
          pdt->defaultValue = ec->sym;
        }
      }
      delete $enum_ls;
      pdt->doc = @enum_header.comment;
      TypeSymbol* pst = new TypeSymbol($ident_def, pdt);
      $enum_header->symbol = pst;
      $enum_decl_stmt = buildChapelStmt(new DefExpr(pst));
    }
    | enum_header ident_def TLCBR error TRCBR   {
      $enum_decl_stmt = buildErrorStandin();
    }
;

enum_header:
    TENUM   {
      $enum_header = new EnumType();
      @$.comment = context->latestComment;
      context->latestComment = NULL;
    }
;

enum_ls:
    enum_item   {
      $enum_ls = new std::vector<DefExpr*>();
      $enum_ls->push_back($enum_item);
      //$enum_ls->doc = context->latestComment;
      // start here for enabling documentation of enum constants
      //context->latestComment = NULL;
    }
    | enum_ls[rhs_1] TCOMMA {
      $$ /* enum_ls */ = $rhs_1;
    }
    | enum_ls[rhs_1] TCOMMA enum_item   {
      $rhs_1->push_back($enum_item);
    }
;

enum_item:
    ident_def   { $enum_item = new DefExpr(new EnumSymbol($ident_def)); }
    | ident_def TASSIGN expr    { $enum_item = new DefExpr(new EnumSymbol($ident_def), $expr); }
;

lambda_decl_expr:
    TLAMBDA {
      captureTokens = 1;
      captureString.clear();
    }
    req_formal_ls   {
      captureTokens = 0;
      $req_formal_ls->userString = astr(captureString);
    }
    opt_ret_tag opt_type opt_lifetime_where function_body_stmt  {
      $req_formal_ls->retTag = $opt_ret_tag;
      if ($opt_ret_tag == RET_REF || $opt_ret_tag == RET_CONST_REF)
        USR_FATAL("'ref' return types are not allowed in lambdas");
      if ($opt_ret_tag == RET_PARAM)
        USR_FATAL("'param' return types are not allowed in lambdas");
      if ($opt_ret_tag == RET_TYPE)
        USR_FATAL("'type' return types are not allowed in lambdas");
      if ($opt_type)
        $req_formal_ls->retExprType = new BlockStmt($opt_type, BLOCK_SCOPELESS);
      if ($opt_lifetime_where.where)
        $req_formal_ls->where = new BlockStmt($opt_lifetime_where.where);
      if ($opt_lifetime_where.lifetime)
        $req_formal_ls->lifetimeConstraints = new BlockStmt($opt_lifetime_where.lifetime);
      $req_formal_ls->insertAtTail($function_body_stmt);
      $lambda_decl_expr = new DefExpr(buildLambda($req_formal_ls));
    }
;

linkage_spec:
        {
                  $linkage_spec = new FnSymbol("");
                }
    | TINLINE   {
                  $linkage_spec = new FnSymbol("");
                  $linkage_spec->addFlag(FLAG_INLINE);
                }
    | TOVERRIDE {
                  $linkage_spec = new FnSymbol("");
                  $linkage_spec->addFlag(FLAG_OVERRIDE);
                }
;

fn_decl_stmt:
    linkage_spec proc_iter_or_op    {
      // Capture the latest comment
      @proc_iter_or_op.comment = context->latestComment;
      context->latestComment = NULL;

      // Sets up to capture tokens while parsing the next grammar nonterminal.
      captureTokens = 1;
      captureString.clear();
    }
    fn_decl_stmt_inner  {
      // Stop capturing and save the result.
      captureTokens = 0;

      $fn_decl_stmt_inner->userString = astr(captureString);
    }
    opt_ret_tag opt_ret_type opt_throws_error opt_lifetime_where opt_function_body_stmt {
      FnSymbol* fn = $fn_decl_stmt_inner;
      FnSymbol* linkageFn = $linkage_spec;

      fn->copyFlags($linkage_spec);
      if (*linkageFn->name)
        // The user explicitly named this function (controls mangling).
        fn->cname = linkageFn->name;
      else if (linkageFn->numFormals() == 1)
        // cname should be set based upon param
        fn->insertFormalAtTail(linkageFn->getFormal(1));

      if ($proc_iter_or_op == ProcIterOp_ITER)
      {
        if (fn->hasFlag(FLAG_EXTERN))
          USR_FATAL_CONT(fn, "'iter' is not legal with 'extern'");
        fn->addFlag(FLAG_ITERATOR_FN);
      }
      if ($proc_iter_or_op == ProcIterOp_OP) {
        fn->addFlag(FLAG_OPERATOR);
        if (fn->_this != NULL) {
          updateOpThisTagOrErr(fn);
          setupTypeIntentArg(toArgSymbol(fn->_this));
        }
      }

      $fn_decl_stmt = buildFunctionDecl($fn_decl_stmt_inner, $opt_ret_tag, $opt_ret_type, $opt_throws_error, $opt_lifetime_where.where, $opt_lifetime_where.lifetime, $opt_function_body_stmt, @proc_iter_or_op.comment);
      context->latestComment = NULL;
    }
;

fn_decl_stmt_inner:
    opt_this_intent_tag fn_ident opt_formal_ls  {
      $fn_decl_stmt_inner = buildFunctionSymbol($opt_formal_ls, $fn_ident, $opt_this_intent_tag, NULL);
    }
    | opt_this_intent_tag assignop_ident opt_formal_ls  {
      $fn_decl_stmt_inner = buildFunctionSymbol($opt_formal_ls, $assignop_ident, $opt_this_intent_tag, NULL);
      $fn_decl_stmt_inner->addFlag(FLAG_ASSIGNOP);
    }
    | opt_this_intent_tag fn_decl_receiver_expr TDOT fn_ident opt_formal_ls {
      $fn_decl_stmt_inner = buildFunctionSymbol($opt_formal_ls, $fn_ident, $opt_this_intent_tag, $fn_decl_receiver_expr);
    }
    | opt_this_intent_tag fn_decl_receiver_expr TDOT assignop_ident opt_formal_ls   {
      $fn_decl_stmt_inner = buildFunctionSymbol($opt_formal_ls, $assignop_ident, $opt_this_intent_tag, $fn_decl_receiver_expr);
      $fn_decl_stmt_inner->addFlag(FLAG_ASSIGNOP);
    }
    | opt_this_intent_tag error opt_formal_ls   {
      $fn_decl_stmt_inner = buildFunctionSymbol($opt_formal_ls, "dummy", INTENT_BLANK, NULL);
    }
;

fn_decl_receiver_expr:
    ident_expr
| TLP expr TRP  { $fn_decl_receiver_expr = $expr; }
;

fn_ident:
    ident_fn_def    { $fn_ident = $ident_fn_def; }
    | TBAND { $fn_ident = "&"; }
    | TBOR  { $fn_ident = "|"; }
    | TBXOR { $fn_ident = "^"; }
    | TBNOT { $fn_ident = "~"; }
    | TEQUAL    { $fn_ident = "=="; }
    | TNOTEQUAL { $fn_ident = "!="; }
    | TLESSEQUAL    { $fn_ident = "<="; }
    | TGREATEREQUAL { $fn_ident = ">="; }
    | TLESS { $fn_ident = "<"; }
    | TGREATER  { $fn_ident = ">"; }
    | TPLUS { $fn_ident = "+"; }
    | TMINUS    { $fn_ident = "-"; }
    | TSTAR { $fn_ident = "*"; }
    | TDIVIDE   { $fn_ident = "/"; }
    | TSHIFTLEFT    { $fn_ident = "<<"; }
    | TSHIFTRIGHT   { $fn_ident = ">>"; }
    | TMOD  { $fn_ident = "%"; }
    | TEXP  { $fn_ident = "**"; }
    | TBANG { $fn_ident = "!"; }
    | TBY   { $fn_ident = "chpl_by"; }
    | THASH { $fn_ident = "#"; }
    | TALIGN    { $fn_ident = "chpl_align"; }
    | TSWAP { $fn_ident = "<=>"; }
    | TIO   { $fn_ident = "<~>"; }
    | TINITEQUALS   { $fn_ident = "init="; }
    | TCOLON    { $fn_ident = ":"; }
    | ident_def TBANG   { $fn_ident = astr($ident_def, "!"); }
;

assignop_ident:
    TASSIGN { $assignop_ident = "="; }
    | TASSIGNPLUS   { $assignop_ident = "+="; }
    | TASSIGNMINUS  { $assignop_ident = "-="; }
    | TASSIGNMULTIPLY   { $assignop_ident = "*="; }
    | TASSIGNDIVIDE { $assignop_ident = "/="; }
    | TASSIGNMOD    { $assignop_ident = "%="; }
    | TASSIGNEXP    { $assignop_ident = "**="; }
    | TASSIGNBAND   { $assignop_ident = "&="; }
    | TASSIGNBOR    { $assignop_ident = "|="; }
    | TASSIGNBXOR   { $assignop_ident = "^="; }
    | TASSIGNSR { $assignop_ident = ">>="; }
    | TASSIGNSL { $assignop_ident = "<<="; }
;

opt_formal_ls:
        { $opt_formal_ls = new FnSymbol("_"); $opt_formal_ls->addFlag(FLAG_NO_PARENS); }
    | TLP formal_ls TRP { $opt_formal_ls = $formal_ls; }
;

req_formal_ls:
    TLP formal_ls TRP   { $req_formal_ls = $formal_ls; }
;

formal_ls:
        { $formal_ls = buildFunctionFormal(NULL, NULL); }
    | formal    { $formal_ls = buildFunctionFormal(NULL, $formal); }
    | formal_ls[rhs_1] TCOMMA formal    { $$ /* formal_ls */ = buildFunctionFormal($rhs_1, $formal); }
;

formal:
    opt_intent_tag ident_def opt_formal_type opt_init_expr  { $formal = buildArgDefExpr($opt_intent_tag, $ident_def, $opt_formal_type, $opt_init_expr, NULL); }
    | pragma_ls opt_intent_tag ident_def opt_formal_type opt_init_expr  { $formal = buildPragmaDefExpr($pragma_ls, buildArgDefExpr($opt_intent_tag, $ident_def, $opt_formal_type, $opt_init_expr, NULL)); }
    | opt_intent_tag ident_def opt_formal_type var_arg_expr { $formal = buildArgDefExpr($opt_intent_tag, $ident_def, $opt_formal_type, NULL, $var_arg_expr); }
    | pragma_ls opt_intent_tag ident_def opt_formal_type var_arg_expr   { $formal = buildPragmaDefExpr($pragma_ls, buildArgDefExpr($opt_intent_tag, $ident_def, $opt_formal_type, NULL, $var_arg_expr)); }
    | opt_intent_tag TLP tuple_var_decl_stmt_inner_ls TRP opt_formal_type opt_init_expr { $formal = buildTupleArgDefExpr($opt_intent_tag, $tuple_var_decl_stmt_inner_ls, $opt_formal_type, $opt_init_expr); }
    | opt_intent_tag TLP tuple_var_decl_stmt_inner_ls TRP opt_formal_type var_arg_expr  { USR_FATAL("variable-length argument may not be grouped in a tuple"); }
;

opt_intent_tag:
        { $opt_intent_tag = INTENT_BLANK; }
    | required_intent_tag   { $opt_intent_tag = $required_intent_tag; }
;

required_intent_tag:
    TIN { $required_intent_tag = INTENT_IN; }
    | TINOUT    { $required_intent_tag = INTENT_INOUT; }
    | TOUT  { $required_intent_tag = INTENT_OUT; }
    | TCONST    { $required_intent_tag = INTENT_CONST; }
    | TCONST TIN    { $required_intent_tag = INTENT_CONST_IN; }
    | TCONST TREF   { $required_intent_tag = INTENT_CONST_REF; }
    | TPARAM    { $required_intent_tag = INTENT_PARAM; }
    | TREF  { $required_intent_tag = INTENT_REF; }
    | TTYPE { $required_intent_tag = INTENT_TYPE; }
;

opt_this_intent_tag:
        { $opt_this_intent_tag = INTENT_BLANK; }
    | TPARAM    { $opt_this_intent_tag = INTENT_PARAM; }
    | TREF  { $opt_this_intent_tag = INTENT_REF;   }
    | TCONST TREF   { $opt_this_intent_tag = INTENT_CONST_REF;   }
    | TCONST    { $opt_this_intent_tag = INTENT_CONST;   }
    | TTYPE { $opt_this_intent_tag = INTENT_TYPE;  }
;

proc_iter_or_op:
    TPROC   { $proc_iter_or_op = ProcIterOp_PROC; }
    | TITER { $proc_iter_or_op = ProcIterOp_ITER; }
    | TOPERATOR { $proc_iter_or_op = ProcIterOp_OP; }
;

opt_ret_tag:
        { $opt_ret_tag = RET_VALUE; }
    | TCONST    { $opt_ret_tag = RET_VALUE; }
    | TCONST TREF   { $opt_ret_tag = RET_CONST_REF; }
    | TREF  { $opt_ret_tag = RET_REF; }
    | TPARAM    { $opt_ret_tag = RET_PARAM; }
    | TTYPE { $opt_ret_tag = RET_TYPE; }
;

opt_throws_error:
        { $opt_throws_error = false; }
    | TTHROWS   { $opt_throws_error = true;  }
;

opt_function_body_stmt:
    TSEMI   { $opt_function_body_stmt = NULL; }
| function_body_stmt
;

function_body_stmt:
    block_stmt
| return_stmt   { $function_body_stmt = new BlockStmt($return_stmt); }
;

query_expr:
    TQUERIEDIDENT   { $query_expr = buildQueriedExpr($TQUERIEDIDENT); }
;

var_arg_expr:
    TDOTDOTDOT  { $var_arg_expr = new SymExpr(gUninstantiated); }
    | TDOTDOTDOT expr   { $var_arg_expr = $expr; }
    | TDOTDOTDOT query_expr { if (DefExpr* def = toDefExpr($query_expr)) {
                             def->sym->addFlag(FLAG_PARAM);
                           }
                           $var_arg_expr = $query_expr;
                         }
;

opt_lifetime_where:
        { $opt_lifetime_where = makeWhereAndLifetime(NULL, NULL); }
    | TWHERE expr   { $opt_lifetime_where = makeWhereAndLifetime($expr, NULL); }
    | TLIFETIME lifetime_components_expr    { $opt_lifetime_where = makeWhereAndLifetime(NULL, $lifetime_components_expr); }
    | TWHERE expr TLIFETIME lifetime_components_expr    { $opt_lifetime_where = makeWhereAndLifetime($expr, $lifetime_components_expr); }
    | TLIFETIME lifetime_components_expr TWHERE expr    { $opt_lifetime_where = makeWhereAndLifetime($expr, $lifetime_components_expr); }
;

lifetime_components_expr:
    lifetime_expr   { $lifetime_components_expr = $lifetime_expr; }
    | lifetime_components_expr[rhs_1] TCOMMA lifetime_expr  { $$ /* lifetime_components_expr */ = new CallExpr(",", $rhs_1, $lifetime_expr); }
;

lifetime_expr:
    lifetime_ident TASSIGN      lifetime_ident  {$lifetime_expr = new CallExpr("=", $1 /* lifetime_ident_1 */, $3 /* lifetime_ident_3 */);}
    | lifetime_ident TLESS        lifetime_ident    {$lifetime_expr = new CallExpr("<", $1 /* lifetime_ident_1 */, $3 /* lifetime_ident_3 */);}
    | lifetime_ident TLESSEQUAL   lifetime_ident    {$lifetime_expr = new CallExpr("<=", $1 /* lifetime_ident_1 */, $3 /* lifetime_ident_3 */);}
    | lifetime_ident TEQUAL       lifetime_ident    {$lifetime_expr = new CallExpr("==", $1 /* lifetime_ident_1 */, $3 /* lifetime_ident_3 */);}
    | lifetime_ident TGREATER     lifetime_ident    {$lifetime_expr = new CallExpr(">", $1 /* lifetime_ident_1 */, $3 /* lifetime_ident_3 */);}
    | lifetime_ident TGREATEREQUAL lifetime_ident   {$lifetime_expr = new CallExpr(">=", $1 /* lifetime_ident_1 */, $3 /* lifetime_ident_3 */);}
    | TRETURN lifetime_ident    { $lifetime_expr = new CallExpr(PRIM_RETURN, $lifetime_ident); }
;

lifetime_ident:
    TIDENT  { $lifetime_ident = new CallExpr(PRIM_LIFETIME_OF, new UnresolvedSymExpr($TIDENT)); }
    | TTHIS { $lifetime_ident = new CallExpr(PRIM_LIFETIME_OF, new UnresolvedSymExpr("this")); }
;

type_alias_decl_stmt:
    TTYPE type_alias_decl_stmt_inner TSEMI  { $type_alias_decl_stmt = $type_alias_decl_stmt_inner; }
    | TCONFIG TTYPE type_alias_decl_stmt_inner TSEMI    { $type_alias_decl_stmt = handleConfigTypes($type_alias_decl_stmt_inner); }
    | TEXTERN TTYPE type_alias_decl_stmt_inner TSEMI    { $type_alias_decl_stmt = convertTypesToExtern($type_alias_decl_stmt_inner); }
;

type_alias_decl_stmt_inner:
    ident_def opt_init_type {
      VarSymbol* var = new VarSymbol($ident_def);

      var->addFlag(FLAG_TYPE_VARIABLE);

      var->doc               = context->latestComment;
      context->latestComment = NULL;

      DefExpr* def = new DefExpr(var, $opt_init_type);

      $type_alias_decl_stmt_inner = buildChapelStmt(def);
    }
    | ident_def opt_init_type TCOMMA type_alias_decl_stmt_inner[rhs_1]  {
      VarSymbol* var = new VarSymbol($ident_def);

      var->addFlag(FLAG_TYPE_VARIABLE);

      var->doc               = context->latestComment;
      context->latestComment = NULL;

      DefExpr* def = new DefExpr(var, $opt_init_type);

      $rhs_1->insertAtHead(def);
      $$ /* type_alias_decl_stmt_inner */ = buildChapelStmt($rhs_1);
    }
;

opt_init_type:
        { $opt_init_type = NULL; }
    | TASSIGN type_level_expr   { $opt_init_type = $type_level_expr; }
    | TASSIGN array_type    { $opt_init_type = buildForallLoopExprFromArrayType($array_type); } // Cannot be a type_level_expr as expr inherits from type_level_expr.
;

var_decl_type:
    TPARAM  { $var_decl_type = buildVarDeclFlags(FLAG_PARAM); }
    | TCONST    { $var_decl_type = buildVarDeclFlags(FLAG_CONST); }
    | TREF  { $var_decl_type = buildVarDeclFlags(FLAG_REF_VAR); }
    | TCONST TREF   { $var_decl_type = buildVarDeclFlags(FLAG_CONST, FLAG_REF_VAR); }
    | TVAR  { $var_decl_type = buildVarDeclFlags(); }
;

var_decl_stmt:
    TCONFIG var_decl_type var_decl_stmt_inner_ls TSEMI  {
      $var_decl_type->insert(FLAG_CONFIG);
      $var_decl_stmt = buildVarDecls($var_decl_stmt_inner_ls, context->latestComment, $var_decl_type);
      context->latestComment = NULL;
    }
    | var_decl_type var_decl_stmt_inner_ls TSEMI    {
      $var_decl_stmt = buildVarDecls($var_decl_stmt_inner_ls, context->latestComment, $var_decl_type);
      context->latestComment = NULL;
    }
;

var_decl_stmt_inner_ls:
    var_decl_stmt_inner
| var_decl_stmt_inner_ls[rhs_1] TCOMMA var_decl_stmt_inner  {
      for_alist(expr, $var_decl_stmt_inner->body)
        $rhs_1->insertAtTail(expr->remove());
    }
;

var_decl_stmt_inner:
    ident_def opt_type opt_init_expr    { $var_decl_stmt_inner = buildChapelStmt(new DefExpr(new VarSymbol($ident_def), $opt_init_expr, $opt_type)); }
    | TLP tuple_var_decl_stmt_inner_ls TRP opt_type opt_init_expr   { $var_decl_stmt_inner = buildTupleVarDeclStmt($tuple_var_decl_stmt_inner_ls, $opt_type, $opt_init_expr); }
;

tuple_var_decl_component:
    TUNDERSCORE { $tuple_var_decl_component = new DefExpr(new VarSymbol("chpl__tuple_blank")); }
    | ident_def { $tuple_var_decl_component = new DefExpr(new VarSymbol($ident_def)); }
    | TLP tuple_var_decl_stmt_inner_ls TRP  { $tuple_var_decl_component = $tuple_var_decl_stmt_inner_ls; }
;

tuple_var_decl_stmt_inner_ls:
    tuple_var_decl_component    { $tuple_var_decl_stmt_inner_ls = buildChapelStmt($tuple_var_decl_component); }
    | tuple_var_decl_component TCOMMA   { $tuple_var_decl_stmt_inner_ls = buildChapelStmt($tuple_var_decl_component); }
    | tuple_var_decl_component TCOMMA tuple_var_decl_stmt_inner_ls[rhs_1]   { $$ /* tuple_var_decl_stmt_inner_ls */ = ($rhs_1->insertAtHead($tuple_var_decl_component), $rhs_1); }
;

opt_init_expr:
        { $opt_init_expr = NULL; }
    | TASSIGN TNOINIT   { $opt_init_expr = new SymExpr(gNoInit); }
    | TASSIGN opt_try_expr  { $opt_init_expr = $opt_try_expr; }
;

ret_array_type:
    TLSBR TRSBR type_level_expr { $ret_array_type = new CallExpr("chpl__buildArrayRuntimeType", gNil, $type_level_expr); }
    | TLSBR TRSBR   { $ret_array_type = new CallExpr("chpl__buildArrayRuntimeType", gNil, NULL); }
    | TLSBR expr_ls TRSBR type_level_expr   { $ret_array_type = new CallExpr("chpl__buildArrayRuntimeType",
             new CallExpr("chpl__ensureDomainExpr", $expr_ls), $type_level_expr);
    }
    | TLSBR expr_ls TRSBR   { $ret_array_type = new CallExpr("chpl__buildArrayRuntimeType",
             new CallExpr("chpl__ensureDomainExpr", $expr_ls), NULL);
    }
    | TLSBR TRSBR ret_array_type[rhs_1] { $$ /* ret_array_type */ = new CallExpr("chpl__buildArrayRuntimeType", gNil, $rhs_1); }
    | TLSBR expr_ls TRSBR ret_array_type[rhs_1] { $$ /* ret_array_type */ = new CallExpr("chpl__buildArrayRuntimeType",
             new CallExpr("chpl__ensureDomainExpr", $expr_ls), $rhs_1);
    }
    | TLSBR error TRSBR {
      $ret_array_type = new CallExpr(PRIM_ERROR);
    }

;

opt_ret_type:
        { $opt_ret_type = NULL; }
    | TCOLON type_level_expr    { $opt_ret_type = $type_level_expr; }
    | TCOLON ret_array_type { $opt_ret_type = $ret_array_type; }
    | TCOLON reserved_type_ident_use    { $opt_ret_type = new UnresolvedSymExpr($reserved_type_ident_use); }
    | error { $opt_ret_type = NULL; }
;

opt_type:
        { $opt_type = NULL; }
    | TCOLON type_level_expr    { $opt_type = $type_level_expr; }
    | TCOLON array_type { $opt_type = $array_type; }
    | TCOLON reserved_type_ident_use    { $opt_type = new UnresolvedSymExpr($reserved_type_ident_use); }
    | error { $opt_type = NULL; }
;

array_type:
    TLSBR expr_ls TRSBR type_level_expr { $array_type = new CallExpr("chpl__buildArrayRuntimeType",
             new CallExpr("chpl__ensureDomainExpr", $expr_ls), $type_level_expr);
    }
    | TLSBR expr_ls TRSBR array_type[rhs_1] { $$ /* array_type */ = new CallExpr("chpl__buildArrayRuntimeType",
             new CallExpr("chpl__ensureDomainExpr", $expr_ls), $rhs_1);
    }
    | TLSBR expr_ls TIN expr TRSBR type_level_expr  {
      if ($expr_ls->argList.length != 1)
        USR_FATAL($expr, "invalid index expression");
      $array_type = new CallExpr("chpl__buildArrayRuntimeType",
             new CallExpr("chpl__ensureDomainExpr", $expr), $type_level_expr, $expr_ls->get(1)->remove(),
             new CallExpr("chpl__ensureDomainExpr", $expr->copy()));
    }
    | TLSBR error TRSBR {
      $array_type = new CallExpr(PRIM_ERROR);
    }
;

opt_formal_array_elt_type:
        { $opt_formal_array_elt_type = NULL; }
    | type_level_expr   { $opt_formal_array_elt_type = $type_level_expr; }
    | query_expr    { $opt_formal_array_elt_type = $query_expr; }
;

formal_array_type:
    TLSBR TRSBR opt_formal_array_elt_type   { $formal_array_type = new CallExpr("chpl__buildArrayRuntimeType", gNil, $opt_formal_array_elt_type); }
    | TLSBR expr_ls TRSBR opt_formal_array_elt_type { $formal_array_type = buildFormalArrayType($expr_ls, $opt_formal_array_elt_type); }
    // Johnk: Unclear to me what the type should be when [<range>][] <type> is encountered.
//        At present buildArrayRuntimeType is undefined when gNil is passed and
//        the second argument is a formal_array_type[rhs_1].
| TLSBR TRSBR formal_array_type[rhs_2]  { $$ /* formal_array_type */ = new CallExpr("chpl__buildArrayRuntimeType", gNil, $rhs_2); }
    | TLSBR expr_ls TRSBR formal_array_type[rhs_1]  { $$ /* formal_array_type */ = buildFormalArrayType($expr_ls, $rhs_1); }
    | TLSBR expr_ls TIN expr TRSBR opt_formal_array_elt_type    { $formal_array_type = buildFormalArrayType($expr, $opt_formal_array_elt_type, $expr_ls); }
;

opt_formal_type:
        { $opt_formal_type = NULL; }
    | TCOLON type_level_expr    { $opt_formal_type = $type_level_expr; }
    | TCOLON query_expr { $opt_formal_type = $query_expr; }
    | TCOLON reserved_type_ident_use    { $opt_formal_type = new UnresolvedSymExpr($reserved_type_ident_use); }
    | TCOLON formal_array_type  { $opt_formal_type = $formal_array_type; }
;

expr_ls:
    expr    { $expr_ls = new CallExpr(PRIM_ACTUALS_LIST, $expr); }
    | query_expr    { $expr_ls = new CallExpr(PRIM_ACTUALS_LIST, $query_expr); }
    | expr_ls[rhs_1] TCOMMA expr    { $rhs_1->insertAtTail($expr); }
    | expr_ls[rhs_1] TCOMMA query_expr  { $rhs_1->insertAtTail($query_expr); }
;

simple_expr_ls:
    expr    { $simple_expr_ls = new CallExpr(PRIM_ACTUALS_LIST, $expr);}
    | simple_expr_ls[rhs_1] TCOMMA expr { $rhs_1->insertAtTail($expr); }
;

tuple_component:
    TUNDERSCORE { $tuple_component = new UnresolvedSymExpr("chpl__tuple_blank"); }
    | opt_try_expr  { $tuple_component = $opt_try_expr; }
    | query_expr    { $tuple_component = $query_expr; }
;

tuple_expr_ls:
    tuple_component TCOMMA tuple_component  { $tuple_expr_ls = new CallExpr(PRIM_ACTUALS_LIST, $1 /* tuple_component_1 */, $3 /* tuple_component_3 */); }
    | tuple_expr_ls[rhs_1] TCOMMA tuple_component   { $rhs_1->insertAtTail($tuple_component); }
;

opt_actual_ls:
        { $opt_actual_ls = new CallExpr(PRIM_ACTUALS_LIST); }
| actual_ls
;

actual_ls:
    actual_expr { $actual_ls = new CallExpr(PRIM_ACTUALS_LIST, $actual_expr); }
    | actual_ls[rhs_1] TCOMMA actual_expr   { $rhs_1->insertAtTail($actual_expr); }
;

actual_expr:
    ident_use TASSIGN query_expr    { $actual_expr = buildNamedActual($ident_use, $query_expr); }
    | ident_use TASSIGN opt_try_expr    { $actual_expr = buildNamedActual($ident_use, $opt_try_expr); }
    | query_expr    { $actual_expr = $query_expr; }
    | opt_try_expr  { $actual_expr = $opt_try_expr; }
;

ident_expr:
    ident_use   { $ident_expr = new UnresolvedSymExpr($ident_use); }
    | scalar_type   { $ident_expr = $scalar_type; }
;

type_level_expr:
    sub_type_level_expr %prec TNOELSE   { $type_level_expr = $sub_type_level_expr; }
    | sub_type_level_expr TQUESTION %prec TQUESTION { $type_level_expr = new CallExpr( PRIM_TO_NILABLE_CLASS_CHECKED, $sub_type_level_expr); }
    | TQUESTION { $type_level_expr = new SymExpr(gUninstantiated); }
;

sub_type_level_expr:
    nil_expr
| lhs_expr                  // var b: a.type || (?,?) || foo()
| cond_expr                 // type b = if b then uint else int
| unary_op_expr             // We allow binary exprs as types...why not unary?
| binary_op_expr            // tuples, expr dmapped expr, overloaded binary ops
| TSINGLE expr  { $sub_type_level_expr = new CallExpr( "_singlevar", $expr); }
    | TINDEX TLP opt_actual_ls TRP  { $sub_type_level_expr = new CallExpr("chpl__buildIndexType", $opt_actual_ls); }
    | TDOMAIN TLP opt_actual_ls TRP { $sub_type_level_expr = new CallExpr("chpl__buildDomainRuntimeType", new UnresolvedSymExpr("defaultDist"), $opt_actual_ls); }
    | TSUBDOMAIN TLP opt_actual_ls TRP  { $sub_type_level_expr = new CallExpr("chpl__buildSubDomainType", $opt_actual_ls); }
    | TSPARSE TSUBDOMAIN TLP actual_expr TRP    { $sub_type_level_expr = new CallExpr("chpl__buildSparseDomainRuntimeType", buildDotExpr($actual_expr->copy(), "defaultSparseDist"), $actual_expr); }
    | TATOMIC expr  { $sub_type_level_expr = new CallExpr("chpl__atomicType", $expr); }
    | TSYNC expr    { $sub_type_level_expr = new CallExpr( "_syncvar", $expr); }
    | TOWNED    { $sub_type_level_expr = new UnresolvedSymExpr("_owned"); }
    | TOWNED expr   { $sub_type_level_expr = new CallExpr( "_owned", $expr); }
    | TUNMANAGED    { $sub_type_level_expr = new SymExpr(dtUnmanaged->symbol); }
    | TUNMANAGED expr   { $sub_type_level_expr = new CallExpr( PRIM_TO_UNMANAGED_CLASS_CHECKED, $expr); }
    | TSHARED   { $sub_type_level_expr = new UnresolvedSymExpr("_shared"); }
    | TSHARED expr  { $sub_type_level_expr = new CallExpr( "_shared", $expr); }
    | TBORROWED { $sub_type_level_expr = new SymExpr(dtBorrowed->symbol); }
    | TBORROWED expr    { $sub_type_level_expr = new CallExpr( PRIM_TO_BORROWED_CLASS_CHECKED, $expr); }
    | TCLASS    { $sub_type_level_expr = new SymExpr(dtAnyManagementNonNilable->symbol); }
    | TRECORD   { $sub_type_level_expr = new SymExpr(dtAnyRecord->symbol); }
;

for_expr:
    TFOR expr TIN expr TDO expr %prec TFOR  { $for_expr = buildForLoopExpr($2 /* expr_2 */, $4 /* expr_4 */, $6 /* expr_6 */); }
    | TFOR expr TIN zippered_iterator TDO expr %prec TFOR   { $for_expr = buildForLoopExpr($2 /* expr_2 */, $zippered_iterator, $6 /* expr_6 */, NULL, false, true); }
    | TFOR expr TDO expr %prec TFOR { $for_expr = buildForLoopExpr(NULL, $2 /* expr_2 */, $4 /* expr_4 */); }
    | TFOR expr TIN expr TDO TIF expr TTHEN expr %prec TNOELSE  { $for_expr = buildForLoopExpr($2 /* expr_2 */, $4 /* expr_4 */, $9 /* expr_9 */, $7 /* expr_7 */); }
    | TFOR expr TIN zippered_iterator TDO TIF expr TTHEN expr %prec TNOELSE { $for_expr = buildForLoopExpr($2 /* expr_2 */, $zippered_iterator, $9 /* expr_9 */, $7 /* expr_7 */, false, true); }
    | TFOR expr TDO TIF expr TTHEN expr %prec TNOELSE   { $for_expr = buildForLoopExpr(NULL, $2 /* expr_2 */, $7 /* expr_7 */, $5 /* expr_5 */); }
    | TFORALL expr TIN expr TDO expr %prec TFOR { $for_expr = buildForallLoopExpr($2 /* expr_2 */, $4 /* expr_4 */, $6 /* expr_6 */); }
    | TFORALL expr TIN zippered_iterator TDO expr %prec TFOR    { $for_expr = buildForallLoopExpr($2 /* expr_2 */, $zippered_iterator, $6 /* expr_6 */, NULL, false, true); }
    | TFORALL expr TDO expr %prec TFOR  { $for_expr = buildForallLoopExpr(NULL, $2 /* expr_2 */, $4 /* expr_4 */); }
    | TFORALL expr TIN expr TDO TIF expr TTHEN expr %prec TNOELSE   { $for_expr = buildForallLoopExpr($2 /* expr_2 */, $4 /* expr_4 */, $9 /* expr_9 */, $7 /* expr_7 */); }
    | TFORALL expr TIN zippered_iterator TDO TIF expr TTHEN expr %prec TNOELSE  { $for_expr = buildForallLoopExpr($2 /* expr_2 */, $zippered_iterator, $9 /* expr_9 */, $7 /* expr_7 */, false, true); }
    | TFORALL expr TDO TIF expr TTHEN expr %prec TNOELSE    { $for_expr = buildForallLoopExpr(NULL, $2 /* expr_2 */, $7 /* expr_7 */, $5 /* expr_5 */); }
    | TLSBR expr_ls TRSBR expr %prec TFOR   {
      if ($expr_ls->argList.length > 1)
        $for_expr = buildForallLoopExpr(NULL, new CallExpr("chpl__ensureDomainExpr", $expr_ls), $expr, NULL, true);
      else
        $for_expr = buildForallLoopExpr(NULL, $expr_ls->get(1)->remove(), $expr, NULL, true);
    }
    | TLSBR expr_ls TIN expr TRSBR expr %prec TFOR  {
      if ($expr_ls->argList.length != 1)
        USR_FATAL($4 /* expr_4 */, "invalid index expression");
      $for_expr = buildForallLoopExpr($expr_ls->get(1)->remove(), $4 /* expr_4 */, $6 /* expr_6 */, NULL, true);
    }
    | TLSBR expr_ls TIN zippered_iterator TRSBR expr %prec TFOR {
      if ($expr_ls->argList.length != 1)
        USR_FATAL($zippered_iterator, "invalid index expression");
      $for_expr = buildForallLoopExpr($expr_ls->get(1)->remove(), $zippered_iterator, $expr, NULL, false, true);
    }
    | TLSBR expr_ls TIN expr TRSBR TIF expr TTHEN expr %prec TNOELSE    {
      if ($expr_ls->argList.length != 1)
        USR_FATAL($4 /* expr_4 */, "invalid index expression");
      $for_expr = buildForallLoopExpr($expr_ls->get(1)->remove(), $4 /* expr_4 */, $9 /* expr_9 */, $7 /* expr_7 */);
    }
    | TLSBR expr_ls TIN zippered_iterator TRSBR TIF expr TTHEN expr %prec TNOELSE   {
      if ($expr_ls->argList.length != 1)
        USR_FATAL($zippered_iterator, "invalid index expression");
      $for_expr = buildForallLoopExpr($expr_ls->get(1)->remove(), $zippered_iterator, $9 /* expr_9 */, $7 /* expr_7 */, false, true);
    }
;

cond_expr:
    TIF expr TTHEN expr TELSE expr  { $cond_expr = new IfExpr($2 /* expr_2 */, $4 /* expr_4 */, $6 /* expr_6 */); }
/* MPF: it would be nice to match TIF expr TTHEN expr but
   the attempt below leads to reduce-reduce conflicts:
      TIF expr TTHEN expr %prec TNOELSE
   with for_expr.
 */
;

nil_expr:
    TNIL    { $nil_expr = new SymExpr(gNil); }
;

stmt_level_expr:
    nil_expr
| ident_expr
| dot_expr
| call_expr
| lambda_decl_expr
| new_expr
| let_expr
| io_expr TIO expr  { $stmt_level_expr = new CallExpr("<~>", $io_expr, $expr); }
;

opt_task_intent_ls:
        { $opt_task_intent_ls = NULL; }
| task_intent_clause
;

task_intent_clause:
    TWITH TLP task_intent_ls TRP    { $task_intent_clause = $task_intent_ls; }
;

task_intent_ls:
    intent_expr { $task_intent_ls = new CallExpr(PRIM_ACTUALS_LIST); addTaskIntent($task_intent_ls, $intent_expr); }
    | task_intent_ls[rhs_1] TCOMMA intent_expr  { addTaskIntent($rhs_1, $intent_expr); }
;

forall_intent_clause:
    TWITH TLP forall_intent_ls TRP  { $forall_intent_clause = $forall_intent_ls; }
;

forall_intent_ls:
    intent_expr { $forall_intent_ls = new CallExpr(PRIM_ACTUALS_LIST); addForallIntent($forall_intent_ls, $intent_expr); }
    | forall_intent_ls[rhs_1] TCOMMA intent_expr    { addForallIntent($rhs_1, $intent_expr); }
;

intent_expr:
    shadow_var_prefix ident_expr opt_type opt_init_expr {
      $intent_expr = ShadowVarSymbol::buildForPrefix($shadow_var_prefix, $ident_expr, $opt_type, $opt_init_expr);
    }
    | reduce_scan_op_expr TREDUCE ident_expr    {
      $intent_expr = ShadowVarSymbol::buildFromReduceIntent($ident_expr, $reduce_scan_op_expr);
    }
    | expr                TREDUCE ident_expr    {
      $intent_expr = ShadowVarSymbol::buildFromReduceIntent($ident_expr, $expr);
    }
;

shadow_var_prefix:
    TCONST  { $shadow_var_prefix = SVP_CONST;     }
    | TIN   { $shadow_var_prefix = SVP_IN;        }
    | TCONST TIN    { $shadow_var_prefix = SVP_CONST_IN;  }
    | TREF  { $shadow_var_prefix = SVP_REF;       }
    | TCONST TREF   { $shadow_var_prefix = SVP_CONST_REF; }
    | TVAR  { $shadow_var_prefix = SVP_VAR;       }
;

io_expr:
    lhs_expr
| io_expr[rhs_1] TIO expr   { $$ /* io_expr */ = new CallExpr("<~>", $rhs_1, $expr); }
;

new_maybe_decorated:
    TNEW         %prec TNOELSE  { $new_maybe_decorated = new CallExpr(PRIM_NEW); }
    | TNEW TOWNED   { $new_maybe_decorated = new CallExpr(PRIM_NEW,
                        new NamedExpr(astr_chpl_manager,
                                      new SymExpr(dtOwned->symbol))); }
    | TNEW TSHARED  { $new_maybe_decorated = new CallExpr(PRIM_NEW,
                        new NamedExpr(astr_chpl_manager,
                                      new SymExpr(dtShared->symbol))); }
    | TNEW TUNMANAGED   { $new_maybe_decorated = new CallExpr(PRIM_NEW,
                        new NamedExpr(astr_chpl_manager,
                                      new SymExpr(dtUnmanaged->symbol))); }
    | TNEW TBORROWED    { $new_maybe_decorated = new CallExpr(PRIM_NEW,
                        new NamedExpr(astr_chpl_manager,
                                      new SymExpr(dtBorrowed->symbol))); }
;

new_expr:
    /* handles the typical new cases, e.g. new C(); new owned C() */
  new_maybe_decorated expr %prec TNEW   { $new_maybe_decorated->insertAtTail($expr);
      $new_expr = $new_maybe_decorated; }
    /* handles e.g. new (typefn())(initargs) */
| TNEW TOWNED TLP expr TRP TLP opt_actual_ls TRP %prec TNOELSE  { $new_expr = new CallExpr(PRIM_NEW,
                        new NamedExpr(astr_chpl_manager,
                                      new SymExpr(dtOwned->symbol)),
                        new CallExpr($expr, $opt_actual_ls));
    }
    | TNEW TSHARED TLP expr TRP TLP opt_actual_ls TRP %prec TNOELSE { $new_expr = new CallExpr(PRIM_NEW,
                        new NamedExpr(astr_chpl_manager,
                                      new SymExpr(dtShared->symbol)),
                        new CallExpr($expr, $opt_actual_ls));
    }
    | TNEW TOWNED TLP expr TRP TLP opt_actual_ls TRP TQUESTION  { $new_expr = new CallExpr(PRIM_NEW,
                        new NamedExpr(astr_chpl_manager,
                                      new SymExpr(dtOwned->symbol)),
                        new CallExpr(PRIM_TO_NILABLE_CLASS_CHECKED,
                                     new CallExpr($expr, $opt_actual_ls)));
    }
    | TNEW TSHARED TLP expr TRP TLP opt_actual_ls TRP TQUESTION { $new_expr = new CallExpr(PRIM_NEW,
                        new NamedExpr(astr_chpl_manager,
                                      new SymExpr(dtShared->symbol)),
                        new CallExpr(PRIM_TO_NILABLE_CLASS_CHECKED,
                                     new CallExpr($expr, $opt_actual_ls)));
    }
;

let_expr:
    TLET var_decl_stmt_inner_ls TIN expr    { $let_expr = buildLetExpr($var_decl_stmt_inner_ls, $expr); }
;

expr:
    literal_expr
| type_level_expr
| for_expr
| reduce_expr
| scan_expr
| lambda_decl_expr
| new_expr
| let_expr
| ifc_constraint
| TLP TDOTDOTDOT expr[rhs_1] TRP    { $$ /* expr */ = new CallExpr(PRIM_TUPLE_EXPAND, $rhs_1); }
    | expr[rhs_1] TCOLON expr[rhs_2]    { $$ /* expr */ = createCast($rhs_1, $rhs_2); }
    | expr[rhs_1] TDOTDOT expr[rhs_2]   { $$ /* expr */ = buildBoundedRange($rhs_1, $rhs_2); }
    | expr[rhs_1] TDOTDOTOPENHIGH expr[rhs_2]   { $$ /* expr */ = buildBoundedRange($rhs_1, $rhs_2, false, true); }
    /* The following cases would extend the current '..<' open range
   interval constructor to also support '<..' and '<..<'.  This
   concept didn't win enough support to merge as present, but are here
   in case we change our minds in a future release.

| expr TDOTDOTOPENLOW expr
    { $$ = buildBoundedRange($1, $3, true, false); }
| expr TDOTDOTOPENBOTH expr
    { $$ = buildBoundedRange($1, $3, true, true); }
| expr TDOTDOTOPENLOW
    { $$ = buildLowBoundedRange($1, true); }
*/
| expr[rhs_1] TDOTDOT   { $$ /* expr */ = buildLowBoundedRange($rhs_1); }
    | TDOTDOT expr[rhs_1]   { $$ /* expr */ = buildHighBoundedRange($rhs_1); }
    | TDOTDOTOPENHIGH expr[rhs_1]   { $$ /* expr */ = buildHighBoundedRange($rhs_1, true); }
    | TDOTDOT   { $expr = buildUnboundedRange(); }
;

opt_expr:
        { $opt_expr = NULL; }
    | expr  { $opt_expr = $expr; }
;

opt_try_expr:
    TTRY expr   { $opt_try_expr = tryExpr($expr); }
    | TTRYBANG expr { $opt_try_expr = tryBangExpr($expr); }
    | expr  { $opt_try_expr = $expr; }
;

lhs_expr:
  ident_expr
| call_expr
| dot_expr
| parenthesized_expr
;

call_base_expr:
    lhs_expr    { $call_base_expr = $lhs_expr; }
    | expr TBANG    { $call_base_expr = new CallExpr("postfix!", $expr); }
    | sub_type_level_expr TQUESTION {$call_base_expr = new CallExpr(PRIM_TO_NILABLE_CLASS_CHECKED, $sub_type_level_expr);}
    | lambda_decl_expr  { $call_base_expr = $lambda_decl_expr; }
| str_bytes_literal
;

call_expr:
    call_base_expr TLP opt_actual_ls TRP    { $call_expr = new CallExpr($call_base_expr, $opt_actual_ls); }
    | call_base_expr TLSBR opt_actual_ls TRSBR  { $call_expr = buildSquareCallExpr($call_base_expr, $opt_actual_ls); }
    | TPRIMITIVE TLP opt_actual_ls TRP  { $call_expr = buildPrimitiveExpr($opt_actual_ls); }
;

dot_expr:
    expr TDOT ident_use { $dot_expr = buildDotExpr($expr, $ident_use); }
    | expr TDOT TTYPE   { $dot_expr = new CallExpr(PRIM_TYPEOF, $expr); }
    | expr TDOT TDOMAIN { $dot_expr = buildDotExpr($expr, "_dom"); }
    | expr TDOT TLOCALE { $dot_expr = buildDotExpr($expr, "locale"); }
    | expr TDOT TBYTES TLP TRP  { $dot_expr = new CallExpr(buildDotExpr($expr, "chpl_bytes")); }
;

parenthesized_expr:
    TLP tuple_component TRP { $parenthesized_expr = $tuple_component; }
    | TLP tuple_component TCOMMA TRP    { $parenthesized_expr = buildOneTuple($tuple_component); }
    | TLP tuple_expr_ls TRP { $parenthesized_expr = buildTuple($tuple_expr_ls); }
    | TLP tuple_expr_ls TCOMMA TRP  { $parenthesized_expr = buildTuple($tuple_expr_ls); }
;

bool_literal:
    TFALSE  { $bool_literal = new SymExpr(gFalse); }
    | TTRUE { $bool_literal = new SymExpr(gTrue); }
;

str_bytes_literal:
    STRINGLITERAL   { $str_bytes_literal = buildStringLiteral($STRINGLITERAL); }
    | BYTESLITERAL  { $str_bytes_literal = buildBytesLiteral($BYTESLITERAL); }
;

literal_expr:
    bool_literal
| str_bytes_literal
| INTLITERAL    { $literal_expr = buildIntLiteral($INTLITERAL, yyfilename, chplLineno);    }
    | REALLITERAL   { $literal_expr = buildRealLiteral($REALLITERAL);   }
    | IMAGLITERAL   { $literal_expr = buildImagLiteral($IMAGLITERAL);   }
    | CSTRINGLITERAL    { $literal_expr = buildCStringLiteral($CSTRINGLITERAL); }
    | TNONE { $literal_expr = new SymExpr(gNone); }
    | TLCBR expr_ls TRCBR   { $literal_expr = new CallExpr("chpl__buildDomainExpr", $expr_ls,
                                            new SymExpr(gTrue)); }
    | TLCBR expr_ls TCOMMA TRCBR    { $literal_expr = new CallExpr("chpl__buildDomainExpr", $expr_ls,
                                                   new SymExpr(gTrue)); }
    | TLSBR expr_ls TRSBR   { $literal_expr = new CallExpr("chpl__buildArrayExpr",  $expr_ls); }
    | TLSBR expr_ls TCOMMA TRSBR    { $literal_expr = new CallExpr("chpl__buildArrayExpr",  $expr_ls); }
    | TLSBR assoc_expr_ls TRSBR {
      $literal_expr = new CallExpr("chpl__buildAssociativeArrayExpr", $assoc_expr_ls);
    }
    | TLSBR assoc_expr_ls TCOMMA TRSBR  {
      $literal_expr = new CallExpr("chpl__buildAssociativeArrayExpr", $assoc_expr_ls);
    }

;

assoc_expr_ls:
    expr TALIAS expr    { $assoc_expr_ls = new CallExpr(PRIM_ACTUALS_LIST, $1 /* expr_1 */, $3 /* expr_3 */); }
    | assoc_expr_ls[rhs_1] TCOMMA expr TALIAS expr  { $rhs_1->insertAtTail($3 /* expr_3 */); $rhs_1->insertAtTail($5 /* expr_5 */); }
;

binary_op_expr:
    expr TPLUS expr { $binary_op_expr = new CallExpr("+", $1 /* expr_1 */, $3 /* expr_3 */); }
    | expr TMINUS expr  { $binary_op_expr = new CallExpr("-", $1 /* expr_1 */, $3 /* expr_3 */); }
    | expr TSTAR expr   { $binary_op_expr = new CallExpr("*", $1 /* expr_1 */, $3 /* expr_3 */); }
    | expr TDIVIDE expr { $binary_op_expr = new CallExpr("/", $1 /* expr_1 */, $3 /* expr_3 */); }
    | expr TSHIFTLEFT expr  { $binary_op_expr = new CallExpr("<<", $1 /* expr_1 */, $3 /* expr_3 */); }
    | expr TSHIFTRIGHT expr { $binary_op_expr = new CallExpr(">>", $1 /* expr_1 */, $3 /* expr_3 */); }
    | expr TMOD expr    { $binary_op_expr = new CallExpr("%", $1 /* expr_1 */, $3 /* expr_3 */); }
    | expr TEQUAL expr  { $binary_op_expr = new CallExpr("==", $1 /* expr_1 */, $3 /* expr_3 */); }
    | expr TNOTEQUAL expr   { $binary_op_expr = new CallExpr("!=", $1 /* expr_1 */, $3 /* expr_3 */); }
    | expr TLESSEQUAL expr  { $binary_op_expr = new CallExpr("<=", $1 /* expr_1 */, $3 /* expr_3 */); }
    | expr TGREATEREQUAL expr   { $binary_op_expr = new CallExpr(">=", $1 /* expr_1 */, $3 /* expr_3 */); }
    | expr TLESS expr   { $binary_op_expr = new CallExpr("<", $1 /* expr_1 */, $3 /* expr_3 */); }
    | expr TGREATER expr    { $binary_op_expr = new CallExpr(">", $1 /* expr_1 */, $3 /* expr_3 */); }
    | expr TBAND expr   { $binary_op_expr = new CallExpr("&", $1 /* expr_1 */, $3 /* expr_3 */); }
    | expr TBOR expr    { $binary_op_expr = new CallExpr("|", $1 /* expr_1 */, $3 /* expr_3 */); }
    | expr TBXOR expr   { $binary_op_expr = new CallExpr("^", $1 /* expr_1 */, $3 /* expr_3 */); }
    | expr TAND expr    { $binary_op_expr = new CallExpr("&&", $1 /* expr_1 */, $3 /* expr_3 */); }
    | expr TOR  expr    { $binary_op_expr = new CallExpr("||", $1 /* expr_1 */, $3 /* expr_3 */); }
    | expr TEXP expr    { $binary_op_expr = new CallExpr("**", $1 /* expr_1 */, $3 /* expr_3 */); }
    | expr TBY expr { $binary_op_expr = new CallExpr("chpl_by", $1 /* expr_1 */, $3 /* expr_3 */); }
    | expr TALIGN expr  { $binary_op_expr = new CallExpr("chpl_align", $1 /* expr_1 */, $3 /* expr_3 */); }
    | expr THASH expr   { $binary_op_expr = new CallExpr("#", $1 /* expr_1 */, $3 /* expr_3 */); }
    | expr TDMAPPED expr    { $binary_op_expr = new CallExpr("chpl__distributed", $3 /* expr_3 */, $1 /* expr_1 */,
                                               new SymExpr(gTrue)); }
;

unary_op_expr:
    TPLUS expr %prec TUPLUS { $unary_op_expr = new CallExpr("+", $expr); }
    | TMINUS expr %prec TUMINUS { $unary_op_expr = new CallExpr("-", $expr); }
    | TMINUSMINUS expr %prec TUMINUS    { $unary_op_expr = buildPreDecIncWarning($expr, '-'); }
    | TPLUSPLUS expr %prec TUPLUS   { $unary_op_expr = buildPreDecIncWarning($expr, '+'); }
    | TBANG expr %prec TLNOT    { $unary_op_expr = new CallExpr("!", $expr); }
    | expr TBANG    { $unary_op_expr = new CallExpr("postfix!", $expr); }
    | TBNOT expr    { $unary_op_expr = new CallExpr("~", $expr); }
;

reduce_expr:
    expr TREDUCE expr   { $reduce_expr = buildReduceExpr($1 /* expr_1 */, $3 /* expr_3 */); }
    | expr TREDUCE zippered_iterator    { $reduce_expr = buildReduceExpr($expr, $zippered_iterator, true); }
    | reduce_scan_op_expr TREDUCE expr  { $reduce_expr = buildReduceExpr($reduce_scan_op_expr, $expr); }
    | reduce_scan_op_expr TREDUCE zippered_iterator { $reduce_expr = buildReduceExpr($reduce_scan_op_expr, $zippered_iterator, true); }
;

scan_expr:
    expr TSCAN expr { $scan_expr = buildScanExpr($1 /* expr_1 */, $3 /* expr_3 */); }
    | expr TSCAN zippered_iterator  { $scan_expr = buildScanExpr($expr, $zippered_iterator, true); }
    | reduce_scan_op_expr TSCAN expr    { $scan_expr = buildScanExpr($reduce_scan_op_expr, $expr); }
    | reduce_scan_op_expr TSCAN zippered_iterator   { $scan_expr = buildScanExpr($reduce_scan_op_expr, $zippered_iterator, true); }
;

reduce_scan_op_expr:
    TPLUS   { $reduce_scan_op_expr = new UnresolvedSymExpr("SumReduceScanOp"); }
    | TSTAR { $reduce_scan_op_expr = new UnresolvedSymExpr("ProductReduceScanOp"); }
    | TAND  { $reduce_scan_op_expr = new UnresolvedSymExpr("LogicalAndReduceScanOp"); }
    | TOR   { $reduce_scan_op_expr = new UnresolvedSymExpr("LogicalOrReduceScanOp"); }
    | TBAND { $reduce_scan_op_expr = new UnresolvedSymExpr("BitwiseAndReduceScanOp"); }
    | TBOR  { $reduce_scan_op_expr = new UnresolvedSymExpr("BitwiseOrReduceScanOp"); }
    | TBXOR { $reduce_scan_op_expr = new UnresolvedSymExpr("BitwiseXorReduceScanOp"); }
;
mingodad commented 1 year ago

I'm working to achieve a LALR(1)/LEX to try grammars online with wasm based on https://github.com/BenHanson/gram_grep and I've got the Chappel grammar working, view it here https://mingodad.github.io/parsertl-playground/playground/ select Chappel parser from the examples, you can edit the Grammar or the Input source and press Parse to see a parser tree.

I hope it can be a nice tool to experiment with LALR(1)/LEX grammars with instant feedback !