1 /* pphs - a pretty printer for Haskell code */
5 #define MAXLINELENGTH 256
7 enum face {KW, ID, IS, SU, ST, CO, NU, MA, SP, LC, RC, CR, BF, FQ, EQ, DQ, QD, EE, DC, DP, CP, LE, GE, LA, RA, RR, TI, BE};
8 /* Possible values of typeface */
10 int widecolons = 0; /* User may want space between double colons */
11 int subscripts = 0; /* User may want subscripts after '_' in identifiers */
12 int tablength = 8; /* User's input file tablength */
14 typedef struct ElementType_Tag { /* Basic storage unit */
15 char chars[MAXLINELENGTH]; /* Characters */
16 enum face typeface[MAXLINELENGTH]; /* Typefaces */
17 int indentation, length, col; /* Indentation level, non-empty length, column level */
20 typedef struct StackNodeType_Tag *Link; /* Stack-related types */
21 typedef struct StackNodeType_Tag {
22 ElementType Element; /* Stack item */
23 Link Next; /* Link to next node */
25 typedef StackNodeType *StackNodePtr;
26 typedef StackNodePtr StackType;
28 typedef int QueueSizeType; /* Queue-related types */
29 typedef struct QueueNodeType_Tag *Connection;
30 typedef struct QueueNodeType_Tag {
31 ElementType Element; /* Queue item */
32 Connection Next; /* Link to next node */
34 typedef QueueNodeType *QueueNodePtr;
35 typedef struct QueueType_Tag {
36 QueueNodePtr Front, Rear;
40 FILE *ifptr; /* input file pointer */
42 /* * * STACK FUNCTIONS * * */
44 CreateStack() /* Returns an empty stack */
50 IsEmptyStack(s) /* Returns 1 if s is empty, 0 otherwise */
57 Push(s, x) /* Returns stack with x pushed onto s */
63 p = (StackNodeType *) malloc(sizeof(StackNodeType));
65 fprintf(stderr, "pphs: Stack is too big\n");
76 Top(s) /* Returns value of top element in s */
83 Pop(s) /* Returns stack with top element of s popped off */
94 PopSym(s) /* Returns stack with top element of s popped off without freeing */
100 /* free(s); As PopSym is called within a function, free would free space needed later */
103 /* * * QUEUE FUNCTIONS * * */
105 CreateQueue() /* Returns an empty queue */
116 IsEmptyQueue(q) /* Returns 1 if q is empty, 0 otherwise */
119 return(q.Front == NULL);
123 LengthOfQueue(q) /* Returns length of q */
130 FrontOfQueue(q) /* Returns pointer to front of q */
137 RearOfQueue(q) /* Returns pointer to rear of q */
144 AddToQueue(q, x) /* Adds item x to rear of queue q */
150 p = (QueueNodeType *) malloc(sizeof(QueueNodeType));
152 fprintf(stderr, "pphs: Queue is too big\n");
161 (*(q.Rear)).Next = p;
169 TakeFromQueue(q) /* Removes front item from queue */
174 if (q.Front == NULL) {
175 fprintf(stderr, "pphs: Stack underflow\n");
180 q.Front = (*(q.Front)).Next;
188 /* * * TYPEFACE FUNCTIONS * * */
190 IsMathsChar(c) /* Returns 1 if c is a character to be in maths */
193 return((c == '[') || (c == ']') || (c == '/') || (c == ',') || (c == '!')
194 || (c == ':') || (c == ';') || (c == '(') || (c == ')') || (c == '&')
195 || (c == '#') || (c == '+') || (c == '-') || (c == '<') || (c == '>')
196 || (c == '{') || (c == '}') || (c == '=') || (c == '|') || (c == '\'')
201 ChangeTypeface(store, length, finish, tf) /* Changes the typeface to tf in store
202 for length until finish */
209 for (counter = (finish - length); counter < finish; counter++)
210 store.typeface[counter] = tf;
215 CheckForDoubleChar(store, position) /* Checks for double character
216 in store.chars[position - 2..position - 1],
217 if found alters typeface */
221 if ((position >= 2) && (store.typeface[position - 2] != DC)) {
222 if ((store.chars[position - 2] == '-') && (store.chars[position - 1] == '-')) {
223 store.typeface[position - 2] = LC; /* Haskell "--" line comment */
224 store.typeface[position - 1] = LC;
226 else if ((store.chars[position - 2] == '{') && (store.chars[position - 1] == '-')) {
227 store.typeface[position - 2] = RC; /* Haskell "{-" regional comment begin */
228 store.typeface[position - 1] = DC;
230 else if ((store.chars[position - 2] == '-') && (store.chars[position - 1] == '}')) {
231 store.typeface[position - 2] = CR; /* Haskell "-}" regional comment end */
232 store.typeface[position - 1] = DC;
234 else if ((store.chars[position - 2] == '+') && (store.chars[position - 1] == '+')) {
235 store.typeface[position - 2] = DP; /* Double plus */
236 store.typeface[position - 1] = DC;
238 else if ((store.chars[position - 2] == ':') && (store.chars[position - 1] == '+')) {
239 store.typeface[position - 2] = CP; /* Colon plus */
240 store.typeface[position - 1] = DC;
242 else if ((store.chars[position - 2] == '<') && (store.chars[position - 1] == '=')) {
243 store.typeface[position - 2] = LE; /* Less than or equal to */
244 store.typeface[position - 1] = DC;
246 else if ((store.chars[position - 2] == '>') && (store.chars[position - 1] == '=')) {
247 store.typeface[position - 2] = GE; /* Greater than or equal to */
248 store.typeface[position - 1] = DC;
250 else if ((store.chars[position - 2] == '<') && (store.chars[position - 1] == '-')) {
251 store.typeface[position - 2] = LA; /* Leftarrow */
252 store.typeface[position - 1] = DC;
254 else if ((store.chars[position - 2] == '-') && (store.chars[position - 1] == '>')) {
255 store.typeface[position - 2] = RA; /* Rightarrow */
256 store.typeface[position - 1] = DC;
258 else if ((store.chars[position - 2] == '=') && (store.chars[position - 1] == '>')) {
259 store.typeface[position - 2] = RR; /* Double rightarrow */
260 store.typeface[position - 1] = DC;
262 else if (((store.chars[position - 2] == '*') && (store.chars[position - 1] == '*'))
263 || ((store.chars[position - 2] == '^') && (store.chars[position - 1] == '^'))) {
264 store.typeface[position - 2] = MA; /* Exponent, ie not Times */
265 store.typeface[position - 1] = MA;
272 IsHaskellPunc(c) /* Returns 1 if c is a punctuation mark not part of identifier */
275 return((c == ' ') || (c == ',') || (c == '@') || (c == '#') || (c == '$')
276 || (c == '%') || (c == '&') || (c == '*') || (c == '(') || (c == ')')
277 || (c == '-') || (c == '+') || (c == '=') || (c == '\\') || (c == '|')
278 || (c == '[') || (c == ']') || (c == '{') || (c == '}') || (c == ':')
279 || (c == ';') || (c == '"') || (c == '~') || (c == '?') || (c == '/')
280 || (c == '<') || (c == '>') || (c == '^'));
284 IsKeyWord(str) /* Returns 1 if str is a keyword to be in keyword font */
285 char str[MAXLINELENGTH];
287 return((!(strcmp(str, "case"))) || (!(strcmp(str, "class")))
288 || (!(strcmp(str, "data"))) || (!(strcmp(str, "default")))
289 || (!(strcmp(str, "deriving"))) || (!(strcmp(str, "else")))
290 || (!(strcmp(str, "hiding"))) || (!(strcmp(str, "if")))
291 || (!(strcmp(str, "import"))) || (!(strcmp(str, "in")))
292 || (!(strcmp(str, "infix"))) || (!(strcmp(str, "infixl")))
293 || (!(strcmp(str, "infixr"))) || (!(strcmp(str, "instance")))
294 || (!(strcmp(str, "interface"))) || (!(strcmp(str, "let")))
295 || (!(strcmp(str, "module"))) || (!(strcmp(str, "of")))
296 || (!(strcmp(str, "renaming"))) || (!(strcmp(str, "then")))
297 || (!(strcmp(str, "to"))) || (!(strcmp(str, "type")))
298 || (!(strcmp(str, "where"))));
302 KeyWord(c, store, position) /* Returns length of keyword if a keyword ends
303 at store.chars[position - 1] */
308 int counter, start, end = position - 1, keywordlen = 0;
309 char str[MAXLINELENGTH];
311 if ((!isalpha(c)) && (c != '_') && (c != '\'') && (position)) {
312 for (counter = end; (counter >= 0) && ((isalpha(store.chars[counter]))
313 || (c == '_') || (c == '\''))
314 && (counter >= store.indentation); counter--) {
315 ; /* Just count letters */
318 for (counter = 0; counter + start <= end; counter++) {
319 str[counter] = store.chars[counter + start]; /* Copy letters into str */
321 str[counter] = '\0'; /* Add null character to end */
322 if (IsKeyWord(str)) /* Checks word in str is keyword */
323 keywordlen = strlen(str); /* and measures it */
329 CheckForKeyword(c, store, position) /* Returns store with any possible keyword
330 ending at store.chars[position - 1]
331 identified as such in store.typeface */
336 if (KeyWord(c, store, position))
337 store = ChangeTypeface(store, KeyWord(c, store, position), position, KW);
342 IsNumber(c, store, position, statesok) /* Returns 1 if c forms part of a number */
345 int position, statesok;
347 int counter, foundident = 0, foundpunc = 0;
349 if (((isdigit(c)) || (c == 'e') || (c == 'E') || (c == '|') || (c == '.'))
351 counter = position - 1;
352 while ((isdigit(store.chars[counter])) && (counter >= 0))
354 if (((store.chars[counter] == '+') || (store.chars[counter] == '-'))
355 && ((store.chars[counter - 1] == 'e') || (store.chars[counter - 1] == 'E'))
358 else if (((store.chars[counter] == 'e') || (store.chars[counter] == 'E'))
361 while ((isdigit(store.chars[counter])) && (counter >= 0))
363 if ((store.chars[counter] == '.') && (counter > 1))
365 while ((isdigit(store.chars[counter])) && (counter >= 0))
367 if ((isalpha(store.chars[counter])) && (counter >= 0))
368 foundident = 1; /* ie not number */
369 else if ((IsHaskellPunc(store.chars[counter])) || (counter < 0))
370 foundpunc = 1; /* ie is number */
374 /* * * LINE SELECTION FUNCTIONS * * */
376 SelectSkipLine(s, store, linecounter) /* Returns store containing line for skipover */
384 if (!(IsEmptyStack(s))) {
385 while (((Top(s)).length <= linecounter) || ((Top(s)).indentation >= linecounter)) {
388 if (IsEmptyStack(s)) {
389 counter = temp.length;
390 while (counter < linecounter) {
391 temp.chars[counter] = ' ';
392 temp.typeface[counter++] = SP;
394 temp.chars[counter] = '\0'; /* Add null character to end */
401 else { /* Stack is empty */
402 counter = store.length;
403 while (counter < linecounter) {
404 store.chars[counter] = ' ';
405 store.typeface[counter++] = SP;
407 store.chars[counter] = '\0'; /* Add null character to end */
411 /* * * STORING FUNCTIONS * * */
413 CreateStore() /* Returns an empty store */
417 strcpy(store.chars, "");
419 store.indentation = 0;
425 StoreSpace(store, position) /* Stores a space in the store at current position */
429 store.chars[position] = ' ';
430 store.typeface[position] = SP;
433 /* * * WRITING FUNCTIONS * * */
435 WriteStartFace(tf) /* Writes LaTeX typeface commands for start of section */
438 if (tf == KW) /* Keywords */
439 printf("{\\keyword ");
440 else if ((tf == ID) || (tf == IS)) /* Identifiers */
442 else if (tf == ST) /* Strings */
444 else if (tf == CO) /* Comments */
446 else if (tf == NU) /* Numbers */
448 else if ((tf == MA) || (tf == TI)) /* Various maths */
453 WriteFinishFace(tf) /* Writes LaTeX typeface commands for end of section */
456 if ((tf == KW) || (tf == ID) || (tf == ST) || (tf == CO)
457 || (tf == NU)) /* Keywords, identifiers, strings, comments or numbers */
459 else if ((tf == MA) || (tf == TI)) /* Various maths */
461 else if (tf == IS) /* Subscripts in identifiers */
466 WriteSpaces(store, counter, finish) /* Writes consecutive spaces,
467 returning new counter value */
471 int spaces = 0; /* The number of spaces found */
473 for (; (store.typeface[counter] == SP) && (counter < finish); counter++)
475 printf("\\xspa{%d}", spaces);
480 WriteChar(store, counter, finish) /* Writes charater, returning new counter value */
484 if (store.typeface[counter] == SP) /* Space */
485 printf("\\xspa1"); /* Redundant */
486 else if (store.typeface[counter] == BE) /* Bar under equals sign */
488 else if (store.typeface[counter] == DP) { /* Double plus */
489 if ((counter < finish - 1) && (store.typeface[counter + 1] == DC)) {
490 printf("\\plusplus");
494 else if (store.typeface[counter] == CP) { /* Colon plus */
495 if ((counter < finish - 1) && (store.typeface[counter + 1] == DC)) {
500 else if (store.typeface[counter] == LE) { /* Less than or equal to */
501 if ((counter < finish - 1) && (store.typeface[counter + 1] == DC)) {
506 else if (store.typeface[counter] == GE) { /* Greater than or equal to */
507 if ((counter < finish - 1) && (store.typeface[counter + 1] == DC)) {
512 else if (store.typeface[counter] == LA) { /* Leftarrow */
513 if ((counter < finish - 1) && (store.typeface[counter + 1] == DC)) {
514 printf("$\\leftarrow$");
518 else if (store.typeface[counter] == RA) { /* Rightarrow */
519 if ((counter < finish - 1) && (store.typeface[counter + 1] == DC)) {
520 printf("$\\rightarrow$");
524 else if (store.typeface[counter] == RR) { /* Double rightarrow */
525 if ((counter < finish - 1) && (store.typeface[counter + 1] == DC)) {
526 printf("$\\Rightarrow$");
530 else if (store.typeface[counter] == RC) { /* Regional comment begin */
531 if ((counter < finish - 1) && (store.typeface[counter + 1] == DC)) {
532 printf("{\\com \\{-\\/}");
536 printf("{\\com \\{\\/}");
538 else if (store.typeface[counter] == CR) { /* Regional comment end */
539 if ((counter < finish - 1) && (store.typeface[counter + 1] == DC)) {
540 printf("{\\com -\\}\\/}");
544 printf("{\\com -\\/}");
546 else if ((store.typeface[counter] == LC) && (store.chars[counter] == '-'))
547 printf("{\\rm -}"); /* Comment - problem: "--" becomes "-" in LaTeX so fix done */
548 else if (store.chars[counter] == '\\')
549 printf("\\hbox{$\\setminus$}"); /* Backslash */
550 else if (store.chars[counter] == '*') {
551 if (store.typeface[counter] == TI)
552 printf("\\times "); /* Multiplication */
554 printf("*"); /* Other star symbols, eg Exponent */
556 else if ((store.chars[counter] == '_') && (store.typeface[counter] == SU)) {
557 if ((counter < finish - 1) && (store.typeface[counter + 1] == IS))
558 printf("$_"); /* Subscript character */
560 else if (store.chars[counter] == '^')
561 printf("\\char'136 "); /* Up-arrow */
562 else if (store.chars[counter] == '~')
563 printf("\\char'176 "); /* Tilda */
564 else if ((store.chars[counter] == ':') && (store.chars[counter - 1] == ':')
566 printf("\\,:"); /* Double colon */
567 else if (store.chars[counter] == '"') {
568 if ((counter) && ((store.chars[counter - 1] == '"')
569 || (store.chars[counter - 1] == '\'')))
570 printf("\\,"); /* If previous character was a quote, leave a little space */
571 if (store.typeface[counter] == DQ)
572 printf("{\\rm ``}"); /* Open doublequote */
573 else if (store.typeface[counter] == QD)
574 printf("{\\rm \"}"); /* Close doublequote */
576 printf("{\\rm \\char'175}"); /* Escape doublequote in string */
578 else if (store.chars[counter] == '\'') {
579 if ((counter) && ((store.chars[counter - 1] == '"')
580 || ((store.chars[counter - 1] == '\'')
581 && ((store.typeface[counter - 1] != MA)
582 || (store.typeface[counter] != MA)))))
583 printf("\\,"); /* If previous character was a quote, leave a little space
584 except when it's a double prime */
585 if (store.typeface[counter] == FQ)
586 printf("\\forquo "); /* Forward single quote */
587 else if (store.typeface[counter] == EQ)
588 printf("\\escquo "); /* Escape single quote */
589 else if (store.typeface[counter] == BF) {
590 if ((counter + 1 < store.length) && (store.typeface[counter + 1] == BF)
591 && (counter + 1 != store.indentation)) {
592 printf("{\\com \'\'\\/}"); /* Closing LaTeX style quote */
596 printf("{\\com \'\\/}"); /* Single quote following backquote in comment */
599 printf("\'"); /* Prime */
601 else if (store.chars[counter] == '{')
602 printf("\\hbox{$\\cal \\char'146$}"); /* Open curly bracket */
603 else if (store.chars[counter] == '}')
604 printf("\\hbox{$\\cal \\char'147$}"); /* Close curly bracket */
605 else if ((counter) && (store.chars[counter - 1] == '[') && (store.chars[counter] == ']'))
606 printf("\\,]"); /* Leave small gap between adjacent square brackets */
607 else if ((store.chars[counter] == '$') || (store.chars[counter] == '%')
608 || (store.chars[counter] == '_') || (store.chars[counter] == '#')
609 || (store.chars[counter] == '&')) /* Various characters needing '\' for LaTeX */
610 printf("\\%c", store.chars[counter]);
611 else /* Other characters */
612 printf("%c", store.chars[counter]);
617 WriteSkipover(store) /* Writes the skipover portion of line in store */
622 printf("\\skipover{"); /* Write opening LaTeX skipover command */
623 WriteStartFace(store.typeface[counter]); /* Write opening LaTeX typeface command */
624 if (store.typeface[counter] == SP)
625 counter = WriteSpaces(store, counter, store.indentation); /* Write spaces */
627 counter = WriteChar(store, counter, store.indentation); /* Write character */
628 for (counter++; counter < store.indentation; counter++){ /* until end of skipover */
629 if (store.typeface[counter - 1] != store.typeface[counter]) { /* If typeface change */
630 WriteFinishFace(store.typeface[counter - 1]); /* write closing typeface command */
631 WriteStartFace(store.typeface[counter]); /* write opening LaTeX typeface command */
633 if (store.typeface[counter] == SP)
634 counter = WriteSpaces(store, counter, store.indentation); /* Write spaces */
636 counter = WriteChar(store, counter, store.indentation); /* Write character */
638 if (store.typeface[counter - 1] == SU)
639 ; /* If indentation is under subscript don't open math section */
641 WriteFinishFace(store.typeface[counter - 1]); /* Write closing LaTeX typeface command */
642 printf("}"); /* Write closing LaTeX skipover command */
646 WriteWords(store) /* Writes rest of line, starting at indentation level */
649 int counter = store.indentation;
650 int intabular = 0; /* Boolean: is in tabular section for internal alignment */
652 WriteStartFace(store.typeface[counter]); /* Write opening LaTeX typeface command */
653 if (store.typeface[counter] == SP)
654 counter = WriteSpaces(store, counter, store.length); /* Write spaces */
656 counter = WriteChar(store, counter, store.length); /* Write character */
657 for (counter++; counter < store.length; counter++){ /* until end of word */
658 if ((store.col) && (store.col == counter)) {
660 if (store.chars[counter - 1] == ':')
664 if (store.typeface[counter - 1] != store.typeface[counter]) /* If typeface change */
665 WriteFinishFace(store.typeface[counter - 1]); /* Write closing typeface command */
666 if ((store.typeface[counter] == SP) && (intabular)) {
670 if ((store.typeface[counter - 1] != store.typeface[counter]) /* If typeface change */
671 && ((store.chars[counter] != ':') || (store.col != counter + 1)))
672 WriteStartFace(store.typeface[counter]); /* Write opening LaTeX typeface command */
673 if (store.typeface[counter] == SP)
674 counter = WriteSpaces(store, counter, store.length); /* Write spaces */
675 else if ((store.chars[counter] != ':') || (!store.col) || (store.col != counter + 1))
676 counter = WriteChar(store, counter, store.length); /* Write character */
678 WriteFinishFace(store.typeface[counter - 1]); /* Write closing LaTeX typeface command */
682 WriteLine(store, needed) /* Writes the line in store,
683 only writing LaTeX newline if needed */
687 if (store.indentation)
688 WriteSkipover(store);
689 if (store.indentation < store.length)
692 printf("\\\\"); /* LaTeX newline character */
697 WriteQueue(q) /* Writes lines, removing them from queue,
698 leaves last line in queue if not in tabular section */
703 if ((!(IsEmptyQueue(q))) && ((*(FrontOfQueue(q))).Element.col)) {
704 printf("\\begin{tabular}{@{}l@{\\xspa1}c@{}l}\n");
707 while (LengthOfQueue(q) > !intabular) {
708 WriteLine((*(FrontOfQueue(q))).Element, 1); /* LaTeX newline character is needed */
709 q = TakeFromQueue(q);
712 printf("\\end{tabular}\\\\\n");
717 WriteRestOfQueue(q) /* Writes all lines, removing them from queue,
718 doesn't have LaTeX newline after last line */
723 if ((!(IsEmptyQueue(q))) && ((*(FrontOfQueue(q))).Element.col)) {
724 printf("\\begin{tabular}{@{}l@{\\xspa1}c@{}l}\n");
727 while (!(IsEmptyQueue(q))) {
728 WriteLine((*(FrontOfQueue(q))).Element, (LengthOfQueue(q) > 1)); /* Last line doesn't
729 need LaTeX newline character */
730 q = TakeFromQueue(q);
733 printf("\\end{tabular}");
734 if (!IsEmptyQueue(q)) /* Last line doesn't need LaTeX newline character */
742 main (argc, argv) /* * * MAIN PROGRAM * * */
746 int tripped = 1, instring = 0, instringincomment = 0, inlinecomment = 0;
747 int incharquote = 0, incharquoteincomment = 0, inbackquoteincomment = 0;
749 /* Booleans - just taken new line, in string, in string inside comment, in line comment,
750 in character quote, in character quote inside comment, in backquote inside comment,
752 int linecounter = 0, indentcounter = 0, inregcomment = 0, pos;
753 /* Counters: current position on line, indentation of current line,
754 nesting level of regional comments, position marker */
755 char c; /* Character */
756 StackType s; /* Stack of previous longest lines */
757 QueueType q; /* Queue of lines waiting to be printed */
758 ElementType store; /* Store of letters, typefaces and non-empty length */
760 if ((argc == 3) && (argv[1][0] == '-')) { /* If options specified with call */
761 if (strstr(argv[1], "s")) /* if -s option, subscripts in identifiers wanted */
763 if (strstr(argv[1], "t")) { /* if -tX option, tab characters are X spaces */
764 for (pos = 1; (argv[1][pos] != 't'); pos++) /* find 't' */
766 for (pos++, tablength = 0; isdigit(argv[1][pos]); pos++) /* read number */
767 tablength = (tablength * 10) + (argv[1][pos] - '0');
769 if (strstr(argv[1], "w")) /* if -w option called, wide double colons wanted */
772 else if (argc == 2) /* If no options */
774 else { /* If not called with pphs and a filename */
775 fprintf(stderr, "pphs: Call with one file name\n");
779 if ((strcspn(argv[argc - 1], ".") == strlen(argv[argc - 1])) /* If filename has no extention */
780 && ((ifptr = fopen(argv[argc - 1], "r")) == NULL)) /* and no plain file of that name */
781 strcat(argv[argc - 1], ".hs"); /* add a ".hs" extention */
782 if ((ifptr = fopen(argv[argc - 1], "r")) == NULL) { /* Open input file */
783 fprintf(stderr, "pphs: File could not be opened\n"); /* eg isn't there */
788 printf("\\begin{tabbing}\n"); /* Start of Haskell program */
790 store = CreateStore(); /* an empty one */
791 s = CreateStack(); /* an empty one */
792 q = CreateQueue(); /* an empty one */
794 fscanf(ifptr, "%c", &c); /* Read character */
795 while (!feof(ifptr)) { /* While not at end of input file */
796 while ((isspace(c)) && (!(feof(ifptr)))) { /* Read blank characters */
799 linecounter++; /* Count leading spaces */
801 store = StoreSpace(store, linecounter++); /* Store intermediate
803 if (store.length < linecounter)
804 store.chars[linecounter] = '\0'; /* Add null character to end */
806 fscanf(ifptr, "%c", &c); /* Read next character */
808 else if (c == '\t') {
810 linecounter += (tablength - (linecounter % tablength));
812 store = StoreSpace(store, linecounter++);
813 for (; linecounter % tablength; linecounter++)
814 store = StoreSpace(store, linecounter);
815 if (store.length < linecounter)
816 store.chars[linecounter] = '\0'; /* Add null character to end */
818 fscanf(ifptr, "%c", &c); /* Read next character */
820 else if (c == '\n') {
821 tripped = 1; /* Just taken a new line */
823 if (!(IsEmptyStack(s)))
824 while (((Top(s)).length <= store.length)
825 && ((Top(s)).indentation >= store.length)) {
830 if (store.length > 0) { /* Push non-empty line onto indentation stack */
831 store.indentation = indentcounter;
834 if (!(IsEmptyQueue(q))) {
835 if ((store.col != (*(FrontOfQueue(q))).Element.col)
836 || (!(*(FrontOfQueue(q))).Element.col))
837 q = WriteQueue(q); /* If internal alignment changes or there is none
840 q = AddToQueue(q, store); /* Add to writing queue */
841 linecounter = 0; /* Get ready to count leading spaces */
842 store.length = linecounter;
843 fscanf(ifptr, "%c", &c); /* Read next character */
848 indentcounter = linecounter;
849 store.indentation = linecounter;
852 if ((tripped) && (linecounter)) { /* Skipover necessary for indentation */
853 store = SelectSkipLine(s, store, linecounter);
854 store.indentation = linecounter;
858 tripped = 0; /* No longer just taken new line */
859 while ((!(isspace(c))) && (!(feof(ifptr)))) { /* Read word */
860 if ((linecounter > 1) && (!IsEmptyQueue(q))
861 && ((*(RearOfQueue(q))).Element.length >= linecounter)
862 && (linecounter > store.indentation)
863 && (linecounter > (*(RearOfQueue(q))).Element.indentation)
864 && (store.chars[linecounter - 1] == ' ')
865 && ((((*(RearOfQueue(q))).Element.chars[linecounter - 1] == ' ')
866 && ((c == (*(RearOfQueue(q))).Element.chars[linecounter])
868 && ((*(RearOfQueue(q))).Element.chars[linecounter] == ':')
869 && ((*(RearOfQueue(q))).Element.chars[linecounter + 1] == ':'))))
870 || (((*(RearOfQueue(q))).Element.chars[linecounter - 1] == ':')
871 && ((*(RearOfQueue(q))).Element.chars[linecounter] == ':')
873 && ((store.chars[linecounter - 2] == ' ')
874 || ((*(RearOfQueue(q))).Element.chars[linecounter - 2] == ' '))
875 && (((*(RearOfQueue(q))).Element.col == 0)
876 || ((*(RearOfQueue(q))).Element.col == linecounter))) {
877 store.col = linecounter; /* Identify any internal alignment */
878 (*(RearOfQueue(q))).Element.col = linecounter;
880 if ((c == '"') && (!incharquote) /* String outside comments */
881 && (!inregcomment) && (!inlinecomment)) {
882 if (((linecounter) && (store.chars[linecounter - 1] != '\\'))
884 instring = !instring;
886 else if ((c == '"') && (!incharquoteincomment) /* String inside comment */
887 && (!inbackquoteincomment)
888 && ((inregcomment) || (inlinecomment))) {
889 if (((linecounter) && (store.chars[linecounter - 1] != '\\'))
891 instringincomment = !instringincomment;
893 else if ((c == '`') && ((inlinecomment) || (inregcomment))) {
894 if ((linecounter) && (store.chars[linecounter - 1] == '`'))
895 inbackquoteincomment = 2; /* Opening LaTeX style quote in comment */
897 inbackquoteincomment = !inbackquoteincomment; /* Backquote in comment */
899 else if ((linecounter) && (!inlinecomment) && (!instring)) {
900 if ((store.chars[linecounter - 1] == '{') && (c == '-'))
901 inregcomment++; /* Haskell "{-" regional comment begin */
902 else if ((store.chars[linecounter - 1] == '-') && (c == '}')) {
903 inregcomment--; /* Haskell "-}" regional comment end */
904 instringincomment = 0;
905 incharquoteincomment = 0;
906 inbackquoteincomment = 0;
910 if ((!IsEmptyQueue(q))
911 && ((((*(RearOfQueue(q))).Element.chars[linecounter] == '=')
912 && (linecounter == store.indentation))
913 || ((*(RearOfQueue(q))).Element.typeface[linecounter] == BE)))
914 store.typeface[linecounter] = BE;
916 store.typeface[linecounter] = MA;
918 else if ((c == '\'') && (linecounter) && (store.chars[linecounter - 1] == '\\'))
919 store.typeface[linecounter] = EQ; /* Escape character quote */
920 else if ((c == '\'') && (!instring) && (!inregcomment) && (!inlinecomment)) {
921 if (((linecounter) && (store.chars[linecounter - 1] != '\\')
922 && ((IsHaskellPunc(store.chars[linecounter - 1])) || (incharquote)))
924 incharquote = !incharquote;
925 store.typeface[linecounter] = FQ; /* Character quote */
928 store.typeface[linecounter] = MA; /* Prime */
930 else if ((c == '\'') && (!instringincomment)
931 && ((inregcomment) || (inlinecomment))) {
932 if (((linecounter) && (store.chars[linecounter - 1] != '\\')
933 && ((IsHaskellPunc(store.chars[linecounter - 1]))
934 || (incharquoteincomment)))
936 incharquoteincomment = !incharquoteincomment;
937 store.typeface[linecounter] = FQ; /* Character quote in comment */
939 else if (inbackquoteincomment) {
940 inbackquoteincomment--;
941 store.typeface[linecounter] = BF; /* `x' character quote in comment */
944 store.typeface[linecounter] = MA; /* Prime */
947 if ((!incharquote) && (!incharquoteincomment) && (!inbackquoteincomment)
948 && ((instring) || (instringincomment))) {
949 if (((linecounter) && (store.chars[linecounter - 1] != '\\'))
951 store.typeface[linecounter] = DQ; /* Open doublequote */
952 else if (store.chars[linecounter - 1] == '\\')
953 store.typeface[linecounter] = EE; /* Escape doublequote */
955 else if ((!incharquote) && (!incharquoteincomment) && (!inbackquoteincomment)) {
956 if (((linecounter) && (store.chars[linecounter - 1] != '\\'))
958 store.typeface[linecounter] = QD; /* Close doublequote */
959 else if (store.chars[linecounter - 1] == '\\')
960 store.typeface[linecounter] = EE; /* Escape doublequote */
963 store.typeface[linecounter] = EE; /* Character quote of doublequote */
966 if ((inlinecomment) || (inregcomment))
967 store.typeface[linecounter] = CO;
969 store.typeface[linecounter] = MA;
971 else if ((linecounter) && (subscripts) && (c == '_')
972 && (store.typeface[linecounter - 1] == ID))
973 store.typeface[linecounter] = SU; /* Subscript in identifier */
975 store.typeface[linecounter] = TI; /* Times - may be changed by double char */
976 else if (IsMathsChar(c))
977 store.typeface[linecounter] = MA; /* Maths characters */
978 else if (IsNumber(c, store, linecounter,
979 ((!inregcomment) && (!instring) && (!inlinecomment))))
980 store.typeface[linecounter] = NU; /* Numbers */
981 else if ((instring) || (incharquote))
982 store.typeface[linecounter] = ST; /* Characters in strings */
983 else if ((inlinecomment) || (inregcomment))
984 store.typeface[linecounter] = CO; /* Characters in comments */
987 store.typeface[linecounter] = IS; /* Subscript identifiers */
989 store.typeface[linecounter] = ID; /* Others */
992 if ((store.typeface[linecounter - 1] == IS)
993 && (store.typeface[linecounter] != IS))
994 insub = 0; /* End of subscript identifier */
995 store.chars[linecounter++] = c; /* Place character in store */
996 if (linecounter > store.indentation + 1)
997 store = CheckForDoubleChar(store, linecounter);
998 if ((store.typeface[linecounter - 1] == LC) && (!inregcomment)
999 && (!instring) && (!incharquote)) {
1000 instringincomment = 0;
1001 incharquoteincomment = 0;
1002 inbackquoteincomment = 0;
1005 else if ((store.typeface[linecounter - 1] == SU)
1006 && (linecounter != store.indentation))
1008 fscanf(ifptr, "%c", &c); /* Read next character */
1011 if ((!inregcomment) && (!inlinecomment) && (!instring))
1012 store = CheckForKeyword(c, store, linecounter); /* Keywords not in comments or
1013 strings to be in keyword typeface */
1016 store.chars[linecounter] = '\0'; /* String terminating null character */
1017 store.length = linecounter;
1019 if ((!tripped) && (!store.col)) /* If last line not in internal alignment */
1020 q = WriteQueue(q); /* write previous lines which might */
1021 if (!tripped) /* Put final line in queue if non-empty */
1022 q = AddToQueue(q, store);
1023 if (feof(ifptr)) /* Write remaining lines */
1024 q = WriteRestOfQueue(q);
1026 printf("\\end{tabbing}\n"); /* End of Haskell program */