_zero_arg_funs:
    GETCH
|
    GETPID
|
    GETS
;

_one_arg_funs:
    ASCII
|
    EVAL
|
    EXISTS
|
    LISTLEN
|
    ECHO_TOKEN
|
    CMD_TAIL
|
    CMD_HEAD
|
    ARG_HEAD
|
    ARG_TAIL
|
    G_BASE
|
    G_PATH
|
    G_EXT
|
    G_DEXT
|
    PUTENV
|
    GETENV
|
    STRLEN
|
    STRUPR
|
    STRLWR
|
    TRIM
|
    TRIMLEFT
|
    TRIMRIGHT
;

_two_arg_funs:
    C_EXT                           /* string, string */
|
    C_BASE
|
    C_PATH
|
    ELEMENT                         /* int, list | int, string */
|
    FGETS                           /* list fgets(string, int) */
|
    FIELDS                          /* string, string */
|
    LISTFIND                        /* list, string */
|
    LISTUNION                       /* list, list | list, string */
|
    STRCHR                          /* string, string */
|
    STRFIND                         /* string, string */
|
    RESIZE                          /* string, int */
;

_optint_string:
    STAT
|
    CHDIR
|
    SYSTEM
;

_comma_expr:
    ','
    err_expression
    {
        $$ = $2;
    }
|
    zeroframe
;

_optint_special:
    EXEC                                /* optional int allowed */
|
    EXECUTE
;

_comma_arglist:
    ','
    args
    {
        $$ = $2;
    }
|
    zeroframe
;

_opt_arglist:
    args
|
    zeroframe
;

_funname:
    IDENTIFIER
    {
        $$.evalue = p_functionIdx();
    }
;

function:
    _zero_arg_funs                       /* getch() or gets() */
    openpar
    {
        $$ = *p_zeroArgs($1.type);
    }
|
    _one_arg_funs
    openpar
    err_expression
    {
        $$ = *p_oneArg($1.type, &$3);
    }
|
    _two_arg_funs
    openpar
    err_expression
    comma
    err_expression
    {
        $$ = *p_twoArgs($1.type, &$3, &$5);
    }
|
    SUBSTR                              /* three arg function */
    openpar
    err_expression
    comma
    err_expression
    comma
    err_expression
    {
        $$ = *p_threeArgs($1.type, &$3, &$5, &$7);
    }
|
    _optint_string                      /* CHDIR, SYSTEM, STAT */
    openpar
    err_expression                      /* int inserted if string */
    _comma_expr                         /* may be string if first == int */
    {
        $$ = *p_optIntString($1.type, &$3, &$4);
    }
|
    _optint_special                     /* EXEC, EXECUTE */
    openpar                             /* alternatives: */
    err_expression                      /* fun(int, string, ...) */
    _comma_arglist                      /* fun(string, ...)       */
    {
        $$ = *p_optIntSpecial($1.type, &$3, &$4);
    }
|
    PRINTF
    openpar
    args                                /* first may be anything */
    {
        $$ = *p_specials(f_printf, &$3);
    }
|
    FPRINTF
    openpar
    args                                /* argcount >= 2 required */
    {
        $$ = *p_fprintf($1.type, &$3);
    }
|
    STRFORMAT
    openpar
    args                                /* first may be anything */
    {
        $$ = *p_specials(f_strformat, &$3);
    }
|
    _funname
    openpar
    _opt_arglist
    {
        $$ = *p_callFunction($1.evalue, &$3);
    }
|
    p_makeList
;
