# grammar derived from imp80-rde-2022/genps/ps86.dat

I<imp80-init.g>;

# P<SS> IS THE MAIN ENTRY POINT!:

# built-in phrases known to the parser.
B<eof>=0;
B<ch>=1;
B<nl>=2;
#B<junk>=3;

P<nls>              = <nl> <nls>, '';
P<READLINEP>        = <nls>, '';      # Used when there is an optional line break, eg after '=' or ',' in array initialisations.

# Note that the code associated with a grammar rule will be called in three
# contexts: 1) when parsing the concrete syntax
#           2) when converting the concrete syntax tree to an abstract syntax tree
#           3) when walking the abstract syntax tree to perform the main function
#              of the program, whether actually compiling, or converting source to
#              source, or just re-outputting the source (possibly reindented).

# to support all these options without having to invent a lot of new syntax, the
# code part of each rule can restrict when it is executed by testing various
# internally-predefined ifdef's.  X_APP is the one for the actual application.

P<SET_DOWN_FLAG> = {
#ifdef X_APP
  DOWN_flag = 1;
#endif
};

P<DOWNQ> = {
#ifdef X_APP
  if (DOWN_flag == 1) {
    push_scope_level();
  }
  DOWN_flag = 0;
#endif
};

P<DOWN> = {
#ifdef X_APP
  push_scope_level();
#endif
};

P<UP> = {
#ifdef X_APP
  pop_scope_level();
#endif
};

# Currently most of these are holdovers from the ERCC compiler and
# are unlikely to be used, at least in the same style.  They'll
# most likely all be removed, though something with a siilarity
# to the original may return in a different form later when I get
# round to implementing the compiler and realise why they were
# here in the first place :-)

C<MARK>        = { return TRUE; };    # MARK (set marker for linkage)
C<QNAME>       = { return TRUE; };    # BIP(1001) NAME
C<QFORMATP>    = { return TRUE; };
C<VSPECP>      = { return TRUE; };
C<ALIASP>      = { return TRUE; };
C<COLON>       = { return TRUE; };    # BIP(1019) COLON (for label)
C<ELSEP>       = { return TRUE; };
C<SETNEM>      = { return TRUE; };    # BIP(1022) SETNEM (set mnemonic)
C<ICONST>      = { return TRUE; };    # BIP(1002) xconst(TRUE, &strpos)
C<ASMWRONG>    = { return TRUE; };    # BIP(1031) UCWRONG; machine code error
C<OP0FORM>     = { return TRUE; };
C<OPFFORM>     = { return TRUE; };
C<OP1FORM>     = { return TRUE; };    # BIP(1023) PRIMFORM; primary format mnemonic
C<OP2FORM>     = { return TRUE; };    # BIP(1024) SECNFORM; secondary format mnemonic
C<OP3FORM>     = { return TRUE; };    # BIP(1025) TERTFORM; tertiary format mnemonic
C<OPJFORM>     = { return TRUE; };    # (machine code jump format?)


C<FPREG>       = { return TRUE; };    # (machine code floating point register?)
C<REG>         = { return TRUE; };    #               integer

                                      # BIP(1009) N255 (number 0-255 only)
                                      # BIP(1005) phrase N (16 bit decimal number)
C<QEVENTP>     = { return TRUE; };
C<CHUI>        = { return TRUE; };    # BIP(1027) CHUI - check that statement
                                      # starts with valid character:
                                      # letter,'-',%C,%E,%M,%R,%S
C<NOTESTART>   = { return TRUE; };    # BIP(1034) NOTESTART (note %START)
C<NOTEFINISH>  = { return TRUE; };    # BIP(1035) NOTEFINISH (note %FINISH)
C<NOTECYCLE>   = { return TRUE; };    # BIP(1029) NOTECYCLE (note start of %CYCLE)
C<NOTEREPEAT>  = { return TRUE; };    # BIP(1036) NOTEREPEAT (note %REPEAT)
C<INCLUDE>     = { return TRUE; };    # BIP(1038) INCLUDE (include file)
C<TRACE>       = { return TRUE; };    # BIP(1021) TRACE (for %ON conditions)
C<LISTON>      = { return TRUE; };    # BIP(1017) LISTON (turn on listing)
C<LISTOFF>     = { return TRUE; };    # BIP(1018) LISTOFF (turn off listing)
C<DUMMYSTART>  = { return TRUE; };    # BIP(1039) DUMMYSTART: give same 'ar' as %ELSE %START


