primary-expression: identifier constant string-literal ( expression ) postfix-expression: primary-expression postfix-expression [ expression ] postfix-expression ( argument-expression-listopt ) postfix-expression . identifier postfix-expression -> identifier postfix-expression ++ postfix-expression -- ( type-name ) { initializer-list } ( type-name ) { initializer-list , } argument-expression-list: assignment-expression argument-expression-list , assignment-expression unary-expression: postfix-expression ++ unary-expression -- unary-expression unary-operator cast-expression sizeof unary-expression sizeof ( type-name ) unary-operator: one of & * + - ~ ! cast-expression: unary-expression ( type-name ) cast-expression pow-expression: cast-expression cast-expression ** pow-expression ZZ fix doc, Operators section ZZ multiplicative-expression: pow-expression multiplicative-expression * pow-expression multiplicative-expression / pow-expression multiplicative-expression % pow-expression additive-expression: multiplicative-expression additive-expression + multiplicative-expression additive-expression - multiplicative-expression shift-expression: additive-expression shift-expression << additive-expression shift-expression >> additive-expression relational-expression: shift-expression relational-expression < shift-expression relational-expression > shift-expression relational-expression <= shift-expression relational-expression >= shift-expression equality-expression: relational-expression equality-expression == relational-expression equality-expression != relational-expression AND-expression: equality-expression AND-expression & equality-expression exclusive-OR-expression: AND-expression exclusive-OR-expression ^ AND-expression inclusive-OR-expression: exclusive-OR-expression inclusive-OR-expression | exclusive-OR-expression logical-AND-expression: inclusive-OR-expression logical-AND-expression && inclusive-OR-expression logical-OR-expression: logical-AND-expression logical-OR-expression || logical-AND-expression conditional-expression: logical-OR-expression logical-OR-expression ? expression : conditional-expression assignment-expression: conditional-expression unary-expression assignment-operator assignment-expression assignment-operator: one of = *= /= %= += -= <<= >>= &= ^= |= expression: assignment-expression expression , assignment-expression constant-expression: conditional-expression A.2.2 Declarations --- declaration: declaration-specifiers init-declarator-listopt ; declaration-specifiers: storage-class-specifier declaration-specifiersopt type-specifier declaration-specifiersopt type-qualifier declaration-specifiersopt function-specifier declaration-specifiersopt init-declarator-list: init-declarator init-declarator-list , init-declarator init-declarator: declarator declarator = initializer storage-class-specifier: typedef extern static auto register type-specifier: void char short int long float double signed unsigned _Bool _Complex _Imaginary struct-or-union-specifier enum-specifier typedef-name struct-or-union-specifier: struct-or-union identifieropt { struct-declaration-list } struct-or-union identifier struct-or-union: struct union struct-declaration-list: struct-declaration struct-declaration-list struct-declaration struct-declaration: specifier-qualifier-list struct-declarator-list ; specifier-qualifier-list: type-specifier specifier-qualifier-listopt type-qualifier specifier-qualifier-listopt struct-declarator-list: struct-declarator struct-declarator-list , struct-declarator struct-declarator: declarator declaratoropt : constant-expression enum-specifier: enum identifieropt { enumerator-list } enum identifieropt { enumerator-list , } enum identifier enumerator-list: enumerator enumerator-list , enumerator enumerator: enumeration-constant enumeration-constant = constant-expression type-qualifier: const restrict volatile function-specifier: inline declarator: pointeropt direct-declarator direct-declarator: identifier ( declarator ) direct-declarator [ type-qualifier-listopt assignment-expressionopt ] direct-declarator [ static type-qualifier-listopt assignment-expression ] direct-declarator [ type-qualifier-list static assignment-expression ] direct-declarator [ type-qualifier-listopt * ] direct-declarator ( parameter-type-list ) direct-declarator ( identifier-listopt ) pointer: * type-qualifier-listopt * type-qualifier-listopt pointer type-qualifier-list: type-qualifier type-qualifier-list type-qualifier parameter-type-list: parameter-list parameter-list , ... parameter-list: parameter-declaration parameter-list , parameter-declaration parameter-declaration: declaration-specifiers declarator declaration-specifiers abstract-declaratoropt identifier-list: identifier identifier-list , identifier type-name: specifier-qualifier-list abstract-declaratoropt abstract-declarator: pointer pointeropt direct-abstract-declarator direct-abstract-declarator: ( abstract-declarator ) direct-abstract-declaratoropt [ assignment-expressionopt ] direct-abstract-declaratoropt [ * ] direct-abstract-declaratoropt ( parameter-type-listopt ) typedef-name: identifier initializer: assignment-expression { initializer-list } { initializer-list , } initializer-list: designationopt initializer initializer-list , designationopt initializer designation: designator-list = designator-list: designator designator-list designator designator: [ constant-expression ] . identifier --- %{ /* batch spreadsheet processor */ #include #include #include #include #include #include #include #include "ss.h" #include "version.h" int yylex( void); /* to avoid gcc warnings */ extern char *fname; /* flex input file name */ extern int yylineno; /* flex input line number */ extern char *yytext; /* current text matched by flex */ extern int yy_flex_debug; /* flex debug flag */ int parse_cell(const char *,Cell *); /* from scan.l */ static FILE *prev_out; static int opt_fname = 0; static int set_out( char *fname); static void reset( void); /* reset out = prev_out, dir = prev_dir */ static void unknown_function( const char *name); /* calls yyerror() */ %} %union{ int ival; char *string; double number; Cell cell; Range range; Symbol *sym; Node *node; Expr_list *elist; } %token INTEGER DIR %token BYROWS BYCOLS %token CAST CAST_INT CAST_LONG CAST_DOUBLE %{ static int prev_dir = BYROWS; static int opt_dir = 0; %} /* "OR" operator (case-insensitive) could be column or symbol (case-sensitive) */ %token OR %token STRING COLUMN ID %token DOUBLE NUMBER %token CELL RCCELL %token RANGE RCRANGE A0RCRANGE RCA0RANGE %type String col fname %type cell range crange lval %type print_arg print_arg_list %type number /* snumber */ %type symbol %token UMINUS UPLUS POW_OP AND AND_OP OR_OP XOR XOR_OP NOT NOT_OP %token LT LE EQ NE GE GT SHL SHR %token PP PP_X X_PP MM MM_X X_MM %token NFUNC RFUNC ASGN_OP .so tmp/nf_tokens .so tmp/rf_tokens %token MUL_ASGN DIV_ASGN MOD_ASGN ADD_ASGN SUB_ASGN %token AND_ASGN XOR_ASGN OR_ASGN SHL_ASGN SHR_ASGN %token BIT_AND_ASGN BIT_XOR_ASGN BIT_OR_ASGN %token COPY DEBUG_CMD FILL SRAND PRINT EVAL RESET HELP PLOT2D PLOT3D FORMAT EXIT QUIT %token ON OFF OUTPUT STDOUT HEADERS %token PRINT_ARG %token A0 RC CR %token ALL CONSTANTS VALUES FORMULAS FUNCTIONS POINTERS FORMATS SYMBOLS STATES %type pri post unary cast pow mul add compare shift equal and or xor cond %type asgn expr asgn_or_range opt_asgn_or_range %type bit_and bit_xor bit_or %type expr_list lval_list fn_arg_list asgn_list %token EMPTY %token MAX_TOKEN /*** must be last token defined ***/ %% stmt: /* nothing */ | stmt ';' | stmt '{' lval_list '}' '=' NFUNC '(' fn_arg_list ')' ';' { add_func( $6, listify_ranges( $3), listify_ranges($8) ); } | stmt '{' lval_list '}' '=' RFUNC '(' fn_arg_list ')' ';' { add_func( $6, $3, $8); } | stmt '{' lval_list '}' '=' symbol '(' fn_arg_list ')' ';' { unknown_function( $6->name); } | stmt range '=' '{' expr_list '}' ';' { install_range( $2, listify_ranges($5), 1); } | stmt expr ';' { switch( $2->type) { case STRING: case NUMBER: case ID: case CELL: case RCCELL: case RANGE: case RCRANGE: case A0RCRANGE: case RCA0RANGE: /* no effect only if no assignments in expression? fprintf( out, "ss: ignoring expression with no effect\n"); */ break; /* operator or function: */ default: install_symbol( lookup_symbol(""), $2); break; } } | stmt command ';' { reset(); } | stmt error ';' { yyerrok; reset(); } ; command: HELP { func_help(0); } | HELP String { func_help($2); } | EXIT { exit(0); } | QUIT { exit(0); } | DEBUG_CMD ON { debug = 1; } | DEBUG_CMD INTEGER { debug = $2; } | DEBUG_CMD OFF { debug = 0; } | DEBUG_CMD { fprintf( out, "ss: debug level is %d\n", debug); } | HEADERS { fprintf( out, "ss: headers are %s\n", headers ? "on" : "off"); } | HEADERS ON { headers = 1; } | HEADERS OFF { headers = 0; } | COPY opt_dir crange crange { ss_copy( $3, $4); } | FILL opt_dir crange { ss_ttfill( $3); } | FILL opt_dir crange '{' expr_list '}' { ss_fill_expr_list( $3, $5); } | FILL opt_dir crange asgn_list { ss_fill( $3, $4); } | SRAND asgn { ss_srand( $2); } | OUTPUT fname { if( set_out( $2) && prev_out != stdout) fclose( prev_out); } | DIR { prev_dir = dir; dir = $1; } /* byrows or bycols command */ | PRINT opt_fname opt_dir { print_Range = used; ss_print( VALUES); } | PRINT opt_fname opt_dir { print_Range = used; } print_arg_list { } | PRINT opt_fname opt_dir ALL { print_Range = used; ss_print( SYMBOLS); ss_print( FORMULAS); ss_print( VALUES); } | PRINT opt_fname opt_dir crange { print_Range = $4->u.r; ss_print( VALUES); } | PRINT opt_fname opt_dir crange { print_Range = $4->u.r; } print_arg_list { } | PRINT opt_fname opt_dir crange ALL { print_Range = $4->u.r; ss_print( SYMBOLS); ss_print( FORMULAS); ss_print( VALUES); } | PLOT2D opt_fname opt_dir { ss_plot2d( 0); } | PLOT2D opt_fname opt_dir crange { ss_plot2d( $4); } | PLOT3D opt_fname opt_dir { ss_plot3d( 0); } | PLOT3D opt_fname opt_dir crange { ss_plot3d( $4); } | EVAL opt_dir { ss_eval( 0, -1, EVAL_ALL); } | EVAL opt_dir INTEGER { ss_eval( 0, $3, EVAL_ALL); } | EVAL opt_dir crange { ss_eval( $3, -1, EVAL_RANGE); } | EVAL opt_dir crange INTEGER { ss_eval( $3, $4, EVAL_RANGE); } | EVAL opt_dir crange SYMBOLS { ss_eval( $3, -1, EVAL_RANGE_SYMS); } | EVAL opt_dir crange SYMBOLS INTEGER { ss_eval( $3, $5, EVAL_RANGE_SYMS); } | EVAL opt_dir SYMBOLS { ss_eval( 0, -1, EVAL_SYMS); } | EVAL opt_dir SYMBOLS INTEGER { ss_eval( 0, $4, EVAL_SYMS); } | EVAL opt_dir SYMBOLS crange { ss_eval( $4, -1, EVAL_SYMS_RANGE); } | EVAL opt_dir SYMBOLS crange INTEGER { ss_eval( $4, $5, EVAL_SYMS_RANGE); } | RESET { ss_eval_reset( 0, EVAL_ALL); } | RESET crange { ss_eval_reset( $2, EVAL_RANGE); } | RESET SYMBOLS { ss_eval_reset( 0, EVAL_SYMS); } | RESET crange SYMBOLS { ss_eval_reset( $2, EVAL_RANGE_SYMS); } | RESET SYMBOLS crange { ss_eval_reset( $3, EVAL_SYMS_RANGE); } | FORMAT A0 { print_Format = A0; } | FORMAT RC { print_Format = RC; } | FORMAT CR { print_Format = CR; } | FORMAT String { install_format( $2); } | FORMAT col String /* col is a string */ { Cell c; parse_cell( $2, &c); install_col_format( c.col, $3); } | FORMAT INTEGER String { install_row_format( $2, $3); } | FORMAT cell String { install_cell_format( $2, $3); } | FORMAT range String { install_range_format( $2, $3); } | FORMAT SYMBOLS String { install_symbol_format( $3); } ; print_arg_list: print_arg { ss_print( $1); } | print_arg_list print_arg { ss_print( $2); } | print_arg_list ',' print_arg { ss_print( $3); } ; print_arg: /* SYMBOLS can also appear in FORMAT and EVAL commands */ PRINT_ARG | SYMBOLS { $$ = SYMBOLS; } ; symbol: ID { $$ = lookup_symbol( $1); } | COLUMN { $$ = lookup_symbol( $1); } | RC { $$ = lookup_symbol( "RC"); } | CR { $$ = lookup_symbol( "CR"); } | ON { $$ = lookup_symbol( "on"); } | OR { $$ = lookup_symbol( "$1"); } ; col: COLUMN | RC { $$ = "RC"; } | CR { $$ = "CR"; } | ON { $$ = "on"; } | OR { $$ = "or"; } ; opt_dir: /* nothing */ | DIR { opt_dir = 1; prev_dir = dir; dir = $1; } ; opt_fname: /* nothing */ | fname { opt_fname = set_out( $1); } ; fname: String | STDOUT { $$ = "stdout"; } | '-' { $$ = "stdout"; } ; /* concatencate adjacent literal strings */ String: STRING | String STRING { $$ = estrcat( $1, $2); } ; /* pri, post, and unary are like the C spec primary, postfix, and unary expressions */ pri: symbol { $$ = add_symbol( $1); } | cell | number { $$ = add_number( $1); } /* | String { $$ = add_string( $1); } */ | '(' expr ')' { $$ = $2; } /* Since { expr_list } is used for range assignments, * maybe should also allow single expressions. * But this conflicts with the lval_list statement | '{' expr '}' { $$ = $2; } */ ; post: pri | NFUNC '(' ')' { $$ = add_func( $1, 0, 0); } | NFUNC '(' fn_arg_list ')' { $$ = add_func( $1, 0, listify_ranges($3) ); } | RFUNC '(' fn_arg_list ')' { $$ = add_func( $1, 0, $3); } | symbol '(' ')' { unknown_function( $1->name); YYERROR; } | symbol '(' fn_arg_list ')' { unknown_function( $1->name); YYERROR; } | post PP { $$ = add_op( X_PP, $1, 0); } | post MM { $$ = add_op( X_MM, $1, 0); } ; /* expr_list can contain empty entries, e.g. { 1,,3 } but fn_arg_list can not */ fn_arg_list: asgn_or_range { $$ = new_expr_list( $1); } | fn_arg_list ',' asgn_or_range { append_expr_list( $1, $3); } ; asgn_or_range: asgn | range ; expr_list: opt_asgn_or_range { $$ = new_expr_list( $1); } | expr_list ',' opt_asgn_or_range { append_expr_list( $1, $3); } ; opt_asgn_or_range: asgn | range | /* nothing */ { $$ = add_empty(); } ; /* for date/time FILL command */ asgn_list: asgn { $$ = new_expr_list( $1); } | asgn_list ',' asgn { append_expr_list( $1, $3); } ; /* to allow a cell to specify a single-cell range */ crange: cell { $$ = rangeify( $1); } | range ; lval_list: lval { $$ = new_expr_list( $1); } | lval_list ',' lval { append_expr_list( $1, $3); } ; lval: symbol { $$ = add_symbol( $1); } | cell | range ; unary: post | '+' cast { $$ = $2; } | '-' cast { if( $2->type == NUMBER) /* negate number */ { $2->u.val = -$2->u.val; $$ = $2; } else if( $2->type == UMINUS) /* cancel two minuses */ { $$ = Right($2); free( $2); } else { $$ = add_op( UMINUS, 0, $2); } } | '~' cast { $$ = add_op( '~', 0, $2); } | NOT_OP cast { $$ = add_op( NOT_OP, 0, $2); } | NOT cast { $$ = add_op( NOT, 0, $2); } | PP unary { $$ = add_op( PP_X, 0, $2); } | MM unary { $$ = add_op( MM_X, 0, $2); } ; cast: unary | '(' CAST ')' cast { $$ = add_op( $2, 0, $4); } ; ; /* mul, add, etc. follow C spec */ mul: pow | mul '*' pow { $$ = add_op( '*', $1, $3); } | mul '/' pow { $$ = add_op( '/', $1, $3); } | mul '%' pow { $$ = add_op( '%', $1, $3); } ; add: mul | add '+' mul { $$ = add_op( '+', $1, $3); } | add '-' mul { $$ = add_op( '-', $1, $3); } ; shift: add | shift SHL add { $$ = add_op( SHL, $1, $3); } | shift SHR add { $$ = add_op( SHR, $1, $3); } ; compare: shift | compare LT shift { $$ = add_op( LT, $1, $3); } | compare LE shift { $$ = add_op( LE, $1, $3); } | compare GT shift { $$ = add_op( GT, $1, $3); } | compare GE shift { $$ = add_op( GE, $1, $3); } ; equal: compare | equal EQ compare { $$ = add_op( EQ, $1, $3); } | equal NE compare { $$ = add_op( NE, $1, $3); } ; bit_and: equal | bit_and '&' equal { $$ = add_op( '&', $1, $3 ); } ; bit_xor: bit_and | bit_xor '^' bit_and { $$ = add_op( '^', $1, $3 ); } ; bit_or: bit_xor | bit_or '|' bit_xor { $$ = add_op( '|', $1, $3 ); } ; and: bit_or | and AND_OP bit_or { $$ = add_op( AND_OP, $1, $3 ); } | and AND bit_or { $$ = add_op( AND, $1, $3 ); } ; xor: and | xor XOR_OP and { $$ = add_op( XOR_OP, $1, $3 ); } | xor XOR and { $$ = add_op( XOR, $1, $3 ); } ; or: xor | or OR_OP xor { $$ = add_op( OR_OP, $1, $3 ); } | or OR xor { $$ = add_op( OR, $1, $3 ); } ; cond: or | or '?' expr ':' cond { $$ = add_cond( $1, $3, $5); } ; /* to follow C spec would use: pri ASGN_OP asgn * but ss only allows cell, range or symbol as lval */ asgn: cond | String { $$ = add_string( $1); } | symbol '=' asgn { $$ = add_symbol( $1); install_symbol( $1, $3); } | symbol ASGN_OP asgn { $$ = add_symbol( $1); install_symbol( $1, add_op( $2, $$, $3)); } | cell '=' asgn { install_cell( $1, $3, 1, 1); } | cell ASGN_OP asgn { install_cell( $1, add_op( $2, 0, $3), 1, 1); } ; expr: asgn | expr ',' asgn { $$ = add_op( ',', $1, $3); } ; cell: CELL { $$ = add_cell( &$1, CELL); } | RCCELL { $$ = add_cell( &$1, RCCELL); } | A0 { $$ = add_cell( &cell_00, CELL); } ; range: RANGE { $$ = add_range( &$1, RANGE); } | RCRANGE { $$ = add_range( &$1, RCRANGE); } | A0RCRANGE { $$ = add_range( &$1, A0RCRANGE); } | RCA0RANGE { $$ = add_range( &$1, RCA0RANGE); } ; number: DOUBLE | INTEGER { $$ = (double)$1; } ; %% static void unknown_function( const char *name) { char buf[128]; sprintf( buf, "unknown function: %.100s", name); yyerror( buf); } int yywrap( void) /* called at EOF */ { return 1; } static int set_out( char *fname) { FILE *f; if( strcmp( fname, "stdout") == 0 || strcmp( fname, "-") == 0) f = stdout; else f = fopen( fname, "w"); if( f == NULL) { char buf[256]; sprintf( buf, "%.100s: %.100s", fname, strerror( errno) ); yyerror( buf); return 0; } prev_out = out; out = f; return 1; } static void reset( void) { if( opt_fname) { if( out != stdout) fclose( out); out = prev_out; opt_fname = 0; } if( opt_dir) { dir = prev_dir; opt_dir = 0; } } /* called for parser syntax error */ void yyerror( const char *msg) { fprintf( out, "error:%s:%d: %s, text = %s\n", fname ? fname : "", yylineno, msg, yytext ? yytext : ""); } static void usage( void) { fprintf( stderr, "Usage: ss [-h|--help] [-d|--debug] [-v|--verbose]" " [--version]\n [-r|--rows #rows] [-c|--cols #cols]\n"); } int main( int argc, char *argv[]) { int verbose = 0, errors = 0; /* initialize rand() */ srand( time(0) ); /* set default output */ out = prev_out = stdout; /* disable flex and bison debug */ #if YYDEBUG yydebug = 0; #endif yy_flex_debug = 0; /* check args */ while( argc > 1) { if( strcmp( argv[1], "-d") == 0 || strcmp( argv[1], "--debug") == 0) { #if YYDEBUG yydebug = 1; #endif yy_flex_debug = 1; } else if( strcmp( argv[1], "-h") == 0 || strcmp( argv[1], "--help") == 0) { usage(); exit(0); } else if( strcmp( argv[1], "-v") == 0 || strcmp( argv[1], "--verbose") == 0) { ++verbose; } else if( strcmp( argv[1], "--version") == 0) { fprintf( out, "%s\n", version); exit(0); } else if( (strcmp( argv[1], "-r") == 0 || strcmp( argv[1], "--rows") == 0) && argc > 2) { --argc, ++argv; SS_MAXROWS = atoi( argv[1]); if( SS_MAXROWS <= 0) { ++errors; fprintf( out, "ss: bad #rows: %s\n", argv[1]); } } else if( (strcmp( argv[1], "-c") == 0 || strcmp( argv[1], "--cols") == 0) && argc > 2) { --argc, ++argv; SS_MAXCOLS = atoi( argv[1]); if( SS_MAXCOLS <= 0) { ++errors; fprintf( out, "ss: bad #cols: %s\n", argv[1]); } } else { ++errors; fprintf( out, "ss: bad option: %s\n", argv[1]); } --argc, ++argv; } if( verbose) { fprintf( out, "ss: rows 0...%d, cols 0...%d (A...", SS_MAXROWS-1, SS_MAXCOLS-1); print_col( SS_MAXCOLS-1); fprintf( out, ")\n"); } if( errors) { usage(); exit( errors); } /* initialize ss arrays */ init_ss(); /* initialize ss function table */ init_func(); /* initialize constants */ install_constant( "HUGE_VAL", HUGE_VAL); install_constant( "DBL_EPSILON", DBL_EPSILON); install_constant( "RAND_MAX", RAND_MAX); /* start parsing... */ yyparse(); return 0; }