--- /dev/null
+ /* pphs - a pretty printer for Haskell code */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#define MAXLINELENGTH 256
+
+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};
+ /* Possible values of typeface */
+
+int widecolons = 0; /* User may want space between double colons */
+int subscripts = 0; /* User may want subscripts after '_' in identifiers */
+int tablength = 8; /* User's input file tablength */
+
+typedef struct ElementType_Tag { /* Basic storage unit */
+ char chars[MAXLINELENGTH]; /* Characters */
+ enum face typeface[MAXLINELENGTH]; /* Typefaces */
+ int indentation, length, col; /* Indentation level, non-empty length, column level */
+} ElementType;
+
+typedef struct StackNodeType_Tag *Link; /* Stack-related types */
+typedef struct StackNodeType_Tag {
+ ElementType Element; /* Stack item */
+ Link Next; /* Link to next node */
+} StackNodeType;
+typedef StackNodeType *StackNodePtr;
+typedef StackNodePtr StackType;
+
+typedef int QueueSizeType; /* Queue-related types */
+typedef struct QueueNodeType_Tag *Connection;
+typedef struct QueueNodeType_Tag {
+ ElementType Element; /* Queue item */
+ Connection Next; /* Link to next node */
+} QueueNodeType;
+typedef QueueNodeType *QueueNodePtr;
+typedef struct QueueType_Tag {
+ QueueNodePtr Front, Rear;
+ QueueSizeType Length;
+} QueueType;
+
+FILE *ifptr; /* input file pointer */
+
+ /* * * STACK FUNCTIONS * * */
+StackType
+ CreateStack() /* Returns an empty stack */
+{
+ return(NULL);
+}
+
+int
+ IsEmptyStack(s) /* Returns 1 if s is empty, 0 otherwise */
+StackType s;
+{
+ return(s == NULL);
+}
+
+StackType
+ Push(s, x) /* Returns stack with x pushed onto s */
+StackType s;
+ElementType x;
+{
+ StackType p;
+
+ p = (StackNodeType *) malloc(sizeof(StackNodeType));
+ if (p == NULL) {
+ fprintf(stderr, "pphs: Stack is too big\n");
+ exit(3);
+ }
+ else {
+ (*p).Element = x;
+ (*p).Next = s;
+ return(p);
+ }
+}
+
+ElementType
+ Top(s) /* Returns value of top element in s */
+StackType s;
+{
+ return((*s).Element);
+}
+
+StackType
+ Pop(s) /* Returns stack with top element of s popped off */
+StackType s;
+{
+ StackType t;
+
+ t = (*s).Next;
+ free(s);
+ return(t);
+}
+
+StackType
+ PopSym(s) /* Returns stack with top element of s popped off without freeing */
+StackType s;
+{
+ StackType t;
+
+ t = (*s).Next;
+/* free(s); As PopSym is called within a function, free would free space needed later */
+ return(t);
+}
+ /* * * QUEUE FUNCTIONS * * */
+QueueType
+ CreateQueue() /* Returns an empty queue */
+{
+ QueueType q;
+
+ q.Front = NULL;
+ q.Rear = NULL;
+ q.Length = 0;
+ return(q);
+}
+
+int
+ IsEmptyQueue(q) /* Returns 1 if q is empty, 0 otherwise */
+QueueType q;
+{
+ return(q.Front == NULL);
+}
+
+int
+ LengthOfQueue(q) /* Returns length of q */
+QueueType q;
+{
+ return(q.Length);
+}
+
+QueueNodePtr
+ FrontOfQueue(q) /* Returns pointer to front of q */
+QueueType q;
+{
+ return(q.Front);
+}
+
+QueueNodePtr
+ RearOfQueue(q) /* Returns pointer to rear of q */
+QueueType q;
+{
+ return(q.Rear);
+}
+
+QueueType
+ AddToQueue(q, x) /* Adds item x to rear of queue q */
+QueueType q;
+ElementType x;
+{
+ QueueNodePtr p;
+
+ p = (QueueNodeType *) malloc(sizeof(QueueNodeType));
+ if (p == NULL) {
+ fprintf(stderr, "pphs: Queue is too big\n");
+ exit(4);
+ }
+ else {
+ (*p).Element = x;
+ (*p).Next = NULL;
+ if (q.Front == NULL)
+ q.Front = p;
+ else
+ (*(q.Rear)).Next = p;
+ q.Rear = p;
+ q.Length++;
+ return(q);
+ }
+}
+
+QueueType
+ TakeFromQueue(q) /* Removes front item from queue */
+QueueType q;
+{
+ QueueNodePtr p;
+
+ if (q.Front == NULL) {
+ fprintf(stderr, "pphs: Stack underflow\n");
+ exit(5);
+ }
+ else {
+ p = q.Front;
+ q.Front = (*(q.Front)).Next;
+ if (q.Front == NULL)
+ q.Rear = NULL;
+ q.Length--;
+ free(p);
+ return(q);
+ }
+}
+ /* * * TYPEFACE FUNCTIONS * * */
+int
+ IsMathsChar(c) /* Returns 1 if c is a character to be in maths */
+char c;
+{
+ return((c == '[') || (c == ']') || (c == '/') || (c == ',') || (c == '!')
+ || (c == ':') || (c == ';') || (c == '(') || (c == ')') || (c == '&')
+ || (c == '#') || (c == '+') || (c == '-') || (c == '<') || (c == '>')
+ || (c == '{') || (c == '}') || (c == '=') || (c == '|') || (c == '\'')
+ || (c == '^'));
+}
+
+ElementType
+ ChangeTypeface(store, length, finish, tf) /* Changes the typeface to tf in store
+ for length until finish */
+ElementType store;
+int length, finish;
+enum face tf;
+{
+ int counter;
+
+ for (counter = (finish - length); counter < finish; counter++)
+ store.typeface[counter] = tf;
+ return(store);
+}
+
+ElementType
+ CheckForDoubleChar(store, position) /* Checks for double character
+ in store.chars[position - 2..position - 1],
+ if found alters typeface */
+ElementType store;
+int position;
+{
+ if ((position >= 2) && (store.typeface[position - 2] != DC)) {
+ if ((store.chars[position - 2] == '-') && (store.chars[position - 1] == '-')) {
+ store.typeface[position - 2] = LC; /* Haskell "--" line comment */
+ store.typeface[position - 1] = LC;
+ }
+ else if ((store.chars[position - 2] == '{') && (store.chars[position - 1] == '-')) {
+ store.typeface[position - 2] = RC; /* Haskell "{-" regional comment begin */
+ store.typeface[position - 1] = DC;
+ }
+ else if ((store.chars[position - 2] == '-') && (store.chars[position - 1] == '}')) {
+ store.typeface[position - 2] = CR; /* Haskell "-}" regional comment end */
+ store.typeface[position - 1] = DC;
+ }
+ else if ((store.chars[position - 2] == '+') && (store.chars[position - 1] == '+')) {
+ store.typeface[position - 2] = DP; /* Double plus */
+ store.typeface[position - 1] = DC;
+ }
+ else if ((store.chars[position - 2] == ':') && (store.chars[position - 1] == '+')) {
+ store.typeface[position - 2] = CP; /* Colon plus */
+ store.typeface[position - 1] = DC;
+ }
+ else if ((store.chars[position - 2] == '<') && (store.chars[position - 1] == '=')) {
+ store.typeface[position - 2] = LE; /* Less than or equal to */
+ store.typeface[position - 1] = DC;
+ }
+ else if ((store.chars[position - 2] == '>') && (store.chars[position - 1] == '=')) {
+ store.typeface[position - 2] = GE; /* Greater than or equal to */
+ store.typeface[position - 1] = DC;
+ }
+ else if ((store.chars[position - 2] == '<') && (store.chars[position - 1] == '-')) {
+ store.typeface[position - 2] = LA; /* Leftarrow */
+ store.typeface[position - 1] = DC;
+ }
+ else if ((store.chars[position - 2] == '-') && (store.chars[position - 1] == '>')) {
+ store.typeface[position - 2] = RA; /* Rightarrow */
+ store.typeface[position - 1] = DC;
+ }
+ else if ((store.chars[position - 2] == '=') && (store.chars[position - 1] == '>')) {
+ store.typeface[position - 2] = RR; /* Double rightarrow */
+ store.typeface[position - 1] = DC;
+ }
+ else if (((store.chars[position - 2] == '*') && (store.chars[position - 1] == '*'))
+ || ((store.chars[position - 2] == '^') && (store.chars[position - 1] == '^'))) {
+ store.typeface[position - 2] = MA; /* Exponent, ie not Times */
+ store.typeface[position - 1] = MA;
+ }
+ }
+ return(store);
+}
+
+int
+ IsHaskellPunc(c) /* Returns 1 if c is a punctuation mark not part of identifier */
+char c;
+{
+ return((c == ' ') || (c == ',') || (c == '@') || (c == '#') || (c == '$')
+ || (c == '%') || (c == '&') || (c == '*') || (c == '(') || (c == ')')
+ || (c == '-') || (c == '+') || (c == '=') || (c == '\\') || (c == '|')
+ || (c == '[') || (c == ']') || (c == '{') || (c == '}') || (c == ':')
+ || (c == ';') || (c == '"') || (c == '~') || (c == '?') || (c == '/')
+ || (c == '<') || (c == '>') || (c == '^'));
+}
+
+int
+ IsKeyWord(str) /* Returns 1 if str is a keyword to be in keyword font */
+char str[MAXLINELENGTH];
+{
+ return((!(strcmp(str, "case"))) || (!(strcmp(str, "class")))
+ || (!(strcmp(str, "data"))) || (!(strcmp(str, "default")))
+ || (!(strcmp(str, "deriving"))) || (!(strcmp(str, "else")))
+ || (!(strcmp(str, "hiding"))) || (!(strcmp(str, "if")))
+ || (!(strcmp(str, "import"))) || (!(strcmp(str, "in")))
+ || (!(strcmp(str, "infix"))) || (!(strcmp(str, "infixl")))
+ || (!(strcmp(str, "infixr"))) || (!(strcmp(str, "instance")))
+ || (!(strcmp(str, "interface"))) || (!(strcmp(str, "let")))
+ || (!(strcmp(str, "module"))) || (!(strcmp(str, "of")))
+ || (!(strcmp(str, "renaming"))) || (!(strcmp(str, "then")))
+ || (!(strcmp(str, "to"))) || (!(strcmp(str, "type")))
+ || (!(strcmp(str, "where"))));
+}
+
+int
+ KeyWord(c, store, position) /* Returns length of keyword if a keyword ends
+ at store.chars[position - 1] */
+char c;
+ElementType store;
+int position;
+{
+ int counter, start, end = position - 1, keywordlen = 0;
+ char str[MAXLINELENGTH];
+
+ if ((!isalpha(c)) && (c != '_') && (c != '\'') && (position)) {
+ for (counter = end; (counter >= 0) && ((isalpha(store.chars[counter]))
+ || (c == '_') || (c == '\''))
+ && (counter >= store.indentation); counter--) {
+ ; /* Just count letters */
+ }
+ start = ++counter;
+ for (counter = 0; counter + start <= end; counter++) {
+ str[counter] = store.chars[counter + start]; /* Copy letters into str */
+ }
+ str[counter] = '\0'; /* Add null character to end */
+ if (IsKeyWord(str)) /* Checks word in str is keyword */
+ keywordlen = strlen(str); /* and measures it */
+ }
+ return(keywordlen);
+}
+
+ElementType
+ CheckForKeyword(c, store, position) /* Returns store with any possible keyword
+ ending at store.chars[position - 1]
+ identified as such in store.typeface */
+char c;
+ElementType store;
+int position;
+{
+ if (KeyWord(c, store, position))
+ store = ChangeTypeface(store, KeyWord(c, store, position), position, KW);
+ return(store);
+}
+
+int
+ IsNumber(c, store, position, statesok) /* Returns 1 if c forms part of a number */
+char c;
+ElementType store;
+int position, statesok;
+{
+ int counter, foundident = 0, foundpunc = 0;
+
+ if (((isdigit(c)) || (c == 'e') || (c == 'E') || (c == '|') || (c == '.'))
+ && (statesok)) {
+ counter = position - 1;
+ while ((isdigit(store.chars[counter])) && (counter >= 0))
+ counter--;
+ if (((store.chars[counter] == '+') || (store.chars[counter] == '-'))
+ && ((store.chars[counter - 1] == 'e') || (store.chars[counter - 1] == 'E'))
+ && (counter > 2))
+ counter -= 2;
+ else if (((store.chars[counter] == 'e') || (store.chars[counter] == 'E'))
+ && (counter > 1))
+ counter--;
+ while ((isdigit(store.chars[counter])) && (counter >= 0))
+ counter--;
+ if ((store.chars[counter] == '.') && (counter > 1))
+ counter--;
+ while ((isdigit(store.chars[counter])) && (counter >= 0))
+ counter--;
+ if ((isalpha(store.chars[counter])) && (counter >= 0))
+ foundident = 1; /* ie not number */
+ else if ((IsHaskellPunc(store.chars[counter])) || (counter < 0))
+ foundpunc = 1; /* ie is number */
+ }
+ return(foundpunc);
+}
+ /* * * LINE SELECTION FUNCTIONS * * */
+ElementType
+ SelectSkipLine(s, store, linecounter) /* Returns store containing line for skipover */
+StackType s;
+ElementType store;
+int linecounter;
+{
+ ElementType temp;
+ int counter;
+
+ if (!(IsEmptyStack(s))) {
+ while (((Top(s)).length <= linecounter) || ((Top(s)).indentation >= linecounter)) {
+ temp = Top(s);
+ s = PopSym(s);
+ if (IsEmptyStack(s)) {
+ counter = temp.length;
+ while (counter < linecounter) {
+ temp.chars[counter] = ' ';
+ temp.typeface[counter++] = SP;
+ }
+ temp.chars[counter] = '\0'; /* Add null character to end */
+ s = Push(s, temp);
+ break;
+ }
+ }
+ store = Top(s);
+ }
+ else { /* Stack is empty */
+ counter = store.length;
+ while (counter < linecounter) {
+ store.chars[counter] = ' ';
+ store.typeface[counter++] = SP;
+ }
+ store.chars[counter] = '\0'; /* Add null character to end */
+ }
+ return(store);
+}
+ /* * * STORING FUNCTIONS * * */
+ElementType
+ CreateStore() /* Returns an empty store */
+{
+ ElementType store;
+
+ strcpy(store.chars, "");
+ store.length = 0;
+ store.indentation = 0;
+ store.col = 0;
+ return(store);
+}
+
+ElementType
+ StoreSpace(store, position) /* Stores a space in the store at current position */
+ElementType store;
+int position;
+{
+ store.chars[position] = ' ';
+ store.typeface[position] = SP;
+ return(store);
+}
+ /* * * WRITING FUNCTIONS * * */
+void
+ WriteStartFace(tf) /* Writes LaTeX typeface commands for start of section */
+enum face tf;
+{
+ if (tf == KW) /* Keywords */
+ printf("{\\keyword ");
+ else if ((tf == ID) || (tf == IS)) /* Identifiers */
+ printf("{\\iden ");
+ else if (tf == ST) /* Strings */
+ printf("{\\stri ");
+ else if (tf == CO) /* Comments */
+ printf("{\\com ");
+ else if (tf == NU) /* Numbers */
+ printf("{\\numb ");
+ else if ((tf == MA) || (tf == TI)) /* Various maths */
+ printf("$");
+}
+
+void
+ WriteFinishFace(tf) /* Writes LaTeX typeface commands for end of section */
+enum face tf;
+{
+ if ((tf == KW) || (tf == ID) || (tf == ST) || (tf == CO)
+ || (tf == NU)) /* Keywords, identifiers, strings, comments or numbers */
+ printf("\\/}");
+ else if ((tf == MA) || (tf == TI)) /* Various maths */
+ printf("$");
+ else if (tf == IS) /* Subscripts in identifiers */
+ printf("\\/}$");
+}
+
+int
+ WriteSpaces(store, counter, finish) /* Writes consecutive spaces,
+ returning new counter value */
+ElementType store;
+int counter, finish;
+{
+ int spaces = 0; /* The number of spaces found */
+
+ for (; (store.typeface[counter] == SP) && (counter < finish); counter++)
+ spaces++;
+ printf("\\xspa{%d}", spaces);
+ return(--counter);
+}
+
+int
+ WriteChar(store, counter, finish) /* Writes charater, returning new counter value */
+ElementType store;
+int counter, finish;
+{
+ if (store.typeface[counter] == SP) /* Space */
+ printf("\\xspa1"); /* Redundant */
+ else if (store.typeface[counter] == BE) /* Bar under equals sign */
+ printf("\\bareq");
+ else if (store.typeface[counter] == DP) { /* Double plus */
+ if ((counter < finish - 1) && (store.typeface[counter + 1] == DC)) {
+ printf("\\plusplus");
+ counter++;
+ }
+ }
+ else if (store.typeface[counter] == CP) { /* Colon plus */
+ if ((counter < finish - 1) && (store.typeface[counter + 1] == DC)) {
+ printf("{:}{+}");
+ counter++;
+ }
+ }
+ else if (store.typeface[counter] == LE) { /* Less than or equal to */
+ if ((counter < finish - 1) && (store.typeface[counter + 1] == DC)) {
+ printf("$\\leq$");
+ counter++;
+ }
+ }
+ else if (store.typeface[counter] == GE) { /* Greater than or equal to */
+ if ((counter < finish - 1) && (store.typeface[counter + 1] == DC)) {
+ printf("$\\geq$");
+ counter++;
+ }
+ }
+ else if (store.typeface[counter] == LA) { /* Leftarrow */
+ if ((counter < finish - 1) && (store.typeface[counter + 1] == DC)) {
+ printf("$\\leftarrow$");
+ counter++;
+ }
+ }
+ else if (store.typeface[counter] == RA) { /* Rightarrow */
+ if ((counter < finish - 1) && (store.typeface[counter + 1] == DC)) {
+ printf("$\\rightarrow$");
+ counter++;
+ }
+ }
+ else if (store.typeface[counter] == RR) { /* Double rightarrow */
+ if ((counter < finish - 1) && (store.typeface[counter + 1] == DC)) {
+ printf("$\\Rightarrow$");
+ counter++;
+ }
+ }
+ else if (store.typeface[counter] == RC) { /* Regional comment begin */
+ if ((counter < finish - 1) && (store.typeface[counter + 1] == DC)) {
+ printf("{\\com \\{-\\/}");
+ counter++;
+ }
+ else
+ printf("{\\com \\{\\/}");
+ }
+ else if (store.typeface[counter] == CR) { /* Regional comment end */
+ if ((counter < finish - 1) && (store.typeface[counter + 1] == DC)) {
+ printf("{\\com -\\}\\/}");
+ counter++;
+ }
+ else
+ printf("{\\com -\\/}");
+ }
+ else if ((store.typeface[counter] == LC) && (store.chars[counter] == '-'))
+ printf("{\\rm -}"); /* Comment - problem: "--" becomes "-" in LaTeX so fix done */
+ else if (store.chars[counter] == '\\')
+ printf("\\hbox{$\\setminus$}"); /* Backslash */
+ else if (store.chars[counter] == '*') {
+ if (store.typeface[counter] == TI)
+ printf("\\times "); /* Multiplication */
+ else
+ printf("*"); /* Other star symbols, eg Exponent */
+ }
+ else if ((store.chars[counter] == '_') && (store.typeface[counter] == SU)) {
+ if ((counter < finish - 1) && (store.typeface[counter + 1] == IS))
+ printf("$_"); /* Subscript character */
+ }
+ else if (store.chars[counter] == '^')
+ printf("\\char'136 "); /* Up-arrow */
+ else if (store.chars[counter] == '~')
+ printf("\\char'176 "); /* Tilda */
+ else if ((store.chars[counter] == ':') && (store.chars[counter - 1] == ':')
+ && (widecolons))
+ printf("\\,:"); /* Double colon */
+ else if (store.chars[counter] == '"') {
+ if ((counter) && ((store.chars[counter - 1] == '"')
+ || (store.chars[counter - 1] == '\'')))
+ printf("\\,"); /* If previous character was a quote, leave a little space */
+ if (store.typeface[counter] == DQ)
+ printf("{\\rm ``}"); /* Open doublequote */
+ else if (store.typeface[counter] == QD)
+ printf("{\\rm \"}"); /* Close doublequote */
+ else
+ printf("{\\rm \\char'175}"); /* Escape doublequote in string */
+ }
+ else if (store.chars[counter] == '\'') {
+ if ((counter) && ((store.chars[counter - 1] == '"')
+ || ((store.chars[counter - 1] == '\'')
+ && ((store.typeface[counter - 1] != MA)
+ || (store.typeface[counter] != MA)))))
+ printf("\\,"); /* If previous character was a quote, leave a little space
+ except when it's a double prime */
+ if (store.typeface[counter] == FQ)
+ printf("\\forquo "); /* Forward single quote */
+ else if (store.typeface[counter] == EQ)
+ printf("\\escquo "); /* Escape single quote */
+ else if (store.typeface[counter] == BF) {
+ if ((counter + 1 < store.length) && (store.typeface[counter + 1] == BF)
+ && (counter + 1 != store.indentation)) {
+ printf("{\\com \'\'\\/}"); /* Closing LaTeX style quote */
+ counter++;
+ }
+ else
+ printf("{\\com \'\\/}"); /* Single quote following backquote in comment */
+ }
+ else
+ printf("\'"); /* Prime */
+ }
+ else if (store.chars[counter] == '{')
+ printf("\\hbox{$\\cal \\char'146$}"); /* Open curly bracket */
+ else if (store.chars[counter] == '}')
+ printf("\\hbox{$\\cal \\char'147$}"); /* Close curly bracket */
+ else if ((counter) && (store.chars[counter - 1] == '[') && (store.chars[counter] == ']'))
+ printf("\\,]"); /* Leave small gap between adjacent square brackets */
+ else if ((store.chars[counter] == '$') || (store.chars[counter] == '%')
+ || (store.chars[counter] == '_') || (store.chars[counter] == '#')
+ || (store.chars[counter] == '&')) /* Various characters needing '\' for LaTeX */
+ printf("\\%c", store.chars[counter]);
+ else /* Other characters */
+ printf("%c", store.chars[counter]);
+ return(counter);
+}
+
+void
+ WriteSkipover(store) /* Writes the skipover portion of line in store */
+ElementType store;
+{
+ int counter = 0;
+
+ printf("\\skipover{"); /* Write opening LaTeX skipover command */
+ WriteStartFace(store.typeface[counter]); /* Write opening LaTeX typeface command */
+ if (store.typeface[counter] == SP)
+ counter = WriteSpaces(store, counter, store.indentation); /* Write spaces */
+ else
+ counter = WriteChar(store, counter, store.indentation); /* Write character */
+ for (counter++; counter < store.indentation; counter++){ /* until end of skipover */
+ if (store.typeface[counter - 1] != store.typeface[counter]) { /* If typeface change */
+ WriteFinishFace(store.typeface[counter - 1]); /* write closing typeface command */
+ WriteStartFace(store.typeface[counter]); /* write opening LaTeX typeface command */
+ }
+ if (store.typeface[counter] == SP)
+ counter = WriteSpaces(store, counter, store.indentation); /* Write spaces */
+ else
+ counter = WriteChar(store, counter, store.indentation); /* Write character */
+ }
+ if (store.typeface[counter - 1] == SU)
+ ; /* If indentation is under subscript don't open math section */
+ else
+ WriteFinishFace(store.typeface[counter - 1]); /* Write closing LaTeX typeface command */
+ printf("}"); /* Write closing LaTeX skipover command */
+}
+
+void
+ WriteWords(store) /* Writes rest of line, starting at indentation level */
+ElementType store;
+{
+ int counter = store.indentation;
+ int intabular = 0; /* Boolean: is in tabular section for internal alignment */
+
+ WriteStartFace(store.typeface[counter]); /* Write opening LaTeX typeface command */
+ if (store.typeface[counter] == SP)
+ counter = WriteSpaces(store, counter, store.length); /* Write spaces */
+ else
+ counter = WriteChar(store, counter, store.length); /* Write character */
+ for (counter++; counter < store.length; counter++){ /* until end of word */
+ if ((store.col) && (store.col == counter)) {
+ printf(" & ");
+ if (store.chars[counter - 1] == ':')
+ printf("$:");
+ intabular = 1;
+ }
+ if (store.typeface[counter - 1] != store.typeface[counter]) /* If typeface change */
+ WriteFinishFace(store.typeface[counter - 1]); /* Write closing typeface command */
+ if ((store.typeface[counter] == SP) && (intabular)) {
+ printf(" & ");
+ intabular = 0;
+ }
+ if ((store.typeface[counter - 1] != store.typeface[counter]) /* If typeface change */
+ && ((store.chars[counter] != ':') || (store.col != counter + 1)))
+ WriteStartFace(store.typeface[counter]); /* Write opening LaTeX typeface command */
+ if (store.typeface[counter] == SP)
+ counter = WriteSpaces(store, counter, store.length); /* Write spaces */
+ else if ((store.chars[counter] != ':') || (!store.col) || (store.col != counter + 1))
+ counter = WriteChar(store, counter, store.length); /* Write character */
+ }
+ WriteFinishFace(store.typeface[counter - 1]); /* Write closing LaTeX typeface command */
+}
+
+void
+ WriteLine(store, needed) /* Writes the line in store,
+ only writing LaTeX newline if needed */
+ElementType store;
+int needed;
+{
+ if (store.indentation)
+ WriteSkipover(store);
+ if (store.indentation < store.length)
+ WriteWords(store);
+ if (needed)
+ printf("\\\\"); /* LaTeX newline character */
+ printf("\n");
+}
+
+QueueType
+ WriteQueue(q) /* Writes lines, removing them from queue,
+ leaves last line in queue if not in tabular section */
+QueueType q;
+{
+ int intabular = 0;
+
+ if ((!(IsEmptyQueue(q))) && ((*(FrontOfQueue(q))).Element.col)) {
+ printf("\\begin{tabular}{@{}l@{\\xspa1}c@{}l}\n");
+ intabular = 1;
+ }
+ while (LengthOfQueue(q) > !intabular) {
+ WriteLine((*(FrontOfQueue(q))).Element, 1); /* LaTeX newline character is needed */
+ q = TakeFromQueue(q);
+ }
+ if (intabular)
+ printf("\\end{tabular}\\\\\n");
+ return(q);
+}
+
+QueueType
+ WriteRestOfQueue(q) /* Writes all lines, removing them from queue,
+ doesn't have LaTeX newline after last line */
+QueueType q;
+{
+ int intabular = 0;
+
+ if ((!(IsEmptyQueue(q))) && ((*(FrontOfQueue(q))).Element.col)) {
+ printf("\\begin{tabular}{@{}l@{\\xspa1}c@{}l}\n");
+ intabular = 1;
+ }
+ while (!(IsEmptyQueue(q))) {
+ WriteLine((*(FrontOfQueue(q))).Element, (LengthOfQueue(q) > 1)); /* Last line doesn't
+ need LaTeX newline character */
+ q = TakeFromQueue(q);
+ }
+ if (intabular) {
+ printf("\\end{tabular}");
+ if (!IsEmptyQueue(q)) /* Last line doesn't need LaTeX newline character */
+ printf("\\\\");
+ printf("\n");
+ }
+ return(q);
+}
+
+int
+main (argc, argv) /* * * MAIN PROGRAM * * */
+ int argc;
+ char *argv[];
+{
+ int tripped = 1, instring = 0, instringincomment = 0, inlinecomment = 0;
+ int incharquote = 0, incharquoteincomment = 0, inbackquoteincomment = 0;
+ int insub = 0;
+ /* Booleans - just taken new line, in string, in string inside comment, in line comment,
+ in character quote, in character quote inside comment, in backquote inside comment,
+ in subscript */
+ int linecounter = 0, indentcounter = 0, inregcomment = 0, pos;
+ /* Counters: current position on line, indentation of current line,
+ nesting level of regional comments, position marker */
+ char c; /* Character */
+ StackType s; /* Stack of previous longest lines */
+ QueueType q; /* Queue of lines waiting to be printed */
+ ElementType store; /* Store of letters, typefaces and non-empty length */
+
+ if ((argc == 3) && (argv[1][0] == '-')) { /* If options specified with call */
+ if (strstr(argv[1], "s")) /* if -s option, subscripts in identifiers wanted */
+ subscripts = 1;
+ if (strstr(argv[1], "t")) { /* if -tX option, tab characters are X spaces */
+ for (pos = 1; (argv[1][pos] != 't'); pos++) /* find 't' */
+ ;
+ for (pos++, tablength = 0; isdigit(argv[1][pos]); pos++) /* read number */
+ tablength = (tablength * 10) + (argv[1][pos] - '0');
+ }
+ if (strstr(argv[1], "w")) /* if -w option called, wide double colons wanted */
+ widecolons = 1;
+ }
+ else if (argc == 2) /* If no options */
+ ;
+ else { /* If not called with pphs and a filename */
+ fprintf(stderr, "pphs: Call with one file name\n");
+ exit(1);
+ }
+
+ if ((strcspn(argv[argc - 1], ".") == strlen(argv[argc - 1])) /* If filename has no extention */
+ && ((ifptr = fopen(argv[argc - 1], "r")) == NULL)) /* and no plain file of that name */
+ strcat(argv[argc - 1], ".hs"); /* add a ".hs" extention */
+ if ((ifptr = fopen(argv[argc - 1], "r")) == NULL) { /* Open input file */
+ fprintf(stderr, "pphs: File could not be opened\n"); /* eg isn't there */
+ exit(2);
+ }
+ else {
+
+ printf("\\begin{tabbing}\n"); /* Start of Haskell program */
+
+ store = CreateStore(); /* an empty one */
+ s = CreateStack(); /* an empty one */
+ q = CreateQueue(); /* an empty one */
+
+ fscanf(ifptr, "%c", &c); /* Read character */
+ while (!feof(ifptr)) { /* While not at end of input file */
+ while ((isspace(c)) && (!(feof(ifptr)))) { /* Read blank characters */
+ if (c == ' ') {
+ if (tripped)
+ linecounter++; /* Count leading spaces */
+ else { /* or */
+ store = StoreSpace(store, linecounter++); /* Store intermediate
+ or trailing space */
+ if (store.length < linecounter)
+ store.chars[linecounter] = '\0'; /* Add null character to end */
+ }
+ fscanf(ifptr, "%c", &c); /* Read next character */
+ }
+ else if (c == '\t') {
+ if (tripped)
+ linecounter += (tablength - (linecounter % tablength));
+ else {
+ store = StoreSpace(store, linecounter++);
+ for (; linecounter % tablength; linecounter++)
+ store = StoreSpace(store, linecounter);
+ if (store.length < linecounter)
+ store.chars[linecounter] = '\0'; /* Add null character to end */
+ }
+ fscanf(ifptr, "%c", &c); /* Read next character */
+ }
+ else if (c == '\n') {
+ tripped = 1; /* Just taken a new line */
+ inlinecomment = 0;
+ if (!(IsEmptyStack(s)))
+ while (((Top(s)).length <= store.length)
+ && ((Top(s)).indentation >= store.length)) {
+ s = Pop(s);
+ if (IsEmptyStack(s))
+ break;
+ }
+ if (store.length > 0) { /* Push non-empty line onto indentation stack */
+ store.indentation = indentcounter;
+ s = Push(s, store);
+ }
+ if (!(IsEmptyQueue(q))) {
+ if ((store.col != (*(FrontOfQueue(q))).Element.col)
+ || (!(*(FrontOfQueue(q))).Element.col))
+ q = WriteQueue(q); /* If internal alignment changes or there is none
+ write out lines */
+ }
+ q = AddToQueue(q, store); /* Add to writing queue */
+ linecounter = 0; /* Get ready to count leading spaces */
+ store.length = linecounter;
+ fscanf(ifptr, "%c", &c); /* Read next character */
+ }
+ else break;
+ }
+ if (tripped) {
+ indentcounter = linecounter;
+ store.indentation = linecounter;
+ store.col = 0;
+ }
+ if ((tripped) && (linecounter)) { /* Skipover necessary for indentation */
+ store = SelectSkipLine(s, store, linecounter);
+ store.indentation = linecounter;
+ store.col = 0;
+ }
+ if (!feof(ifptr))
+ tripped = 0; /* No longer just taken new line */
+ while ((!(isspace(c))) && (!(feof(ifptr)))) { /* Read word */
+ if ((linecounter > 1) && (!IsEmptyQueue(q))
+ && ((*(RearOfQueue(q))).Element.length >= linecounter)
+ && (linecounter > store.indentation)
+ && (linecounter > (*(RearOfQueue(q))).Element.indentation)
+ && (store.chars[linecounter - 1] == ' ')
+ && ((((*(RearOfQueue(q))).Element.chars[linecounter - 1] == ' ')
+ && ((c == (*(RearOfQueue(q))).Element.chars[linecounter])
+ || ((c == '=')
+ && ((*(RearOfQueue(q))).Element.chars[linecounter] == ':')
+ && ((*(RearOfQueue(q))).Element.chars[linecounter + 1] == ':'))))
+ || (((*(RearOfQueue(q))).Element.chars[linecounter - 1] == ':')
+ && ((*(RearOfQueue(q))).Element.chars[linecounter] == ':')
+ && (c == '=')))
+ && ((store.chars[linecounter - 2] == ' ')
+ || ((*(RearOfQueue(q))).Element.chars[linecounter - 2] == ' '))
+ && (((*(RearOfQueue(q))).Element.col == 0)
+ || ((*(RearOfQueue(q))).Element.col == linecounter))) {
+ store.col = linecounter; /* Identify any internal alignment */
+ (*(RearOfQueue(q))).Element.col = linecounter;
+ }
+ if ((c == '"') && (!incharquote) /* String outside comments */
+ && (!inregcomment) && (!inlinecomment)) {
+ if (((linecounter) && (store.chars[linecounter - 1] != '\\'))
+ || (!linecounter))
+ instring = !instring;
+ }
+ else if ((c == '"') && (!incharquoteincomment) /* String inside comment */
+ && (!inbackquoteincomment)
+ && ((inregcomment) || (inlinecomment))) {
+ if (((linecounter) && (store.chars[linecounter - 1] != '\\'))
+ || (!linecounter))
+ instringincomment = !instringincomment;
+ }
+ else if ((c == '`') && ((inlinecomment) || (inregcomment))) {
+ if ((linecounter) && (store.chars[linecounter - 1] == '`'))
+ inbackquoteincomment = 2; /* Opening LaTeX style quote in comment */
+ else
+ inbackquoteincomment = !inbackquoteincomment; /* Backquote in comment */
+ }
+ else if ((linecounter) && (!inlinecomment) && (!instring)) {
+ if ((store.chars[linecounter - 1] == '{') && (c == '-'))
+ inregcomment++; /* Haskell "{-" regional comment begin */
+ else if ((store.chars[linecounter - 1] == '-') && (c == '}')) {
+ inregcomment--; /* Haskell "-}" regional comment end */
+ instringincomment = 0;
+ incharquoteincomment = 0;
+ inbackquoteincomment = 0;
+ }
+ }
+ if (c == '|') {
+ if ((!IsEmptyQueue(q))
+ && ((((*(RearOfQueue(q))).Element.chars[linecounter] == '=')
+ && (linecounter == store.indentation))
+ || ((*(RearOfQueue(q))).Element.typeface[linecounter] == BE)))
+ store.typeface[linecounter] = BE;
+ else
+ store.typeface[linecounter] = MA;
+ }
+ else if ((c == '\'') && (linecounter) && (store.chars[linecounter - 1] == '\\'))
+ store.typeface[linecounter] = EQ; /* Escape character quote */
+ else if ((c == '\'') && (!instring) && (!inregcomment) && (!inlinecomment)) {
+ if (((linecounter) && (store.chars[linecounter - 1] != '\\')
+ && ((IsHaskellPunc(store.chars[linecounter - 1])) || (incharquote)))
+ || (!linecounter)) {
+ incharquote = !incharquote;
+ store.typeface[linecounter] = FQ; /* Character quote */
+ }
+ else
+ store.typeface[linecounter] = MA; /* Prime */
+ }
+ else if ((c == '\'') && (!instringincomment)
+ && ((inregcomment) || (inlinecomment))) {
+ if (((linecounter) && (store.chars[linecounter - 1] != '\\')
+ && ((IsHaskellPunc(store.chars[linecounter - 1]))
+ || (incharquoteincomment)))
+ || (!linecounter)) {
+ incharquoteincomment = !incharquoteincomment;
+ store.typeface[linecounter] = FQ; /* Character quote in comment */
+ }
+ else if (inbackquoteincomment) {
+ inbackquoteincomment--;
+ store.typeface[linecounter] = BF; /* `x' character quote in comment */
+ }
+ else
+ store.typeface[linecounter] = MA; /* Prime */
+ }
+ else if (c == '"') {
+ if ((!incharquote) && (!incharquoteincomment) && (!inbackquoteincomment)
+ && ((instring) || (instringincomment))) {
+ if (((linecounter) && (store.chars[linecounter - 1] != '\\'))
+ || (!linecounter))
+ store.typeface[linecounter] = DQ; /* Open doublequote */
+ else if (store.chars[linecounter - 1] == '\\')
+ store.typeface[linecounter] = EE; /* Escape doublequote */
+ }
+ else if ((!incharquote) && (!incharquoteincomment) && (!inbackquoteincomment)) {
+ if (((linecounter) && (store.chars[linecounter - 1] != '\\'))
+ || (!linecounter))
+ store.typeface[linecounter] = QD; /* Close doublequote */
+ else if (store.chars[linecounter - 1] == '\\')
+ store.typeface[linecounter] = EE; /* Escape doublequote */
+ }
+ else
+ store.typeface[linecounter] = EE; /* Character quote of doublequote */
+ }
+ else if (c == '`') {
+ if ((inlinecomment) || (inregcomment))
+ store.typeface[linecounter] = CO;
+ else
+ store.typeface[linecounter] = MA;
+ }
+ else if ((linecounter) && (subscripts) && (c == '_')
+ && (store.typeface[linecounter - 1] == ID))
+ store.typeface[linecounter] = SU; /* Subscript in identifier */
+ else if (c == '*')
+ store.typeface[linecounter] = TI; /* Times - may be changed by double char */
+ else if (IsMathsChar(c))
+ store.typeface[linecounter] = MA; /* Maths characters */
+ else if (IsNumber(c, store, linecounter,
+ ((!inregcomment) && (!instring) && (!inlinecomment))))
+ store.typeface[linecounter] = NU; /* Numbers */
+ else if ((instring) || (incharquote))
+ store.typeface[linecounter] = ST; /* Characters in strings */
+ else if ((inlinecomment) || (inregcomment))
+ store.typeface[linecounter] = CO; /* Characters in comments */
+ else {
+ if (insub)
+ store.typeface[linecounter] = IS; /* Subscript identifiers */
+ else
+ store.typeface[linecounter] = ID; /* Others */
+ }
+ if (linecounter)
+ if ((store.typeface[linecounter - 1] == IS)
+ && (store.typeface[linecounter] != IS))
+ insub = 0; /* End of subscript identifier */
+ store.chars[linecounter++] = c; /* Place character in store */
+ if (linecounter > store.indentation + 1)
+ store = CheckForDoubleChar(store, linecounter);
+ if ((store.typeface[linecounter - 1] == LC) && (!inregcomment)
+ && (!instring) && (!incharquote)) {
+ instringincomment = 0;
+ incharquoteincomment = 0;
+ inbackquoteincomment = 0;
+ inlinecomment = 1;
+ }
+ else if ((store.typeface[linecounter - 1] == SU)
+ && (linecounter != store.indentation))
+ insub = 1;
+ fscanf(ifptr, "%c", &c); /* Read next character */
+ if (feof(ifptr))
+ c = ' ';
+ if ((!inregcomment) && (!inlinecomment) && (!instring))
+ store = CheckForKeyword(c, store, linecounter); /* Keywords not in comments or
+ strings to be in keyword typeface */
+ }
+ insub = 0;
+ store.chars[linecounter] = '\0'; /* String terminating null character */
+ store.length = linecounter;
+ }
+ if ((!tripped) && (!store.col)) /* If last line not in internal alignment */
+ q = WriteQueue(q); /* write previous lines which might */
+ if (!tripped) /* Put final line in queue if non-empty */
+ q = AddToQueue(q, store);
+ if (feof(ifptr)) /* Write remaining lines */
+ q = WriteRestOfQueue(q);
+
+ printf("\\end{tabbing}\n"); /* End of Haskell program */
+
+ exit(0);
+ }
+}