P<S>                = <nl>, ';'; # statements separator

P<OP>               = '+',  '-', '&',  '****', '**', '*',  '!!', '!',
		 '//', '/', '>>', '<<',   '.',  '\\\\', '\\',  '^^', '^';

P<UOP>              = '+', '-', '\\', '~', '';  # BIP(1028) phrase +' (unary operator):

P<ASSOP>            = '==', '=', '<-', '->';

P<COMP1>            = '=', '>=', '>', '#', '\\=', '<>', '<=', '<', '->', '==', '##', '\\==';

P<COMP2>            = '=', '>=', '>', '#', '\\=', '<>', '<=', '<', '->', '==', '##', '\\==';


# <NAME> and <CONST> as regexps rather than BIPs... (demo, incomplete)
##P<NAME>        = «[A-Za-z][A-Za-z0-9]*»;   # BIP(1001) pname(TRUE)
P<NAME>             = <!CONST> «[A-Z][A-Z0-9]*» {
#ifdef X_APP
  fprintf(stderr, " [Name] ");
#endif
};   # BIP(1001) pname(TRUE)

P<BigCharConst>     = «'([^\']|'')*'»; # <sq><sq><sq><sq>, <sq><sq>, <sq> <ch> <sq>;

P<CharConst>        = «''''», «''», «'.'»; # <sq><sq><sq><sq>, <sq><sq>, <sq> <ch> <sq>;
# TO DO: CONST is all types of const, not just plain numbers (see <N> for 16 bit numbers for example)

P<OptExponent>      = '@'<N>, '';
P<OptDecimal>       = '.'<N>, '';
# BIP(1003) xconst(FALSE, &strpos)
P<CONST>            = <N><OptDecimal><OptExponent>,
                      <CharConst>,
                      <ALIASTEXT>,
                      'E'<ALIASTEXT>,           # EBCDIC
                      «[MBKXR]»<BigCharConst>;  # Multi Binary oKtal heX Realhex  (K'7777' not O'7777' - earlier error)

P<N>                = «[0-9][0-9]*»;
##P<ALIASTEXT>        = «\".*\"»;   # BIP(1013) TEXTTEXT (alias text)   [I'll handle "" later.]

P<dq>               = '"' ;
P<any>         = «.» ;
P<stringchars>      = <dq><dq> <stringchars>, <!dq> <any> <stringchars>, '';
P<ALIASTEXT>        = <dq> <stringchars> <dq> ;

P<semi>             = ';';
##P<eof>         = <!any>;
P<Comment>          = '!' <TEXT>, '|' <TEXT>, "comment" <TEXT> {
  return -1;
};
P<TEXT>             = <!S> «.» <TEXT>, '';   # comment text


P<OPERAND>          = <NAME><APP><ENAMEQ>,
                      <CONST>,
                      '('<EXPR>')' {
};

P<COPERAND>         = <NAME>, <CONST>, '('<CEXPR>')';

P<CEXPR>            = <UOP><COPERAND><MARK><RESTOFCEXPR>;

P<STAROREXPR>       = <UOP><COPERAND><MARK><RESTOFCEXPR>,
                      '*';

P<EXPR>             = <UOP><OPERAND><MARK><RESTOFEXPR>;

P<RESTOFEXPR>       = <OP><OPERAND><RESTOFEXPR>,
                      '';

P<RESTOFCEXPR>      = <OP><COPERAND><RESTOFCEXPR>,
                      '';

P<APP>              = '('<EXPR><RESTOFAPP>')',
                      '';

P<RESTOFAPP>        = ',' <EXPR><RESTOFAPP>,
                      '';

P<PC_IU>            = "if",
                      "unless";

P<PC_WU>            = "while"<SC><RESTOFCOND><MARK>,
                      "until"<SC><RESTOFCOND><MARK>,
                      "for"<NAME>'='<EXPR>','<EXPR>','<EXPR><MARK>;

P<ALIASQ>           = "alias"<ALIASTEXT>,
                      '';

P<NAMES>           = ','<READLINEP><NAME><NAMES>,   # added to enable implicit continuation in record formats
                      '';

P<FULLTYPE>         = "integer",
                      '';

P<BTYPE>            = "real",
                      "integer";

# signed/unsigned extensions could go here.
P<XTYPE>            = "integer",
                      "real",
                      "long" "long"<BTYPE>,
                      "long"<BTYPE>,
                      "byte"<FULLTYPE>,
                      "string"<REPFACT>,
                      "half"<FULLTYPE>,
                      "short"<FULLTYPE>,
                      "record"'('<RFREF>')';

P<RT>               = "routine",
                      <XTYPE><FM>;

P<FM>               = "fn",
                      "map",
                      "function";

P<FPDEL>            = <XTYPE><Opt_AN_N_type><NAME><NAMES>,
                      <RT><Opt_N_type><NAME><NAMES><FPP>,
                      "name"<NAME><NAMES>;

P<Opt_N_type>          = "name",
                      '';

P<Opt_AN_N_type>         = "array""name",
                      "name",
                      '';

P<FPP>              = '('<FPDEL><MARK><RESTOFFPLIST>')',
                      '';

P<RESTOFFPLIST>     = ','<FPDEL><MARK><RESTOFFPLIST>,
                      '';

P<ENDLIST>          = "ofprogram"<UP>,
                      "offile",
                      "oflist"<LISTOFF>,
                      <UP>;   # of Rt/Fn/Map or begin block

P<PC_FORMATQ>       = "format",
                      '';

P<SC>               = <EXPR><COMP1><EXPR><RESTOFSC>,
                      '('<SC><RESTOFCOND>')',
                      "not"<SC>;


P<RESTOFSC>         = <COMP2><EXPR>,
                      '';

P<RESTOFCOND>       = "and"<SC><RESTOFANDC>,
                      "or"<SC><RESTOFORC>,
                      '';

P<RESTOFANDC>       = "and"<SC><RESTOFANDC>,
                      '';

P<RESTOFORC>        = "or"<SC><RESTOFORC>,
                      '';

P<RESTOFUI>         = <ASSOP><EXPR>,
                      # ':' was here.  Moved to <UI>. Maybe try putting back now everything else is fixed...
                      '';

P<Opt_RtFnMapSpec>  = "spec",
                      <SET_DOWN_FLAG>;

P<VSPECQ>           = "spec",
                      '';

P<RESTOFBPLIST>     = ','<EXPR>':'<EXPR><RESTOFBPLIST>,
                      '';

P<DECLN>            = <Opt_AN_N_type><NAME><NAMES>,
                      "array"<PC_FORMATQ><ADECLN>;

P<ADECLN>           = <NAME><NAMES><BPAIR><RESTOFARLIST>;

P<RESTOFARLIST>     = ','<ADECLN>,
                      '';


P<OWNDEC>           = <Opt_AN_N_type><VSPECQ><NAME><ALIASQ><Opt_Const_Init><MARK><RESTOFOWNDEC>,
                      "array"<PC_FORMATQ><VSPECP><NAME><ALIASP><BPAIR><CONSTLIST> ;

P<RESTOFOWNDEC>     = ','<READLINEP><NAME><ALIASP><Opt_Const_Init><MARK><RESTOFOWNDEC>,
                      '';

P<XOWN>             = "own",
                      "external",
                      "extrinsic",
                      "constant",
                      "const";

P<CONSTLIST>        = '='<READLINEP>
                      <UOP><COPERAND><RESTOFCEXPR><REPFACT><ROCL>,
                      '';

P<ROCL>             = ','<READLINEP><UOP><COPERAND><RESTOFCEXPR><REPFACT><ROCL>,
                      '';

P<REPFACT>          = '('<STAROREXPR>')',
                      '';


P<RESTOFNLIST>      = ','<CEXPR><RESTOFNLIST>,
                      '';

P<PC_EVENTQ>        = "event",
                      '';

P<OPEXPR>           = ','<EXPR>,
                      '';

P<RESTOFSWLIST>     = ','<NAME><NAMES>'('<EXPR>':'<EXPR>')'<RESTOFSWLIST>,
                      '';

P<RESTOFREPEAT>     = "until"<SC><RESTOFCOND>,
                      '';

P<RESTOFSS1>        = <S>,
                      <PC_IU><SC><RESTOFCOND><S>,
                      <PC_WU><S>;

P<RESTOFIU>         = "start"<NOTESTART>,
                      "then""start"<NOTESTART>,
                      "then"<UI><MARK><ELSEQ>;

P<AUI>              = "and"<UI>,
                      '';

P<ELSEQ>            = "else"<AFTERELSE>,
                      '';

P<AFTERELSE>        = "start"<NOTESTART>,
                      <PC_IU><SC><RESTOFCOND><MARK><RESTOFIU>,
                      <UI>;

P<ENAMEQ>           = '_'<NAME><APP><ENAMEQ>,
                      '';

P<BPAIR>            = '('<EXPR>':'<EXPR><RESTOFBPLIST>')';

P<Opt_Const_Init>   = '='<UOP><COPERAND><RESTOFCEXPR>,
                      '';

P<SEX>              = "system",
                      "external",
                      "dynamic",
                      '';

P<CYCPARM>          = <NAME>'='<EXPR>','<EXPR>','<EXPR>,
                      '';

P<RESTOFRFDEC>      = ','<READLINEP><RFDEC><RESTOFRFDEC>,  # added <READLINEP>
                      '';

P<RFSTMNT>          = "spec"<NAME>,
                      <NAME>'('<RFDEC><RESTOFRFDEC><ALTRFDEC>')';

P<RFREF>            = <NAME>,
                      <RFDEC><RESTOFRFDEC><ALTRFDEC>;

P<RFDEC>            = <XTYPE><RFELMNT>,
                      '('<RFDEC><RESTOFRFDEC><ALTRFDEC>')';

P<RFELMNT>          = <Opt_AN_N_type><NAME><NAMES>,
                      "array"<ADECLN>;

P<ALTRFDEC>         = "or"<RFDEC><RESTOFRFDEC><ALTRFDEC>,
                      '';

P<ASM>              = <!semi> <!nl> <!eof> «.» <ASM>, '';   # TO DO: semicolons in an asm statement eg *LD_1,';'

P<UI>               = <NAME><APP><ENAMEQ><MARK><RESTOFUI><AUI>,
                      '->'<NAME><APP>,
                      "return",
                      "result"<ASSOP><EXPR>,
                      "monitor"<AUI>,
                      "stop",
                      "signal"<PC_EVENTQ><CEXPR><OPEXPR>,
                      "exit",
                      "continue";
                      
P<SS>               = <init> <Imp77_stropping> <STATEMENTS> <terminate> ;

##P<null>='';

P<More_STATEMENTS>  = <STATEMENT> <More_STATEMENTS>, '';
P<STATEMENTS>       = <STATEMENT> <More_STATEMENTS> <eof>;

P<STATEMENT>        = <NAME>'(*):'<COLON>,
                      <NAME>'('<EXPR>'):'<COLON>,
                      <NAME>':'<COLON>,
                      <CHUI><UI><MARK><RESTOFSS1>,
                      <Comment><S>,
                      <PC_IU><SC><RESTOFCOND><MARK><RESTOFIU><S>,
                      "finish"<NOTEFINISH><ELSEQ><S>,
                      "cycle"<NOTECYCLE><CYCPARM><S>,
                      "repeat"<NOTEREPEAT><RESTOFREPEAT><S>,
                      <PC_WU>"cycle"<NOTECYCLE><S>,
                      <XTYPE><MARK><DECLN><S>,
                      "end"<ENDLIST><S>,
                      "record""format"<RFSTMNT><S>,

                      # <Opt_RtFnMapSpec> pushes a scope level, but we want to
                      # add <NAME> to the name tables before pushing
                      # the new scope.  It's only *inside* the procedure
                      # body that we want to restrict declarations to the
                      # nested scope level.  So <Opt_RtFnMapSpec> should only set
                      # a flag, and the flag should be tested (and cleared)
                      # immediately after <NAME> is handled at the previous
                      # scope level.
                      <SEX><RT><MARK><Opt_RtFnMapSpec><NAME><ALIASQ><DOWNQ><FPP><S>,
                      <XOWN><XTYPE><OWNDEC><S>,
                      "include"<CONST><INCLUDE>,
                      "begin"<DOWN><S>,
                      "on"<TRACE><PC_EVENTQ><CEXPR><RESTOFNLIST>"start"<NOTESTART><S>,
                      "switch"<NAME><NAMES>'('<EXPR>':'<EXPR>')'<RESTOFSWLIST><S>,
                      "list"<S><LISTON>,
                      "else"<NOTEFINISH><DUMMYSTART><NOTESTART><S>,
                      '*'<ASM><S>,
                      "trustedprogram"<S>,
                      "mainep"<NAME><S>,
                      "control"<CONST><S>,
                      <S>;
E
