home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 October / usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso / misc / volume6 / jcl < prev    next >
Text File  |  1989-02-03  |  27KB  |  1,162 lines

  1. Path: lll-winken!ames!mailrus!tut.cis.ohio-state.edu!ucbvax!unisoft!uunet!allbery
  2. From: allbery@uunet.UU.NET (Brandon S. Allbery - comp.sources.misc)
  3. Newsgroups: comp.sources.misc
  4. Subject: v06i036: JCL emulator
  5. Message-ID: <48165@uunet.UU.NET>
  6. Date: 4 Feb 89 03:18:19 GMT
  7. Sender: allbery@uunet.UU.NET
  8. Reply-To: lupton@uhccux.uhcc.Hawaii.Edu (Robert Lupton)
  9. Lines: 1150
  10. Approved: allbery@uunet.UU.NET (Brandon S. Allbery - comp.sources.misc)
  11.  
  12. Posting-number: Volume 6, Issue 36
  13. Submitted-by: lupton@uhccux.uhcc.Hawaii.Edu (Robert Lupton)
  14. Archive-name: jcl
  15.  
  16. [You always knew someone would do this...!  ;-)  ++bsa]
  17.  
  18. I wrote this a while ago, and have just found it on an old tape, so
  19. here it is. It emulates our favourite operating system, JCL. To use
  20. it, unpack the shar file, run make, then "JCL < deck" as a demo.
  21.  
  22. As it says in the README, I bequeath this code to the net. In particular
  23. I don't intend to handle any bugfixes/improvements.
  24.  
  25.             Robert Lupton
  26.  
  27. : =-=-=-=-=-=-=-=-=-=-= Cut Here =-=-=-=-=-=-=-=-=-=-=
  28. PATH=/bin:/usr/bin:/usr/ucb:/etc:$PATH
  29. export PATH
  30. echo Extracting CC
  31. if [ -w CC ]; then
  32.     echo File already exists - saving as CC.old
  33.     mv CC CC.old
  34.     chmod 444 CC.old
  35. fi
  36. sed 's/^X//' <<'//go.sysin dd *' >CC
  37. mv $SYSIN $SYSIN.c
  38. cc -c $* $SYSIN.c
  39. mv $SYSIN.o $SYSOUT
  40. mv $SYSIN.c $SYSIN
  41. //go.sysin dd *
  42. if [ `wc -c < CC` != 76 ]; then
  43. made=FALSE
  44. echo error transmitting CC --
  45. echo length should be 76, not `wc -c < CC`
  46. else
  47.     made=TRUE
  48. fi
  49. if [ $made = TRUE ]; then
  50.     chmod 755 CC
  51.     echo -n  ; ls -ld CC
  52. fi
  53. echo Extracting LKED
  54. if [ -w LKED ]; then
  55.     echo File already exists - saving as LKED.old
  56.     mv LKED LKED.old
  57.     chmod 444 LKED.old
  58. fi
  59. sed 's/^X//' <<'//go.sysin dd *' >LKED
  60. mv $SYSIN $SYSIN.o
  61. cc $SYSIN.o $*
  62. mv a.out $SYSOUT
  63. mv $SYSIN.o $SYSIN
  64. //go.sysin dd *
  65. if [ `wc -c < LKED` != 70 ]; then
  66. made=FALSE
  67. echo error transmitting LKED --
  68. echo length should be 70, not `wc -c < LKED`
  69. else
  70.     made=TRUE
  71. fi
  72. if [ $made = TRUE ]; then
  73.     chmod 755 LKED
  74.     echo -n  ; ls -ld LKED
  75. fi
  76. echo Extracting Makefile
  77. if [ -w Makefile ]; then
  78.     echo File already exists - saving as Makefile.old
  79.     mv Makefile Makefile.old
  80.     chmod 444 Makefile.old
  81. fi
  82. sed 's/^X//' <<'//go.sysin dd *' >Makefile
  83. #
  84. # Default rules for compiling code.
  85. #
  86. .c.o :
  87.     cc $(CFLAGS) $*.c
  88. #
  89. CFLAGS = -c -g
  90. #
  91. # linker flags
  92. #
  93. LDFLAGS = -lg -lm
  94. #
  95. # define macros for the source files
  96. #
  97. SOURCE = \
  98. #
  99. OBJECT = \
  100.     parser.o data_defs.o keyword.o main.o yylex.o
  101. #
  102. # cmp is used in issame (needed by VMS)
  103. #
  104. #cmp : cmp.o
  105. #    cc cmp.o -o cmp
  106. #
  107. # Make JCL
  108. #
  109. JCL : $(OBJECT)
  110.     cc -o JCL $(OBJECT) $(LDFLAGS)
  111. #
  112. # make parser.c from parser.y
  113. # issame sees if keyword.h is changed. if not, don't update it
  114. #
  115. parser.c : parser.y
  116.     @- echo Expect 4 unreduced rules
  117.     yacc -d parser.y
  118.     @ mv y.tab.c parser.c
  119.     @ csh -f issame y.tab.h keyword.h
  120. #
  121. # make keyword.c from the list of tokens in keyword.h
  122. #
  123. make_keyword : make_keyword.o
  124.       cc make_keyword.o -o make_keyword
  125. #
  126. keyword.c : keyword.h make_keyword
  127.     make_keyword keyword.h
  128. #
  129. clean :
  130.     - rm *.o JCL cmp make_keyword parser.c keyword.h keyword.c \
  131.     y.output *~ core
  132. #
  133. # Here are all the dependencies:
  134. #
  135. keyword.o :        keyword.h
  136. data_defs.o :        jcl.h
  137. main.o :        yaccun.h
  138. parser.o :        yaccun.h jcl.h
  139. yylex.o :        yaccun.h keyword.h jcl.h
  140. //go.sysin dd *
  141. if [ `wc -c < Makefile` != 1036 ]; then
  142. made=FALSE
  143. echo error transmitting Makefile --
  144. echo length should be 1036, not `wc -c < Makefile`
  145. else
  146.     made=TRUE
  147. fi
  148. if [ $made = TRUE ]; then
  149.     chmod 644 Makefile
  150.     echo -n  ; ls -ld Makefile
  151. fi
  152. echo Extracting README
  153. if [ -w README ]; then
  154.     echo File already exists - saving as README.old
  155.     mv README README.old
  156.     chmod 444 README.old
  157. fi
  158. sed 's/^X//' <<'//go.sysin dd *' >README
  159.    This is something I wrote a few years ago in a fit of nostalgia, but
  160.    never really quite got finished. It was intended to run as a login 
  161.    shell on my new shiny sun, to discourage other users from taking my
  162.    CPU cycles.
  163.  
  164.    It is an emulator for for favourite operating system, JCL on an IBM 360.
  165.    It works as far as it goes, but I never got around to implementing 
  166.    libraries (I was going to use "ar" via system() calls). The grammar 
  167.    is a bit of a hack, with the lex analysis doing a good deal of the work.
  168.  
  169.    To try it out, type "JCL < deck" after running make. I don't really want
  170.    to deal with any enhancements or bug fixes (although I'd be happy to
  171.    see the code improved). I therefore bequeath this code to the net, with
  172.    no strings attached. On the other hand, I doubt if there is much money
  173.    to be made out of it.
  174.  
  175.    One thing that I intended to do, but never did, was to make JCL accept
  176.    input produced by "bcd" (i.e. real card images). I have a programme 
  177.    somewhere that's like bcd but writes paper tapes, if there were enough
  178.    interest I could post it.
  179.  
  180.             
  181.                 Robert Lupton
  182. //go.sysin dd *
  183. if [ `wc -c < README` != 1121 ]; then
  184. made=FALSE
  185. echo error transmitting README --
  186. echo length should be 1121, not `wc -c < README`
  187. else
  188.     made=TRUE
  189. fi
  190. if [ $made = TRUE ]; then
  191.     chmod 644 README
  192.     echo -n  ; ls -ld README
  193. fi
  194. echo Extracting cmp.c
  195. if [ -w cmp.c ]; then
  196.     echo File already exists - saving as cmp.c.old
  197.     mv cmp.c cmp.c.old
  198.     chmod 444 cmp.c.old
  199. fi
  200. sed 's/^X//' <<'//go.sysin dd *' >cmp.c
  201. X/*
  202.  * This programme returns 1 (true) if the two files given as
  203.  * arguments are identical, otherwise it returns 2 (false)
  204.  */
  205. #include <stdio.h>
  206.  
  207.  
  208. main(ac,av)
  209. int ac;
  210. char *av[];
  211. {
  212.    char c1,c2;                /* characters read from files */
  213.    int fil1,fil2;            /* fd's for two files */
  214.  
  215.    if(ac < 3 || (fil1 = open(av[1],0)) < 0 || (fil2 = open(av[2],0)) < 0) {
  216.       exit(2);
  217.    }
  218.  
  219.    while(1) {
  220.       if(read(fil1,&c1,1) == 1) {
  221.          if(read(fil2,&c2,1) == 1) {
  222.             if(c1 != c2) exit(2);
  223.             else ;
  224.          } else {
  225.             exit(2);
  226.          }
  227.       } else if(read(fil2,&c2,1) == 1) {
  228.          exit(2);
  229.       } else {
  230.          exit(1);
  231.       }
  232.    }
  233. }
  234. //go.sysin dd *
  235. if [ `wc -c < cmp.c` != 671 ]; then
  236. made=FALSE
  237. echo error transmitting cmp.c --
  238. echo length should be 671, not `wc -c < cmp.c`
  239. else
  240.     made=TRUE
  241. fi
  242. if [ $made = TRUE ]; then
  243.     chmod 755 cmp.c
  244.     echo -n  ; ls -ld cmp.c
  245. fi
  246. echo Extracting data_defs.c
  247. if [ -w data_defs.c ]; then
  248.     echo File already exists - saving as data_defs.c.old
  249.     mv data_defs.c data_defs.c.old
  250.     chmod 444 data_defs.c.old
  251. fi
  252. sed 's/^X//' <<'//go.sysin dd *' >data_defs.c
  253. X/*
  254.  * Maintain information about DD statements
  255.  */
  256. #include <stdio.h>
  257. #include "jcl.h"
  258.  
  259. #define NDD 20                /* Max. number of current DD sets */
  260. #define SIZE 80                /* length of character strings */
  261.  
  262. typedef struct {
  263.    char name[SIZE],            /* name of DD set */
  264.     file[SIZE],            /* name of associated file */
  265.     step[SIZE];            /* name of step */
  266.    int disp[3];                /* DISP modes */
  267. } DD_SET;
  268.  
  269. static DD_SET dds[NDD];            /* the available DDs */
  270.  
  271. init_dd()
  272. {
  273.    int i;
  274.  
  275.    for(i = 0;i < NDD;i++) {
  276.       dds[i].name[0] = '\0';
  277.    }
  278. }
  279.  
  280. create_dd(name,file,step,disp)
  281. char *name,
  282.      *file,
  283.      *step;
  284. int disp[];
  285. {
  286.    char msg[40];
  287.    int i;
  288.  
  289.    for(i = 0;i < NDD;i++) {
  290.       if(!strcmp(name,dds[i].name)) {
  291.      sprintf(msg,"DD set %s already exists",name);
  292.      yyerror(msg);
  293.      break;
  294.       } else if(dds[i].name[0] == '\0') {
  295.      break;
  296.       }
  297.    }
  298.    if(i == NDD) {
  299.       yyerror("Too many DD sets");
  300.       return(-1);
  301.    }
  302.  
  303.    strcpy(dds[i].name,name);
  304.    strcpy(dds[i].file,file);
  305.    strcpy(dds[i].step,step);
  306.  
  307.    if(disp[0] != UNKNOWN) {
  308.       dds[i].disp[0] = disp[0];
  309.    } else {
  310.       if(access(file,0) == -1) {        /* file dosn't exist */
  311.      dds[i].disp[0] = NEW;
  312.       } else {
  313.      dds[i].disp[0] = OLD;
  314.       }
  315.    }
  316.  
  317.    if(disp[1] != UNKNOWN) {
  318.       dds[i].disp[1] = disp[1];
  319.    } else {
  320.       if(dds[i].disp[0] == NEW) {
  321.      dds[i].disp[1] = DELETE;
  322.       } else {
  323.      dds[i].disp[1] = KEEP;
  324.       }
  325.    }
  326.  
  327.    if(disp[2] != UNKNOWN) {
  328.       dds[i].disp[2] = disp[2];
  329.    } else {
  330.       if(dds[i].disp[0] == NEW) {
  331.      dds[i].disp[2] = DELETE;
  332.       } else {
  333.      dds[i].disp[2] = KEEP;
  334.       }
  335.    }
  336. }
  337.  
  338. X/******************************************************/
  339. X/*
  340.  * Cleanup after a job step
  341.  */
  342. step_clean_dd(step)
  343. char *step;                /* name of step */
  344. {
  345.    int i;
  346.  
  347.    for(i = 0;i < NDD;i++) {
  348.       if(dds[i].name[0] != '\0' && !strcmp(step,dds[i].step)) {
  349.      if(dds[i].disp[1] == DELETE) {
  350.         unlink(dds[i].file);
  351.      }
  352.       }
  353.    }
  354. }
  355.  
  356. X/******************************************************/
  357. X/*
  358.  * Cleanup after job terminates
  359.  */
  360. job_clean_dd()
  361. {
  362.    int i;
  363.  
  364.    for(i = 0;i < NDD;i++) {
  365.       if(dds[i].name[0] != '\0') {
  366.      if(dds[i].disp[2] == DELETE) {
  367.         unlink(dds[i].file);
  368.      }
  369.       }
  370.    }
  371. }
  372.  
  373. X/******************************************************/
  374. X/*
  375.  * Return a string defining all units used in a job step
  376.  */
  377. char *
  378. define_dd(step)
  379. char *step;                /* name of step */
  380. {
  381.    static char string[200],
  382.            *sptr;
  383.    int i;
  384.  
  385.    sptr = string;
  386.    for(i = 0;i < NDD;i++) {
  387.       if(dds[i].name[0] != '\0' && !strcmp(step,dds[i].step)) {
  388.      sprintf(sptr,"%s=%s;export %s;",dds[i].name,dds[i].file,dds[i].name);
  389.      sptr += 10 + 2*strlen(dds[i].name) + strlen(dds[i].file);
  390.       }
  391.    }
  392.    return(string);
  393. }
  394.  
  395. //go.sysin dd *
  396. if [ `wc -c < data_defs.c` != 2689 ]; then
  397. made=FALSE
  398. echo error transmitting data_defs.c --
  399. echo length should be 2689, not `wc -c < data_defs.c`
  400. else
  401.     made=TRUE
  402. fi
  403. if [ $made = TRUE ]; then
  404.     chmod 644 data_defs.c
  405.     echo -n  ; ls -ld data_defs.c
  406. fi
  407. echo Extracting deck
  408. if [ -w deck ]; then
  409.     echo File already exists - saving as deck.old
  410.     mv deck deck.old
  411.     chmod 444 deck.old
  412. fi
  413. sed 's/^X//' <<'//go.sysin dd *' >deck
  414. X//NAME JOB ROBERT.H.LUPTON,MSGLEVEL=(2,2),         comments       78901   
  415. X//         MSGCLASS=A
  416. X//COMP EXEC PGM=CC,PARM='-g'
  417. X//SYSOUT DD DSN=TEMP,DISP=KEEP
  418. X//SYSIN DD *
  419. #include <stdio.h>
  420. main()
  421. {
  422.    printf("Hello World\n");
  423. }
  424. X/*
  425. X//LKED EXEC PGM=LKED,PARM='-lc'
  426. X//SYSIN DD DSN=TEMP,DISP=(,KEEP,DELETE)
  427. X//SYSOUT DD DSN=TST,DISP=(,KEEP,DELETE)
  428. X//GO EXEC PGM=TST
  429. X//                          
  430. //go.sysin dd *
  431. if [ `wc -c < deck` != 390 ]; then
  432. made=FALSE
  433. echo error transmitting deck --
  434. echo length should be 390, not `wc -c < deck`
  435. else
  436.     made=TRUE
  437. fi
  438. if [ $made = TRUE ]; then
  439.     chmod 644 deck
  440.     echo -n  ; ls -ld deck
  441. fi
  442. echo Extracting issame
  443. if [ -w issame ]; then
  444.     echo File already exists - saving as issame.old
  445.     mv issame issame.old
  446.     chmod 444 issame.old
  447. fi
  448. sed 's/^X//' <<'//go.sysin dd *' >issame
  449. # /bin/csh -f
  450. #
  451. # $1 contains a new version of $2
  452. # this programme compares the two files $1 and $2
  453. # if they are different, then replace $1 by $2
  454. # The programme is called by make
  455. #
  456. if({ cmp -s $1 $2 })then    # The same
  457.     /bin/rm $1
  458. else                # different
  459.     /bin/mv $1 $2
  460. endif
  461. //go.sysin dd *
  462. if [ `wc -c < issame` != 272 ]; then
  463. made=FALSE
  464. echo error transmitting issame --
  465. echo length should be 272, not `wc -c < issame`
  466. else
  467.     made=TRUE
  468. fi
  469. if [ $made = TRUE ]; then
  470.     chmod 755 issame
  471.     echo -n  ; ls -ld issame
  472. fi
  473. echo Extracting jcl.h
  474. if [ -w jcl.h ]; then
  475.     echo File already exists - saving as jcl.h.old
  476.     mv jcl.h jcl.h.old
  477.     chmod 444 jcl.h.old
  478. fi
  479. sed 's/^X//' <<'//go.sysin dd *' >jcl.h
  480. X/*
  481.  * Parameters defined for the `scheduler'
  482.  */
  483. #define PSIZE 60            /* size of parm */
  484. #define UNKNOWN 0            /* DISP parameters */
  485. #define DELETE 1
  486. #define KEEP 2
  487. #define NEW 3
  488. #define OLD 4
  489.  
  490. extern char parm[];            /* parameters for EXEC */
  491. extern FILE *msgout;            /* output from `scheduler' */
  492. extern int msglevel1,            /* MSGLEVEL=(msglevel1,msglevel2) */
  493.        msglevel2;
  494. //go.sysin dd *
  495. if [ `wc -c < jcl.h` != 367 ]; then
  496. made=FALSE
  497. echo error transmitting jcl.h --
  498. echo length should be 367, not `wc -c < jcl.h`
  499. else
  500.     made=TRUE
  501. fi
  502. if [ $made = TRUE ]; then
  503.     chmod 644 jcl.h
  504.     echo -n  ; ls -ld jcl.h
  505. fi
  506. echo Extracting main.c
  507. if [ -w main.c ]; then
  508.     echo File already exists - saving as main.c.old
  509.     mv main.c main.c.old
  510.     chmod 444 main.c.old
  511. fi
  512. sed 's/^X//' <<'//go.sysin dd *' >main.c
  513. #include <stdio.h>
  514. #include "yaccun.h"
  515.  
  516. YYSTYPE yylval,yyval;
  517. int verbose = 0;
  518.  
  519. main(ac,av)
  520. int ac;
  521. char *av[];
  522. {
  523.    if(ac > 1) {
  524.       sscanf(av[1],"-v=%d",&verbose);
  525.    }
  526.  
  527.    while(yyparse());
  528. }
  529. //go.sysin dd *
  530. if [ `wc -c < main.c` != 197 ]; then
  531. made=FALSE
  532. echo error transmitting main.c --
  533. echo length should be 197, not `wc -c < main.c`
  534. else
  535.     made=TRUE
  536. fi
  537. if [ $made = TRUE ]; then
  538.     chmod 644 main.c
  539.     echo -n  ; ls -ld main.c
  540. fi
  541. echo Extracting make_keyword.c
  542. if [ -w make_keyword.c ]; then
  543.     echo File already exists - saving as make_keyword.c.old
  544.     mv make_keyword.c make_keyword.c.old
  545.     chmod 444 make_keyword.c.old
  546. fi
  547. sed 's/^X//' <<'//go.sysin dd *' >make_keyword.c
  548. X/*
  549.  * Syntax: av[0] inc_file
  550.  *
  551.  * This programme uses the file inc_file to construct a second stage lex
  552.  * analyser called keyword() in file keyword.c.
  553.  */
  554. #include <stdio.h>
  555. #include <ctype.h>
  556. #define NTOKEN 200        /* maximum number of tokens */
  557. #define OUTFILE "keyword.c"    /* name of output file */
  558. #define POUT fprintf(outfil    /* save space */
  559. #define SIZE 40            /* maximum size of token */
  560.  
  561. static char token[NTOKEN][SIZE];
  562.  
  563. main(ac,av)
  564. int ac;
  565. char *av[];
  566. {
  567.    char  c;
  568.    FILE  *infil,            /* file descriptor for *.h */
  569.      *outfil;
  570.    int   i,
  571.      num_token;                    /* number of tokens */
  572.    extern int *strcmp();
  573.  
  574.    if(ac < 2) {
  575.       fprintf(stderr,"Syntax: make_keyword inc_file\n");
  576.       exit(-2);
  577.    }
  578.    if((infil = fopen(av[1],"r")) == NULL) {
  579.       fprintf(stderr,"Can't open %s\n",av[1]);
  580.       exit(-2);
  581.    }
  582.  
  583.    if((outfil = fopen(OUTFILE,"w")) == NULL) {
  584.       fprintf(stderr,"Can't open %s\n",OUTFILE);
  585.       fclose(infil);
  586.       exit(-2);
  587.    }
  588. X/*
  589.  * Read in the tokens from av[1].
  590.  * Use the val_tok field to give their value in each file
  591.  */
  592.    for(i = 0;i < NTOKEN;i++) {
  593.       if(fscanf(infil,"%*s %*s %s %*d",token[i]) != 1) {
  594.      break;
  595.       }
  596.    }
  597.    fclose(infil);
  598.    num_token = i;
  599.  
  600.    qsort(token,num_token,SIZE,strcmp);       /* sort tokens */
  601.  
  602.    POUT,"/*\n");
  603.    POUT," */\n");
  604.    POUT,"#include <stdio.h>\n");
  605.    POUT,"#include \"%s\"\n",av[1]);
  606.    POUT,"\n");
  607.    POUT,"extern int strcmp();\n");
  608.    POUT,"\n");
  609.    POUT,"keyword(word)\n");
  610.    POUT,"char word[];        /* word to look for */\n");
  611.    POUT,"{\n");
  612.    POUT,"\n");
  613.    POUT,"  switch (word[0]) {\n");
  614.    for(i = 0,c = 'A';c <= 'Z' && i < num_token;c++) {    /* assumes ascii */
  615.       POUT,"  case '%c' :\n",c);
  616.       while(token[i][0] <= c && i < num_token) {
  617.      POUT,"      if(!strcmp(word,\"%s\")) {\n",token[i]);
  618.      POUT,"         return(%s);\n",token[i]);
  619.      POUT,"      } else\n");
  620.      i++;
  621.       }
  622.       POUT,"         break;\n");
  623.    }
  624.  
  625.    POUT,"   default : break;\n");
  626.    POUT,"   }\n");
  627.    POUT,"   return(WORD);\n");
  628.    POUT,"\n");
  629.    POUT,"}\n");
  630.  
  631.    fclose(outfil);
  632. #ifdef unix
  633.    exit(0);            /* success */
  634. #else
  635.    exit(1);            /* success in vmsese */
  636. #endif UniX
  637. }
  638. //go.sysin dd *
  639. if [ `wc -c < make_keyword.c` != 2164 ]; then
  640. made=FALSE
  641. echo error transmitting make_keyword.c --
  642. echo length should be 2164, not `wc -c < make_keyword.c`
  643. else
  644.     made=TRUE
  645. fi
  646. if [ $made = TRUE ]; then
  647.     chmod 755 make_keyword.c
  648.     echo -n  ; ls -ld make_keyword.c
  649. fi
  650. echo Extracting parser.y
  651. if [ -w parser.y ]; then
  652.     echo File already exists - saving as parser.y.old
  653.     mv parser.y parser.y.old
  654.     chmod 444 parser.y.old
  655. fi
  656. sed 's/^X//' <<'//go.sysin dd *' >parser.y
  657. %{
  658. #include <stdio.h>
  659. #include "yaccun.h"
  660. #include "jcl.h"
  661. X/*
  662.  * declare variables in jcl.h
  663.  */
  664. char parm[PSIZE];            /* parameters on EXEC card */
  665. FILE *msgout=stderr;            /* destination for output */
  666. int disp[3],                /* 3 DISP parameters */
  667.     msglevel1 = 1,msglevel2 = 1;    /* MSGLEVEL=(msglevel1,msglevel2) */
  668.  
  669. static char msg[50],            /* used for composing error messages */
  670.         step_name[40];        /* name of current step */
  671. extern char token[];            /* text of last token read */
  672. int pgm;                /* true if current step is a PGM */
  673. extern int verbose;
  674. %}
  675.  
  676. %start deck                /* the complete deck of cards */
  677.  
  678. %token <charval>
  679.       EXEC WORD
  680.  
  681. %token                    /* special characters */
  682.       '\n' ',' '.' '/' '\'' '(' ')' '*' '&' '+' '-' '=' ' '
  683. %token                    /* control words */
  684.       DD DSLASH ENDMARK JOB NULL_CARD SLASHSTAR
  685. %token                    /* keywords */
  686.       COND                    /* Misc. */
  687.       MSGCLASS MSGLEVEL                /* JOB */
  688.       PGM PROC PARM                /* EXEC */
  689.       DATA DCB DISP DSN DUMMY UNIT        /* DD */
  690.  
  691. %type <charval>
  692.       apost_word            /* string enclosed in ' ' */
  693.       dd_file                /* name of file for DD statement */
  694.       dot_name                /* name including '.'s */
  695.       exec_card                /* PGM/PROC run by exec step */
  696.       opt_dot_name            /* optional dot_name */
  697.       opt_word                /* optional word */
  698.       pgm_or_proc            /* name of PGM/PROC */
  699.  
  700. %type <intval>
  701.       disp_par                /* DISP parameter */
  702.       opt_disp                /* optional disp_par */
  703. %%                    /* start of rules */
  704.  
  705. deck  : job_card steps null_card
  706.       {
  707.      job_clean_dd();        /* delete unwanted datasets */
  708.      return(0);
  709.       }
  710.       ;
  711.  
  712. steps :                 /* a collection of job steps */
  713.       | steps step
  714.       ;
  715.  
  716. step  : exec_card opt_dd_cards
  717.       {
  718.      char command[200],
  719.           *define_dd();
  720.  
  721.      if(pgm) {
  722.         sprintf(command,"%s%s %s",define_dd(step_name),$1,parm);
  723.         if(verbose) printf("%s\n",command);
  724.         system(command);
  725.      } else {
  726.         printf("Step %s runs proc %s\n",step_name,$1);
  727.         printf("Parameters: %s\n",parm);
  728.      }
  729.      step_clean_dd(step_name);
  730.       }
  731.       | error '\n'
  732.       {
  733.          yyerrok;
  734.          yyclearin;
  735.       }
  736.       ;
  737.  
  738. opt_dd_cards :
  739.       | opt_dd_cards dd_card
  740.       ;
  741.  
  742. dd_card : DSLASH opt_dot_name ' ' DD ' ' dd_file '\n'
  743.       { create_dd($2,$6,step_name,disp); }
  744.       ;
  745.  
  746. dd_file    : '*'
  747.       {
  748.      char line[81],
  749.           *mktemp(),
  750.           *tempname;
  751.      FILE *fil;
  752.  
  753.      if((tempname = mktemp("DATXXXXXX")) == NULL) {
  754.         yyerror("Can't create temporary file name");
  755.         break;
  756.      }
  757.      if((fil = fopen(tempname,"w")) == NULL) {
  758.         sprintf(msg,"Can't open %s",tempname);
  759.         break;
  760.      }
  761.      strcpy($$,tempname);
  762.  
  763.      while(fgets(line,81,stdin) != NULL) {
  764.         if(!strncmp("/*\n",line,3) || !strncmp("/* ",line,3)) {
  765.            break;
  766.         }
  767.         fputs(line,fil);
  768.      }
  769.      fclose(fil);
  770.  
  771.      disp[0] = NEW;
  772.      disp[1] = DELETE;
  773.      disp[2] = DELETE;
  774.       }
  775.       | DUMMY dd_opts
  776.      { strcpy($$,"/dev/null"); }
  777.       | DSN '=' dot_name dd_opts
  778.      { strcpy($$,$3); }
  779.       ;
  780.  
  781. dd_opts    :
  782.       {
  783.      disp[0] = UNKNOWN;
  784.      disp[1] = UNKNOWN;
  785.      disp[2] = UNKNOWN;
  786.       }
  787.       | dd_opts ',' DCB '=' WORD
  788.       | dd_opts ',' DISP '=' disp_par
  789.       {
  790.      disp[0] = $5;
  791.      disp[1] = UNKNOWN;
  792.      disp[2] = UNKNOWN;
  793.       }
  794.       | dd_opts ',' DISP '=' '(' opt_disp ',' opt_disp ')'
  795.       {
  796.      disp[0] = $6;
  797.      disp[1] = $8;
  798.      disp[2] = UNKNOWN;
  799.       }
  800.       | dd_opts ',' DISP '=' '(' opt_disp ',' opt_disp ',' opt_disp ')'
  801.       {
  802.      disp[0] = $6;
  803.      disp[1] = $8;
  804.      disp[2] = $10;
  805.       }
  806.       ;
  807.  
  808. disp_par : WORD
  809.       {
  810.      if(!strcmp($1,"DELETE")) $$ = DELETE;
  811.      else if(!strcmp($1,"KEEP")) $$ = KEEP;
  812.      else if(!strcmp($1,"NEW")) $$ = NEW;
  813.      else if(!strcmp($1,"OLD")) $$ = OLD;
  814.      else {
  815.         sprintf(msg,"Unknown DISP parameter %s",$1);
  816.         $$ = UNKNOWN;
  817.      }
  818.       }
  819.       ;
  820.  
  821. opt_disp :
  822.       { $$ = UNKNOWN; }
  823.       | disp_par
  824.       { $$ = $1; }
  825.       ;
  826.  
  827. exec_card : EXEC ' ' pgm_or_proc exec_opts '\n'
  828.       {
  829.      strcpy($$,$3);
  830.      strcpy(step_name,$1);
  831.       }
  832.       ;
  833.  
  834. exec_opts :
  835.       | exec_opts ',' COND '=' '(' WORD ',' WORD ',' WORD ')'
  836.       | exec_opts ',' PARM '=' apost_word
  837.      { strcpy(parm,$5); }
  838.       | exec_opts ',' PARM '=' WORD
  839.      { strcpy(parm,$5); }
  840.       ;
  841.  
  842. apost_word : '\'' /* [^']' */
  843.       {
  844.      int i;
  845.  
  846.      for(i = 0;i < CHARMAX
  847.         && ($$[i] = get_cchar()) != '\'' && $$[i] != '\n';i++) ;
  848.      if($$[i] != '\'') put_cchar($$[i]);
  849.      $$[i] = '\0';
  850.       }
  851.       ;
  852.  
  853. pgm_or_proc : PGM '=' WORD
  854.       {
  855.      pgm = 1;            /* it's a programme */
  856.      strcpy($$,$3);
  857.       }
  858.       | PGM '=' apost_word
  859.       {
  860.      pgm = 1;            /* it's a programme */
  861.      strcpy($$,$3);
  862.       }
  863.       | PROC '=' WORD
  864.       {
  865.      pgm = 0;            /* it's a procedure */
  866.      strcpy($$,$3);
  867.       }
  868.       ;
  869.  
  870. job_card : DSLASH opt_word ' ' JOB ' ' dot_name job_opts '\n'
  871.       ;
  872.  
  873. job_opts :
  874.       | job_opts ',' MSGCLASS '=' WORD
  875.       {
  876.          if($5[0] == 'A') {
  877.             if(msgout != stderr) fclose(msgout);
  878.             msgout = stderr;
  879.          } else if($5[0] == 'B') {
  880.             if(msgout != stderr) fclose(msgout);
  881.             if((msgout = fopen("JCL.out","w")) == NULL) {
  882.            yyerror("Can't open JCL.out");
  883.            msgout = stderr;
  884.             }
  885.          } else {
  886.             sprintf(msg,"Unknown MSGCLASS %s",$5);
  887.             yyerror(msg);
  888.          }
  889.       }
  890.       | job_opts ',' MSGLEVEL '=' '(' WORD ',' WORD ')'
  891.       {
  892.          msglevel1 = atoi($6);
  893.          msglevel2 = atoi($8);
  894.       }
  895.       ;
  896.  
  897. dot_name : WORD
  898.          { strcpy($$,$1); }
  899.       | dot_name '.' WORD
  900.          { sprintf($$,"%s.%s",$1,$3); }
  901.       ;
  902.  
  903. null_card : NULL_CARD
  904.       | ENDMARK
  905.       ;
  906.  
  907. opt_word : WORD
  908.          { sprintf($$,$1); }
  909.       |
  910.          { sprintf($$,""); }
  911.       ;
  912.  
  913. opt_dot_name : dot_name
  914.          { sprintf($$,$1); }
  915.       |
  916.          { sprintf($$,""); }
  917.       ;
  918.  
  919. opt_lparen :
  920.       | '('
  921.       ;
  922.  
  923. opt_rparen :
  924.       | ')'
  925.       ;
  926. %%
  927. yyerror(s)
  928. char *s;
  929. {
  930.    if(!strcmp(s,"syntax error")) {
  931.       fprintf(stderr,"Syntax error, last token read %s\n",token);
  932.    } else {
  933.       fprintf(stderr,"   %s\n",s);
  934.    }
  935. }
  936. //go.sysin dd *
  937. if [ `wc -c < parser.y` != 5908 ]; then
  938. made=FALSE
  939. echo error transmitting parser.y --
  940. echo length should be 5908, not `wc -c < parser.y`
  941. else
  942.     made=TRUE
  943. fi
  944. if [ $made = TRUE ]; then
  945.     chmod 644 parser.y
  946.     echo -n  ; ls -ld parser.y
  947. fi
  948. echo Extracting yaccun.h
  949. if [ -w yaccun.h ]; then
  950.     echo File already exists - saving as yaccun.h.old
  951.     mv yaccun.h yaccun.h.old
  952.     chmod 444 yaccun.h.old
  953. fi
  954. sed 's/^X//' <<'//go.sysin dd *' >yaccun.h
  955. X/*
  956.  * these are the typedefs for the yacc union 
  957.  */
  958. #define CHARMAX 80            /* maximum size of word */
  959.  
  960. typedef union {                /* union for yacc variable stack */
  961.    char charval[CHARMAX];
  962.    int intval;
  963. } YYSTYPE;
  964.  
  965. extern YYSTYPE yyval,yylval;
  966. //go.sysin dd *
  967. if [ `wc -c < yaccun.h` != 239 ]; then
  968. made=FALSE
  969. echo error transmitting yaccun.h --
  970. echo length should be 239, not `wc -c < yaccun.h`
  971. else
  972.     made=TRUE
  973. fi
  974. if [ $made = TRUE ]; then
  975.     chmod 755 yaccun.h
  976.     echo -n  ; ls -ld yaccun.h
  977. fi
  978. echo Extracting yylex.c
  979. if [ -w yylex.c ]; then
  980.     echo File already exists - saving as yylex.c.old
  981.     mv yylex.c yylex.c.old
  982.     chmod 444 yylex.c.old
  983. fi
  984. sed 's/^X//' <<'//go.sysin dd *' >yylex.c
  985. #include <stdio.h>
  986. #include "yaccun.h"
  987. #include "keyword.h"
  988. #include "jcl.h"
  989.  
  990. #define FORMAT "%[ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789@#$]"
  991.                         /* format for reading fields */
  992. #define YYCHARVAL (yylval.charval)        /* an abbreviation */
  993. char token[CHARMAX];                /* text of last token read */
  994. static char card[83],                /* current card */
  995.         *cptr;
  996. extern int verbose;                /* get debugging output */
  997. static int need_card = 1;        /* Do I need to read a new card? */
  998.  
  999. int
  1000. yylex()
  1001. {
  1002.    static char word[50];            /* error message */
  1003.    int ret;
  1004.  
  1005.    if(need_card) {            /* so read one */
  1006.       if(fgets(&card[1],81,stdin) == NULL) {
  1007.      return(ENDMARK);
  1008.       }
  1009.       need_card = 0;
  1010.       if(msglevel1 > 0) {
  1011.      fputs(&card[1],msgout);
  1012.       }
  1013.       if(strlen(&card[1]) > 72) {
  1014.      card[0] = card[72];        /* save continuation character */
  1015.       } else {
  1016.      card[0] = ' ';            /* no continuation character */
  1017.       }
  1018.       card[72] = '\0';            /* delete end of card */
  1019.       cptr = &card[72];
  1020.       while(*--cptr == ' ') ;        /* find trailing blanks */
  1021.       *(cptr + 1) = '\0';        /* strip them */
  1022.       cptr = &card[1];            /* now find comments */
  1023.       while(*cptr++ != ' ') ;        /* skip //name field */
  1024.       while(*cptr++ == ' ') ;        /* and first blank field */
  1025.       while(*cptr++ != ' ') ;        /* and JOB/DD/EXEC/etc field */
  1026.       while(*cptr++ == ' ') ;        /* and second blank field */
  1027.       while(*cptr++ != ' ') ;        /* and options field */
  1028.       *--cptr = '\0';            /* cut the comment off the card */
  1029.       cptr = card + strlen(card);    /* 1 past last character */
  1030.       if(*(cptr - 1) != '\n') {        /* check if card ends in \n */
  1031.      *cptr++ = '\n';
  1032.      *cptr = '\0';
  1033.       }
  1034.       cptr = &card[1];
  1035.    }
  1036.  
  1037.    if(*cptr == '\0') {
  1038.       need_card = 1;
  1039.       return(yylex());
  1040.    }
  1041.  
  1042.    if(cptr == &card[1]) {
  1043.       if(!strncmp(cptr,"//*",3)) {            /* comment */
  1044.      need_card = 1;
  1045.      return(yylex());
  1046.       } else if(!strncmp(cptr,"//",2)) {        /* May be EXEC */
  1047.      cptr += 2;                    /* skip // */
  1048.      if(sscanf(cptr,FORMAT,word) == 1) {        /* read NAME field */
  1049.         cptr += strlen(word);
  1050.      } else if(*cptr == '\n') {            /* null card */
  1051.         sprintf(token,"//\\n");
  1052.         return(NULL_CARD);
  1053.      } else {
  1054.         word[0] = '\0';
  1055.      }
  1056.      if(yylex() == ' ') {                /* EXEC or null? */
  1057.         if((ret = yylex()) == EXEC) {        /* yes, an EXEC card */
  1058.            strcpy(YYCHARVAL,word);
  1059.            sprintf(token,"//%s EXEC",word);
  1060.            return(ret);
  1061.         } else if(ret == '\n') {            /* null card */
  1062.            sprintf(token,"//\\n");
  1063.            return(NULL_CARD);
  1064.         }
  1065.      }
  1066.      cptr = &card[3];            /* no, rewind and return // */
  1067.      sprintf(token,"//");
  1068.      ret = DSLASH;
  1069.       } else if(!strncmp(cptr,"/*",2)) {
  1070.      sprintf(token,"/*");
  1071.      cptr += 2;
  1072.      ret = SLASHSTAR;
  1073.       } else {
  1074.      sprintf(word,"Card begins %c%c",*cptr,*(cptr+1));
  1075.      yyerror(word);
  1076.      sprintf(YYCHARVAL,"%c%c",*cptr++,*cptr++);
  1077.      strcpy(token,YYCHARVAL);
  1078.      ret = WORD;
  1079.       }
  1080.    } else {
  1081.       if(sscanf(cptr,FORMAT,YYCHARVAL) == 1) {
  1082.      strcpy(token,YYCHARVAL);
  1083.      cptr += strlen(YYCHARVAL);
  1084.      ret = keyword(YYCHARVAL);
  1085.       } else {
  1086.      switch (*cptr) {
  1087.      case ',': case '.': case '/': case '\'': case '(': case ')':
  1088.      case '*': case '&': case '+': case '-':  case '=':
  1089.         sprintf(token,"%c",*cptr);
  1090.         ret = *cptr++;
  1091.         break;
  1092.      case ' ':
  1093.         while(*cptr == ' ') {
  1094.            cptr++;
  1095.         }
  1096.         sprintf(token,"' '");
  1097.         ret = ' ';
  1098.         break;
  1099.      case '\n':
  1100.         if(card[0] != ' ' || *(cptr - 1) == ',') {    /* Continuation */
  1101.            need_card = 1;                /* skip newline */
  1102.            if(yylex() != DSLASH ||            /* card starts // */
  1103.                       yylex() != ' ') {    /* then spaces */
  1104.           sprintf(word,"Expected continuation card");
  1105.           yyerror(word);
  1106.            }
  1107.            return(yylex());                /* return next */
  1108.         } else {
  1109.            sprintf(token,"\\n");
  1110.            cptr++;
  1111.            ret = '\n';
  1112.         }
  1113.         break;
  1114.      default:
  1115.         sscanf(cptr,"%[^,./'()*&+-= ]",YYCHARVAL);
  1116.         if(YYCHARVAL[strlen(YYCHARVAL) - 1] == '\n') {
  1117.            YYCHARVAL[strlen(YYCHARVAL) - 1] = '\0';
  1118.         }
  1119.         strcpy(token,YYCHARVAL);
  1120.         cptr += strlen(YYCHARVAL);
  1121.         sprintf(word,"Illegal character in string \"%s\"",YYCHARVAL);
  1122.         yyerror(word);
  1123.         ret = WORD;
  1124.         break;
  1125.      }
  1126.       }
  1127.    }
  1128.    if(verbose) {
  1129.       fprintf(msgout,"TOKEN %s\n",token);
  1130.    }
  1131.    return(ret);
  1132. }
  1133.  
  1134. get_cchar()        /* get next character off a card */
  1135. {
  1136.    if(*cptr == '\n') {        /* at end of card */
  1137.       return('\n');
  1138.    } else {
  1139.       return(*cptr++);
  1140.    }
  1141. }
  1142.  
  1143. put_cchar(c)
  1144. int c;
  1145. {
  1146.    if(cptr > &card[0]) {
  1147.       *--cptr = c;
  1148.    }
  1149. }
  1150. //go.sysin dd *
  1151. if [ `wc -c < yylex.c` != 4445 ]; then
  1152. made=FALSE
  1153. echo error transmitting yylex.c --
  1154. echo length should be 4445, not `wc -c < yylex.c`
  1155. else
  1156.     made=TRUE
  1157. fi
  1158. if [ $made = TRUE ]; then
  1159.     chmod 644 yylex.c
  1160.     echo -n  ; ls -ld yylex.c
  1161. fi
  1162.