LTP GCOV extension - code coverage report
Current view: directory - csrc/cl - grammar.y
Test: app.info
Date: 2007-12-10 Instrumented lines: 226
Code covered: 89.4 % Executed lines: 202

       1                 : %{
       2                 : /*
       3                 :         Copyright (C) 2007, Bruce Ediger
       4                 : 
       5                 :     This file is part of cl.
       6                 : 
       7                 :     cl is free software; you can redistribute it and/or modify
       8                 :     it under the terms of the GNU General Public License as published by
       9                 :     the Free Software Foundation; either version 2 of the License, or
      10                 :     (at your option) any later version.
      11                 : 
      12                 :     cl is distributed in the hope that it will be useful,
      13                 :     but WITHOUT ANY WARRANTY; without even the implied warranty of
      14                 :     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      15                 :     GNU General Public License for more details.
      16                 : 
      17                 :     You should have received a copy of the GNU General Public License
      18                 :     along with cl; if not, write to the Free Software
      19                 :     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
      20                 : 
      21                 : */
      22                 : #include <stdio.h>
      23                 : #include <errno.h>    /* errno */
      24                 : #include <string.h>   /* strerror() */
      25                 : #include <stdlib.h>   /* malloc(), free(), strtoul() */
      26                 : #include <unistd.h>   /* getopt() */
      27                 : #include <signal.h>   /* signal(), etc */
      28                 : #include <setjmp.h>   /* setjmp(), longjmp(), jmp_buf */
      29                 : #include <sys/time.h> /* gettimeofday(), struct timeval */
      30                 : 
      31                 : extern char *optarg;
      32                 : 
      33                 : #include <node.h>
      34                 : #include <hashtable.h>
      35                 : #include <atom.h>
      36                 : #include <graph.h>
      37                 : #include <abbreviations.h>
      38                 : #include <spine_stack.h>
      39                 : #include <bracket_abstraction.h>
      40                 : 
      41                 : #ifdef YYBISON
      42                 : #define YYERROR_VERBOSE
      43                 : #endif
      44                 : 
      45                 : /* flags, binary on/off for various outputs */
      46                 : int debug_reduction  = 0;
      47                 : int elaborate_output = 0;
      48                 : int trace_reduction  = 0;
      49                 : int reduction_timer  = 0;
      50                 : int single_step      = 0;
      51                 : int memory_info      = 0;
      52                 : int count_reductions = 0;    /* produce a count of reductions */
      53                 : 
      54                 : int reduction_timeout = 0;   /* how long to let a graph reduction run, seconds */
      55                 : int max_reduction_count = 0; /* when non-zero, how many reductions to perform */
      56                 : 
      57                 : int prompting = 1;
      58                 : 
      59                 : /* Signal handling.  in_reduce_graph used to (a) handle
      60                 :  * contrl-C interruptions (b) reduction-run-time timeouts,
      61                 :  * (c) getting out of single-stepped graph reduction in reduce_graph()
      62                 :  */
      63                 : void sigint_handler(int signo);
      64                 : sigjmp_buf in_reduce_graph;
      65                 : int interpreter_interrupted = 0;
      66                 : int reduction_interrupted = 0;
      67                 : 
      68                 : void top_level_cleanup(int syntax_error_processing);
      69                 : 
      70                 : struct node *reduce_tree(struct node *root);
      71                 : struct node *execute_bracket_abstraction(
      72                 :         struct node *(*bafunc)(struct node *, struct node *),
      73                 :         struct node *abstracted_var,
      74                 :         struct node *root
      75                 : );
      76                 : float elapsed_time(struct timeval before, struct timeval after);
      77                 : void usage(char *progname);
      78                 : 
      79                 : struct filename_node {
      80                 :         const char *filename;
      81                 :         struct filename_node *next;
      82                 : };
      83                 : 
      84                 : /* from lex.l */
      85                 : extern void set_yyin_stdin(void); 
      86                 : extern void set_yyin(const char *filename); 
      87                 : extern void reset_yyin(void);
      88                 : extern void  push_and_open(const char *filename);
      89                 : 
      90                 : extern int yylex(void);
      91                 : int yyerror(char *s1);
      92                 : 
      93                 : /* Various "treat as combinator" flags.
      94                 :  * For example: S_as_combinator, when set (default) causes
      95                 :  * the lexer to treat "S" as an S-combinator.  When unset,
      96                 :  * the lexer treats "S" as any other variable. This can interact
      97                 :  * strangely with bracket abstraction, which assumes that its
      98                 :  * own use of "S" (again, as example) always constitutes a combinator.
      99                 :  */
     100                 : int S_as_combinator = 1;
     101                 : int K_as_combinator = 1;
     102                 : int I_as_combinator = 1;
     103                 : int B_as_combinator = 1;
     104                 : int C_as_combinator = 1;
     105                 : int W_as_combinator = 1;
     106                 : int T_as_combinator = 1;
     107                 : int M_as_combinator = 1;
     108                 : 
     109                 : %}
     110                 : 
     111                 : %union{
     112                 :         const char *identifier;
     113                 :         const char *string_constant;
     114                 :         int   numerical_constant;
     115                 :         struct node *node;
     116                 :         enum combinatorName cn;
     117                 :         struct node *(*bafunc)(struct node *, struct node *);
     118                 : }
     119                 : 
     120                 : 
     121                 : %token <node> TK_EOL
     122                 : %token TK_LPAREN TK_RPAREN TK_LBRACK TK_RBRACK
     123                 : %token <identifier> TK_IDENTIFIER
     124                 : %token <cn> TK_PRIMITIVE
     125                 : %token <string_constant> STRING_LITERAL
     126                 : %token <node> TK_REDUCE TK_TIMEOUT
     127                 : %token <numerical_constant> NUMERICAL_CONSTANT
     128                 : %token <identifier> TK_ALGORITHM_NAME
     129                 : %token TK_DEF TK_TIME TK_LOAD TK_ELABORATE TK_TRACE TK_SINGLE_STEP TK_DEBUG
     130                 : %token TK_MAX_COUNT TK_SET_BRACKET_ABSTRACTION 
     131                 : 
     132                 : %type <node> expression stmnt application term constant interpreter_command
     133                 : %type <node> bracket_abstraction 
     134                 : %type <bafunc> abstraction_algorithm
     135                 : 
     136                 : %%
     137                 : 
     138                 : program
     139              69 :         : stmnt { top_level_cleanup(0); }
     140              69 :         | program stmnt { top_level_cleanup(0); }
     141            5737 :         | error  /* magic token - yacc unwinds to here on syntax error */
     142              12 :                 { top_level_cleanup(1); }
     143              12 :         ;
     144                 : 
     145                 : stmnt
     146                 :         : expression TK_EOL
     147                 :                 {
     148             306 :                         print_graph($1, 0, 0); 
     149             306 :                         $$ = reduce_tree($1);
     150             305 :                         if (!reduction_interrupted)
     151             297 :                                 print_graph($$->left, 0, 0);
     152             305 :                         free_node($$);
     153                 :                 }
     154             305 :         | TK_DEF TK_IDENTIFIER expression TK_EOL
     155                 :                 {
     156            5145 :                         abbreviation_add($2, $3);
     157            5145 :                         ++$3->refcnt;
     158            5145 :                         free_node($3);
     159                 :                 }
     160            5145 :         | interpreter_command
     161             331 :         | TK_EOL  { $$ = NULL; /* blank lines */ }
     162             331 :         ;
     163                 : 
     164                 : interpreter_command
     165               4 :         : TK_TIME TK_EOL { reduction_timer ^= 1; }
     166               4 :         | TK_ELABORATE TK_EOL { elaborate_output ^= 1; }
     167               3 :         | TK_DEBUG TK_EOL { debug_reduction ^= 1; }
     168               3 :         | TK_TRACE TK_EOL { trace_reduction ^= 1; }
     169               3 :         | TK_SINGLE_STEP TK_EOL { single_step ^= 1; }
     170               3 :         | TK_LOAD STRING_LITERAL TK_EOL { push_and_open($2); }
     171               1 :         | TK_TIMEOUT NUMERICAL_CONSTANT TK_EOL { reduction_timeout = $2; }
     172               4 :         | TK_MAX_COUNT NUMERICAL_CONSTANT TK_EOL { max_reduction_count = $2; }
     173               3 :         | TK_SET_BRACKET_ABSTRACTION TK_ALGORITHM_NAME TK_EOL { default_bracket_abstraction = determine_bracket_abstraction($2); }
     174               1 :         ;
     175                 : 
     176                 : expression
     177           20304 :         : application          { $$ = $1; }
     178           20304 :         | term                 { $$ = $1; }
     179            1813 :         | TK_REDUCE expression
     180                 :                 {
     181                 :                         struct node *tmp;
     182              79 :                         tmp = reduce_tree($2);
     183              79 :                         --tmp->left->refcnt;
     184              79 :                         $$ = tmp->left;
     185              79 :                         tmp->left = NULL;
     186              79 :                         free_node(tmp);
     187                 :                 }
     188              79 :         | bracket_abstraction abstraction_algorithm expression
     189                 :                 {
     190             177 :                         $$ = execute_bracket_abstraction($2, $1, $3);
     191             177 :                         ++$1->refcnt;
     192             177 :                         free_node($1);
     193             177 :                         ++$3->refcnt;
     194             177 :                         free_node($3);
     195                 :                 }
     196             177 :         ;
     197                 : 
     198                 : abstraction_algorithm
     199              88 :         : TK_ALGORITHM_NAME  { $$ = determine_bracket_abstraction($1); }
     200              88 :         | { $$ = default_bracket_abstraction; }
     201              89 :         ;
     202                 : 
     203                 : application
     204           20304 :         : term term        { $$ = new_application($1, $2); }
     205           20304 :         | application term { $$ = new_application($1, $2); }
     206           56123 :         ;
     207                 : 
     208                 : bracket_abstraction
     209                 :         : TK_LBRACK TK_IDENTIFIER TK_RBRACK
     210             177 :                 { $$ = new_term($2); }
     211             177 :         ;
     212                 : 
     213                 : term
     214           80730 :         : constant                         { $$ = $1; }
     215           80730 :         | TK_IDENTIFIER
     216                 :                 {
     217            1153 :                         $$ = abbreviation_lookup($1);
     218            1153 :                         if (!$$)
     219             541 :                                 $$ = new_term($1);
     220                 :                 }
     221            1153 :         | TK_LPAREN expression TK_RPAREN  { $$ = $2; }
     222           16662 :         ;
     223                 : 
     224                 : constant
     225           80730 :         : TK_PRIMITIVE  { $$ = new_combinator($1); }
     226                 :         ;
     227                 : 
     228                 : %%
     229                 : 
     230                 : int
     231                 : main(int ac, char **av)
     232              71 : {
     233                 :         int c, r;
     234              71 :         struct filename_node *p, *load_files = NULL, *load_tail = NULL;
     235              71 :         struct hashtable *h = init_hashtable(64, 10);
     236                 :         struct node *(*dba)(struct node *, struct node *);
     237                 :         extern int yyparse();
     238                 : 
     239              71 :         setup_abbreviation_table(h);
     240              71 :         setup_atom_table(h);
     241                 : 
     242             217 :         while (-1 != (c = getopt(ac, av, "deL:mN:pstT:C:B:x")))
     243                 :         {
     244              76 :                 switch (c)
     245                 :                 {
     246                 :                 case 'd':
     247               2 :                         debug_reduction = 1;
     248               2 :                         break;
     249                 :                 case 'e':
     250               1 :                         elaborate_output = 1;
     251               1 :                         break;
     252                 :                 case 'L':
     253               2 :                         p = malloc(sizeof(*p));
     254               2 :                         p->filename = Atom_string(optarg);
     255               2 :                         p->next = NULL;
     256               2 :                         if (load_tail)
     257               0 :                                 load_tail->next = p;
     258               2 :                         load_tail = p;
     259               2 :                         if (!load_files)
     260               2 :                                 load_files = p;
     261               2 :                         break;
     262                 :                 case 'm':
     263               2 :                         memory_info = 1;
     264               2 :                         break;
     265                 :                 case 'p':
     266              56 :                         prompting = 0;
     267              56 :                         break;
     268                 :                 case 's':
     269               1 :                         single_step = 1;
     270               1 :                         break;
     271                 :                 case 'T':
     272               0 :                         reduction_timeout = strtol(optarg, NULL, 10);
     273               0 :                         break;
     274                 :                 case 't':
     275               2 :                         trace_reduction = 1;
     276               2 :                         break;
     277                 :                 case 'x':
     278               1 :                         usage(av[0]);
     279               1 :                         exit(0);
     280                 :                         break;
     281                 :                 case 'B':
     282               1 :                         dba = determine_bracket_abstraction(optarg);
     283               1 :                         if (dba) default_bracket_abstraction = dba;
     284                 :                         else {
     285               0 :                                 fprintf(stderr, "Unknown bracket abstraction algoritm \"%s\"\n", optarg);
     286               0 :                                 usage(av[0]);
     287                 :                         }
     288               1 :                         break;
     289                 :                 case 'C':
     290                 :                         /* Turn *off* selected combinators: they become mere identifiers */
     291               8 :                         switch(optarg[0])
     292                 :                         {
     293                 :                         case 'S':
     294               1 :                                 S_as_combinator = 0;
     295               1 :                                 break;
     296                 :                         case 'K':
     297               1 :                                 K_as_combinator = 0;
     298               1 :                                 break;
     299                 :                         case 'I':
     300               1 :                                 I_as_combinator = 0;
     301               1 :                                 break;
     302                 :                         case 'B':
     303               1 :                                 B_as_combinator = 0;
     304               1 :                                 break;
     305                 :                         case 'C':
     306               1 :                                 C_as_combinator = 0;
     307               1 :                                 break;
     308                 :                         case 'W':
     309               1 :                                 W_as_combinator = 0;
     310               1 :                                 break;
     311                 :                         case 'M':
     312               1 :                                 M_as_combinator = 0;
     313               1 :                                 break;
     314                 :                         case 'T':
     315               1 :                                 T_as_combinator = 0;
     316               1 :                                 break;
     317                 :                         default:
     318               0 :                                 fprintf(stderr, "Unknown primitive combinator \"%s\"\n", optarg);
     319               0 :                                 usage(av[0]);
     320                 :                                 break;
     321                 :                         }
     322               8 :                         break;
     323                 :                 case 'N':
     324               0 :                         max_reduction_count = strtol(optarg, NULL, 10);
     325               0 :                         if (max_reduction_count < 0) max_reduction_count = 0;
     326                 :                         break;
     327                 :                 }
     328                 :         }
     329                 : 
     330              70 :         init_node_allocation(memory_info);
     331                 : 
     332              70 :         if (load_files)
     333                 :         {
     334                 :                 struct filename_node *t, *z;
     335               2 :                 int old_prompt = prompting;
     336               2 :                 prompting = 0;
     337               4 :                 for (z = load_files; z; z = t)
     338                 :                 {
     339                 :                         FILE *fin;
     340                 : 
     341               2 :                         t = z->next;
     342                 : 
     343               2 :                         printf("load file named \"%s\"\n",
     344                 :                                 z->filename);
     345                 : 
     346               2 :                         if (!(fin = fopen(z->filename, "r")))
     347                 :                         {
     348               0 :                                 fprintf(stderr, "Problem reading \"%s\": %s\n",
     349                 :                                         z->filename, strerror(errno));
     350               0 :                                 continue;
     351                 :                         }
     352                 : 
     353               2 :                         set_yyin(z->filename);
     354                 : 
     355               2 :                         r = yyparse();
     356                 : 
     357               2 :                         reset_yyin();
     358                 : 
     359               2 :                         if (r)
     360               0 :                                 printf("Problem with file \"%s\"\n", z->filename);
     361                 : 
     362               2 :                         free(z);
     363               2 :                         fin = NULL;
     364                 :                 }
     365               2 :                 prompting = old_prompt;
     366                 :         }
     367                 : 
     368              70 :         set_yyin_stdin();
     369                 : 
     370                 :         do {
     371              70 :                 if (prompting) printf("CL> ");
     372              70 :                 r =  yyparse();
     373              69 :         } while (r);
     374              69 :         if (prompting) printf("\n");
     375                 : 
     376              69 :         if (memory_info) fprintf(stderr, "Memory usage indicators:\n");
     377              69 :         free_all_nodes(memory_info);
     378              69 :         free_hashtable(h);
     379              69 :         free_all_spine_stacks(memory_info);
     380                 : 
     381              69 :         return r;
     382                 : }
     383                 : 
     384                 : void top_level_cleanup(int syntax_error_occurred)
     385            5818 : {
     386            5818 :         reset_node_allocation();
     387            5818 :         reduction_interrupted = 0;
     388            5818 :         if (prompting && !syntax_error_occurred) printf("CL> ");
     389            5818 : }
     390                 : 
     391                 : int
     392                 : yyerror(char *s1)
     393               6 : {
     394               6 :     fprintf(stderr, "%s\n", s1);
     395                 : 
     396               6 :     return 0;
     397                 : }
     398                 : 
     399                 : 
     400                 : void
     401                 : sigint_handler(int signo)
     402               7 : {
     403                 :         /* the "return value" of 1 or 2 comes out in the
     404                 :          * call to sigsetjmp() in reduce_tree().
     405                 :          */
     406               7 :         siglongjmp(in_reduce_graph, signo == SIGINT? 1: 2);
     407                 : }
     408                 : 
     409                 : /*
     410                 :  * Function reduce_tree() exists to wrap reduce_graph()
     411                 :  * at the topmost level.  It wraps with setting signal handlers,
     412                 :  * taking before & after timestamps, setting jmp_buf structs, etc.
     413                 :  */
     414                 : struct node *
     415                 : reduce_tree(struct node *real_root)
     416             385 : {
     417                 :         void (*old_sigint_handler)(int);
     418                 :         void (*old_sigalm_handler)(int);
     419                 :         struct timeval before, after;
     420                 :         int cc;
     421             385 :         struct node *new_root = new_application(real_root, NULL);
     422                 : 
     423                 :         /* new_root - points to a "dummy" node, necessary for I and
     424                 :          * K reductions, if the expression is something like "I x" or
     425                 :          * K a b. */
     426             385 :         ++new_root->refcnt;
     427             385 :         MARK_RIGHT_BRANCH_TRAVERSED(new_root);
     428                 : 
     429             385 :         old_sigint_handler = signal(SIGINT, sigint_handler);
     430             385 :         old_sigalm_handler = signal(SIGALRM, sigint_handler);
     431                 : 
     432             385 :         if (!(cc = sigsetjmp(in_reduce_graph, 1)))
     433                 :         {
     434             385 :                 alarm(reduction_timeout);
     435             385 :                 gettimeofday(&before, NULL);
     436             385 :                 reduce_graph(new_root);
     437             374 :                 alarm(0);
     438             374 :                 gettimeofday(&after, NULL);
     439                 :         } else {
     440              10 :                 const char *phrase = "Unset";
     441              10 :                 alarm(0);
     442              10 :                 gettimeofday(&after, NULL);
     443              10 :                 switch (cc)
     444                 :                 {
     445                 :                 case 1:
     446               4 :                         phrase = "Interrupt";
     447               4 :                         reduction_interrupted = 1;
     448               4 :                         break;
     449                 :                 case 2:
     450               3 :                         reduction_interrupted = 1;
     451               3 :                         phrase = "Timeout";
     452               3 :                         break;
     453                 :                 case 3:
     454               1 :                         phrase = "Terminated";
     455               1 :                         reduction_interrupted = 1;
     456               1 :                         break;
     457                 :                 case 4:
     458               2 :                         phrase = "Reduction limit";
     459               2 :                         reduction_interrupted = 0;
     460               2 :                         break;
     461                 :                 default:
     462               0 :                         phrase = "Unknown";
     463                 :                         break;
     464                 :                 }
     465              10 :                 printf("%s\n", phrase);
     466              10 :                 ++interpreter_interrupted;
     467                 :         }
     468                 : 
     469             384 :         signal(SIGINT, old_sigint_handler);
     470             384 :         signal(SIGALRM, old_sigalm_handler);
     471                 : 
     472             384 :         if (reduction_timer)
     473               3 :                 printf("elapsed time %.3f seconds\n", elapsed_time(before, after));
     474                 : 
     475             384 :         return new_root;
     476                 : }
     477                 : 
     478                 : /*
     479                 :  * Function execute_bracket_abstraction() exists to wrap various bracket
     480                 :  * abstraction functions.  It wraps with setting signal handlers,
     481                 :  * taking before & after timestamps, setting jmp_buf structs, etc.
     482                 :  */
     483                 : struct node *
     484                 : execute_bracket_abstraction(
     485                 :         struct node *(*bafunc)(struct node *, struct node *),
     486                 :         struct node *abstracted_var,
     487                 :         struct node *root
     488                 : )
     489             177 : {
     490             177 :         struct node *r = NULL;
     491                 :         void (*old_sigint_handler)(int);
     492                 :         void (*old_sigalm_handler)(int);
     493                 :         struct timeval before, after;
     494                 :         int cc;
     495                 : 
     496             177 :         old_sigint_handler = signal(SIGINT, sigint_handler);
     497             177 :         old_sigalm_handler = signal(SIGALRM, sigint_handler);
     498                 : 
     499             177 :         if (!(cc = sigsetjmp(in_reduce_graph, 1)))
     500                 :         {
     501             177 :                 alarm(reduction_timeout);
     502             177 :                 gettimeofday(&before, NULL);
     503             177 :                 r = (bafunc)(abstracted_var, root);
     504             177 :                 alarm(0);
     505             177 :                 gettimeofday(&after, NULL);
     506                 :         } else {
     507               0 :                 const char *phrase = "Unset";
     508               0 :                 alarm(0);
     509               0 :                 gettimeofday(&after, NULL);
     510               0 :                 switch (cc)
     511                 :                 {
     512               0 :                 case 1: phrase = "Interrupt"; break;
     513               0 :                 case 2: phrase = "Timeout";   break;
     514               0 :                 case 3: phrase = "Terminated";break;
     515                 :                 default:
     516               0 :                         phrase = "Unknown";
     517                 :                         break;
     518                 :                 }
     519               0 :                 printf("%s\n", phrase);
     520                 :         }
     521                 : 
     522             177 :         signal(SIGINT, old_sigint_handler);
     523             177 :         signal(SIGALRM, old_sigalm_handler);
     524                 : 
     525             177 :         if (reduction_timer)
     526               1 :                 printf("elapsed time %.3f seconds\n", elapsed_time(before, after));
     527                 : 
     528             177 :         return r;
     529                 : }
     530                 : 
     531                 : /* utility function elapsed_time() */
     532                 : float
     533                 : elapsed_time(struct timeval before, struct timeval after)
     534               4 : {
     535               4 :         float r = 0.0;
     536                 : 
     537               4 :         if (before.tv_usec > after.tv_usec)
     538                 :         {
     539               0 :                 after.tv_usec += 1000000;
     540               0 :                 --after.tv_sec;
     541                 :         }
     542                 : 
     543               4 :         r = (float)(after.tv_sec - before.tv_sec)
     544                 :                 + (1.0E-6)*(float)(after.tv_usec - before.tv_usec);
     545                 : 
     546               4 :         return r;
     547                 : }
     548                 : 
     549                 : void
     550                 : usage(char *progname)
     551               1 : {
     552               1 :         fprintf(stderr, "%s: Combinatory Logic like language interpreter\n",
     553                 :                 progname);
     554               1 :         fprintf(stderr, "Flags:\n"
     555                 :                 "-d             debug reductions\n"
     556                 :                 "-e             elaborate output\n"
     557                 :                 "-L  filename   Load and interpret a filenamed filename\n"
     558                 :                 "-m             on exit, print memory usage summary\n"
     559                 :                 "-N number      perform up to number reductions\n"
     560                 :                 "-s             single-step reductions\n"
     561                 :                 "-T number      evaluate an expression for up to number seconds\n"
     562                 :                 "-t             trace reductions\n"
     563                 :                 "-C combinator  treat combinator as a non-primitive. Combinator one of S, K, I, B, C, W, M, T\n"
     564                 :                 "-B algoritm    Use algorithm as default for bracket abstraction.  One of curry, tromp, grz, btmk\n"
     565                 :                 ""
     566                 :         );
     567               1 : }

Generated by: LTP GCOV extension version 1.6