home *** CD-ROM | disk | FTP | other *** search
/ Source Code 1992 March / Source_Code_CD-ROM_Walnut_Creek_March_1992.iso / usenet / compsrcs / misc / volume06 / jcl < prev    next >
Encoding:
Internet Message Format  |  1991-08-27  |  26.3 KB

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