// £123 | \ # various characters to persuade gedit to accept the file // This is a version of intercode.c, but under development // for dealing with overlays // Translator for Leo III Intercode // This generates a paper tape input file // from the .CSV spreadsheet of the raw typing of the programme listing #include #include #include // arbitrary non-zero values for equality tests #define CONSTSHORT 900 #define CONSTLONG 901 #define PROCMODE 800 #define TABLEMODE 700 #define MAXCHAPS 15 #define CHAP0START 160 // chapter zero generated by translator #define MEMSTART 5600 // start of regular chapters #define PROC0VAR 6 // variable space in proc0, used for register dump when enter master, eg. action 40 #define MAXFILES 20 // just a guess // The modification group is fixed, and must be the same as initially set in the emulator #define MODGRP 1 int modinfo = 0; // I think that this is always the same unless we have multiple overlay points int traninfo = 0; // location of transit area list in procedure 0 int verbosity = 0; char *fmt = "%6s|%3s|%4s|%5s|%1s|%1s|%7s|%s\n"; char separator = ','; char buff[1000]; char **src[25000]; // source code line by line, starting with PROCR 100 int srcp = 0; int curchap; // current chapter int sercol = 0; int actcol = 0; int refcol = 4; int itemcol = 8; int disccol = 13; int modcol = 15; int litcol = 17; int cmtcol = 29; char **head = NULL; // column headings int absent = -10000; // really constants, but avoiding C pre-processor int alpha = -10001; char *wline[30]; // working buffer for line assembly char *lastline[] = { "99999", "99999", "99999", "99999", "99999", "99999", "99999" }; FILE *fout; int crash(int a, int b) // forcibly die diagnostically { char *zz, nogo; zz = NULL; fclose(fout); // write away end of output nogo = *zz; // deliberate crash } defineCols(char **h) // define the columns based on the lower case names in line // result is a new heading line for printing purposes { int i = -1; char *s; while ( (s = h[++i]) != NULL ) if ( *s == 's' ) sercol = i; else if ( *s == 'a' ) actcol = i; else if ( *s == 'r' ) refcol = i; else if ( *s == 'i' ) itemcol = i; else if ( *s == 'd' ) disccol = i; else if ( *s == 'm' ) modcol = i; else if ( *s == 'l' ) litcol = i; else if ( *s == 'c' ) cmtcol = i; else if ( *s != 0 ) fprintf(stderr, "Heading col %s unrecognised\n", s); head = h; } char **readline(FILE *fin) // read a line of source and split into fields { int i = 0; unsigned char *b; unsigned char *p; int smark = 0; char **res; if ( fgets(buff, 999, fin) == NULL ) return NULL; if ( strlen(buff) < 3 ) // ignore short lines -- probably blank return readline(fin); // return the next line b = strdup(buff); wline[0] = b; p = b - 1; while ( *++p != 0 ) if ( smark != 0 ) // inside quotes { if ( *p == '\"' ) // if end of quotes { smark = 0; wline[i] ++; // skip the quote at the start *p = 0; // mark the end of the string here } } else if ( *p == separator || *p == '\n' ) { *p = 0; // comma not in quotes or end of line wline[++i] = p + 1; } else if ( *p < ' ' ) *p = 0; // falling off the end of a string or carriage return else if ( *p == '\"' ) // start of string smark = 1; while ( i < 9 ) wline[++i] = NULL; // pad fields for short record wline[++i] = NULL; // mark end of fields wline[++i] = NULL; // mark end of fields res = (char **)malloc(sizeof(char*) * ++i); while ( --i >= 0 ) res[i] = wline[i]; if ( res[actcol] == NULL ) res[actcol] = "163"; if ( **res < 'a' ) // if lower case letter, defines columns return res; // otherwise return line of input defineCols(res); return readline(fin); // return the next line } // ---------------------------------------------------------- char charval[256]; // Leo III character values indexed by ASCII char hexval[256]; // TEMP !!! or maybe not // Basic Quartet // 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 // ___________________________________________________ // 0 | Sp | // 1 | - | // 2 | & | // Control 3 | 0 | // Quartet 4 | 1 2 3 4 5 6 7 8 9 10 11 + : . £ | // 5 | A B C D E F G H I = * ' ? ? ? | // 6 | J K L M N O P Q R ? % > < ½ \ | // 7 | / S T U V W X Y Z ( ) , ; ? ? | // |_________________________________________________| mkchars() // create the above conversion tables charval and hexval { int i; memset(charval, 0, 256); memset(hexval, 0, 256); for ( i = 0; i<16; i++ ) { hexval[i] = i; hexval[i+'0'] = i; } for ( i = 0; i<6; i++ ) hexval[i+'A'] = i + 10; hexval['t'] = 10; // ten char charval['t'] = 0x4A; // ten char hexval['e'] = 11; // eleven char charval['e'] = 0x4B; // eleven char hexval['p'] = 15; // pound char charval['p'] = 0x4F; // pound char charval[' '] = 0; charval['-'] = 16; charval['&'] = 32; charval['0'] = 48; for ( i = 1; i<10; i++ ) { charval[i+'0'] = i + 0x40; charval[i+'A'-1] = i + 0x50; charval[i+'Q'] = i + 0x70; // must precede next line charval[i+'I'] = i + 0x60; } charval['/'] = 0x71; hexval['+'] = 12; charval['+'] = 0x4C; hexval[':'] = 13; charval[':'] = 0x4D; hexval['.'] = 14; charval['.'] = 0x4E; hexval['£'&255] = 15; charval['£'&255] = 0x4F; // pound char charval['='] = 0x5A; charval['*'] = 0x5B; charval['\''] = 0x5C; charval['?'] = 0x5D; charval['%'] = 0x6B; charval['>'] = 0x6C; charval['<'] = 0x6D; charval['\\'] = 0x6F; charval['h'] = 0x6E; // h = half charval['('] = 0x7A; charval[')'] = 0x7B; charval[','] = 0x7C; charval[';'] = 0x7D; } int fieldval(char *s) // skip initial spaces then // get integer value, -10000 if absent, -10001 if alpha { int res; while ( *s == ' ' ) s ++; res = atoi(s); if ( res == 0 ) if ( *s == 0 ) // null string res = absent; else if ( *s != '0' ) // not an actual zero res = alpha; return res; } int itemval(char *s) // skip initial spaces then // get integer value, -10000 if absent, -10001 if alpha // but an item may be ove with - at the end { int res = fieldval(s); if ( res != 0 && s[strlen(s)-1] == '-' ) // -ve item value return -res; return res; } char *cleancomment(char *s) // strip leading spaces from a comment // needed because of early confusion between comments and notes { s --; while ( *++s == ' ' ) ; return s; } char *getcomment(char **line) { char *p = line[cmtcol]; if ( strlen(p) < 2 ) if ( strlen(line[cmtcol-1]) >= 5 ) p = line[cmtcol-1]; // deal with comment in wrong column else if ( strlen(line[cmtcol-2]) >= 5 ) p = line[cmtcol-2]; // deal with comment in wrong column return cleancomment(p); } main(int argc, char **argv) { FILE *fin; char **line; char itemstr[20]; // string of item int v, j; int i = 0; int numchaps, numroutes; int master = 0; // NZ if processing master routine int count; // counter used to generate serial numbers int curproc, item, ref, disc, mode, ser, act; char *p; // for cleaning-up comment char *magic[] = { "%05d %2d/0 %s%s\n", "%05d %2d/1 %s%s\n", "%05d %2d/2 %s%s\n", "%05d %2d/3 %s%s\n", "%05d %2d/4 %s%s\n", "%05d %2d/5 %s%s\n", "%05d %2d/6 %s%s\n", "%05d %2d/7 %s%s\n", "%05d %2d/8 %s%s\n", "%05d %2d/9 %s%s\n", "%05d %2d/t %s%s\n" }; while ( *(argv[++i]) == '-' ) if ( (j = argv[i][1]) == 'v' ) if ( argv[i][2] == 0 ) verbosity ++; else verbosity = atoi(argv[i]+2); else if ( j == 'm' ) // generating master routine master = 1; else if ( j == 'g' ) // generating master routine generator master = 2; fin = fopen(argv[i], "r"); if ( argc < i + 2 ) fout = stdout; else fout = fopen(argv[i+1], "w"); mkchars(); // sort out Leo characters if ( master == 0 ) // heading sheet for Intercode Translator 080 { fprintf(fout, "SHEET;1;\n"); fprintf(fout, "PROGM;080;0;1;INTERCODE TRANSLATOR\n"); fprintf(fout, "ENTRY;102;3\n"); fprintf(fout, "0;D1;14;0;195;;PRINTER(OR CLEO-SIZEDANNEX)\n"); fprintf(fout, "1;B1;15;4;27;;PT/CARDS MODS\n"); fprintf(fout, "2;A1;7;4;75\n"); fprintf(fout, "3;A2;8;4;75\n"); fprintf(fout, "4;A6;7;4;75\n"); fprintf(fout, "CHAPS;10;100;101;152;327;553;680;776;918;994;995\n"); } else if ( master == 1 ) // heading sheet for Master Routine { fprintf(fout, "SHEET;1;\n"); fprintf(fout, "PROGM;090;1;1;MASTER ROUTINE\n"); fprintf(fout, "ENTRY;551;1\n"); fprintf(fout, "CHAPS;2;100;536;\n"); } else // heading sheet for Master Routine Generator 08004 { fprintf(fout, "SHEET;1;\n"); fprintf(fout, "PROGM;080;04;0;GENERATOR\n"); fprintf(fout, "ENTRY;166;3\n"); fprintf(fout, "0;D1;14;2;195\n"); fprintf(fout, "1;B1;15;2;75\n"); fprintf(fout, "2;A1;7;2;75\n"); fprintf(fout, "3;A2;8;0;75\n"); fprintf(fout, "4;A6;7;0;75\n"); fprintf(fout, "CHAPS;9;100;101;200;326;445;557;558;559;564\n"); } // ser,act,ref,item,d,m,literal,comment -- order of columns is now defined to be this -- probably line = readline(fin); // first line must define columns if ( head == NULL ) { fprintf(fout, "First line must define columns\n"); printf("First line must define columns\n"); fprintf(fout, "Col1 = %s\n", line[0]); exit(1); } while ( strcmp(line[actcol], "CHAPS") != 0 ) // skip the heading info for now line = readline(fin); count = 0; while ( strcmp((line = readline(fin))[actcol], "PROCR") != 0 ) // process sections upto code sheets if ( atoi(line[actcol]) == 164 ) // Link to source file ; else if ( strcmp(line[actcol], "INDEX") == 0 ) // INDEX of overlay equivalents ; else if ( strlen(line[refcol]) != 0 ) // must be a section definition { i = atoi(line[refcol]); // section number v = atoi(line[itemcol]); // size in long words curchap = atoi(line[modcol]); fprintf(fout, "%d;%d;%d;%s;%d;%s\n", count++, i, v, line[disccol], curchap, line[cmtcol]); } else if ( strlen(line[actcol]) != 0 ) // ... or something else that we do not understand fprintf(fout, "Skipped: %s %s\n", line[actcol], line[refcol]); src[srcp++] = line; // start with first procedure count = 2; // now used for couting sheet number while ( line != NULL ) { if ( strlen(line[sercol]) != 0 ) // if not blank line { if ( strcmp(line[actcol], "C") == 0 // if this is a continuation line ... && *(src[srcp-1][sercol]) == '0' ) // ... at the start of a page { src[srcp] = src[srcp-1]; // put the marker line one later src[srcp-1] = line; // and put the real line at the foot of the previous page srcp ++; } else src[srcp++] = line; } ref = atoi(line[refcol]); item = atoi(line[itemcol]); strcpy(itemstr, line[itemcol]); disc = atoi(line[disccol]); ser = atoi(line[sercol]+3); act = atoi(line[actcol]); p = line[cmtcol] - 1; // while ( *++p == ' ' ) ; // count initial spaces in a comment // if ( p - line[cmtcol] >= 3 ) // more that 2 initial spaces -- really an Intercode RH comment // { *--p = ';'; // so put it in the RH field // line[cmtcol] = p; // } while ( *++p != 0 ) // find & if ( *p == '&' && *(p+1) == 'l' ) // found < { *p = '<'; strcpy(p+1, p+4); } if ( atoi(line[0]) == 0 ) // one of our clever markers ; else if ( strcmp(line[actcol], "PROCR") == 0 ) { curproc = ref; fprintf(fout, "SHEET;%d\n", count++); fprintf(fout, "PROCR;%d;%s\n", curproc, getcomment(line)); mode = PROCMODE; } else if ( strcmp(line[actcol], "NOTES") == 0 ) { if ( strcmp(line[disccol], "RADIX") == 0 ) i = disccol; else i = itemcol; fprintf(fout, "NOTES;%s;%s;%s\n", line[i], line[i+1], line[cmtcol]); } else if ( strcmp(line[actcol], "CONST") == 0 ) { if ( disc == 1 || item == 1 ) disc = 1; fprintf(fout, "SHEET;%d\n", count++); fprintf(fout, "CONST;%d;%d;%s\n", ref, disc, getcomment(line)); mode = CONSTLONG; } else if ( strcmp(line[actcol], "TABLE") == 0 ) { if ( disc == 0 ) disc = item; fprintf(fout, "SHEET;%d\n", count++); fprintf(fout, "TABLE;%d;%d;%s\n", ref, disc, getcomment(line)); mode = TABLEMODE; } else { if ( ref >= 100 && ref < 999 ) sprintf(itemstr, "%d", item - 2); if ( mode == TABLEMODE ) { ref = atoi(line[1]); // we will have looked at the wrong columns item = atoi(line[2]); if ( ref >= 100 && ref < 999 ) sprintf(line[2]=itemstr, "%d", item - 2); fprintf(fout, "%d;%d;%s;%s;%s;%s;%s;%s;%s;%s;%s;%s;%s;%s;%s\n", ser-2, ref, line[2], line[3], line[4], line[5], line[6], line[7], line[8], line[9], line[10], line[11], line[12], line[13], line[14]); } else if ( mode == CONSTLONG ) fprintf(fout, "%d;%s%s\n", ser-2, line[refcol], line[cmtcol]); else if ( act >= 40 && act < 50 ) // PROCMODE I/O fprintf(fout, "%d;%s;%s;%s;%s;%s;%s;%s\n", ser-2, line[actcol], line[refcol], line[itemcol], line[disccol], line[modcol], line[litcol], line[cmtcol]); else if ( act != 168 ) // PROCMODE -- but not our padding line { if ( *(p = line[actcol]) == '7' || *p == '8' ) // jump or subroutine call if ( *(p = line[cmtcol]) == '>' ) // Leo III right arrow (i.e. goto) *p = 'g'; if ( *(p = line[refcol]) == 0 ) // blank ref column p = " "; fprintf(fout, "%d;%s;%s;%s;%s;%s;%s;%s\n", ser-2, line[actcol], p, itemstr, line[disccol], line[modcol], line[litcol], line[cmtcol]); } } line = readline(fin); } src[srcp++] = lastline; // terminates address searches src[srcp] = NULL; fprintf(fout, "END\n"); fclose(fout); }