/* c code generated by "tr/translate.c.pss" */ /* note: this c engine cannot handle unicode! */ #include #include #include #include #include "colours.h" #include "tapecell.h" #include "tape.h" #include "buffer.h" #include "charclass.h" #include "command.h" #include "parameter.h" #include "instruction.h" #include "labeltable.h" #include "program.h" #include "machine.h" #include "exitcode.h" #include "machine.methods.h" int main() { struct Machine machine; struct Machine * mm = &machine; newMachine(mm, stdin, 100, 10); script: while (!mm->peep != EOF) { if (mm->peep == EOF) { break; } else { readChar(mm); } /* read */ // make char number relative to line, for error messages if (workspaceInClassType(mm, "[\n]")) { mm->charsRead = 0; /* nochars */ } // newlines can separate commands in (gnu) sed so we will // just add a dummy ';' here. Also, no trailing ; is required if (workspaceInClassType(mm, "[\n]")) { put(mm); mm->buffer.workspace[0] = '\0'; /* clear */ add(mm, ";*"); push(mm); goto parse; } // ignore extraneous white-space? if (workspaceInClassType(mm, "[:space:]")) { mm->buffer.workspace[0] = '\0'; /* clear */ if (mm->peep == EOF) { goto parse; } continue; } // comments, if (0 == strcmp(mm->buffer.workspace, "#")) { until(mm, "\n"); if (!endsWith(mm->buffer.workspace, "\n")) { add(mm, "\n"); } put(mm); mm->buffer.workspace[0] = '\0'; /* clear */ // uncomment line below to include comments in output // and make new reductions // add "comment*"; push; .reparse } // literal tokens '{' and '}' are used to group commands in // sed, ';' is used to separate commands and ',' to separate line // ranges. ! is the postfix negation operator for ranges if (0 == strcmp(mm->buffer.workspace, ",") || 0 == strcmp(mm->buffer.workspace, "{") || 0 == strcmp(mm->buffer.workspace, "}") || 0 == strcmp(mm->buffer.workspace, ";") || 0 == strcmp(mm->buffer.workspace, "!")) { put(mm); add(mm, "*"); push(mm); goto parse; } // various actions: print, delete, swap if (0 == strcmp(mm->buffer.workspace, "=") || 0 == strcmp(mm->buffer.workspace, "p") || 0 == strcmp(mm->buffer.workspace, "P") || 0 == strcmp(mm->buffer.workspace, "l") || 0 == strcmp(mm->buffer.workspace, "d") || 0 == strcmp(mm->buffer.workspace, "D") || 0 == strcmp(mm->buffer.workspace, "F") || 0 == strcmp(mm->buffer.workspace, "g") || 0 == strcmp(mm->buffer.workspace, "G") || 0 == strcmp(mm->buffer.workspace, "h") || 0 == strcmp(mm->buffer.workspace, "H") || 0 == strcmp(mm->buffer.workspace, "n") || 0 == strcmp(mm->buffer.workspace, "N") || 0 == strcmp(mm->buffer.workspace, "x") || 0 == strcmp(mm->buffer.workspace, "z")) { if (0 == strcmp(mm->buffer.workspace, "=")) { replace(mm, "=", "=; # print line-number + \\n"); /* replace */ } if (0 == strcmp(mm->buffer.workspace, "d")) { replace(mm, "d", "d; # delete pattern-space, restart"); /* replace */ } if (0 == strcmp(mm->buffer.workspace, "D")) { replace(mm, "D", "D; # delete pattern-space to 1st \\n, restart"); /* replace */ } if (0 == strcmp(mm->buffer.workspace, "e")) { replace(mm, "e", "e; # exec patt-space command and replace"); /* replace */ } if (0 == strcmp(mm->buffer.workspace, "F")) { replace(mm, "F", "F; # print input filename + \\n"); /* replace */ } if (0 == strcmp(mm->buffer.workspace, "g")) { replace(mm, "g", "g; # replace patt-space with hold-space"); /* replace */ } if (0 == strcmp(mm->buffer.workspace, "G")) { replace(mm, "G", "G; # append hold-space to patt-space + \\n"); /* replace */ } if (0 == strcmp(mm->buffer.workspace, "h")) { replace(mm, "h", "h; # replace hold-space with patt-space"); /* replace */ } if (0 == strcmp(mm->buffer.workspace, "H")) { replace(mm, "H", "H; # append patt-space to hold-space + \\n"); /* replace */ } if (0 == strcmp(mm->buffer.workspace, "l")) { replace(mm, "l", "l; # print pattern-space unambiguously"); /* replace */ } if (0 == strcmp(mm->buffer.workspace, "n")) { replace(mm, "n", "n; # print patt-space, get next line into patt-space "); /* replace */ } if (0 == strcmp(mm->buffer.workspace, "N")) { replace(mm, "N", "N; # append next line to patt-space + \\n "); /* replace */ } if (0 == strcmp(mm->buffer.workspace, "p")) { replace(mm, "p", "p; # print pattern-space"); /* replace */ } if (0 == strcmp(mm->buffer.workspace, "P")) { replace(mm, "P", "P; # print pattern-space up to 1st newline"); /* replace */ } if (0 == strcmp(mm->buffer.workspace, "x")) { replace(mm, "x", "x; # swap pattern-space with hold-space"); /* replace */ } if (0 == strcmp(mm->buffer.workspace, "z")) { replace(mm, "z", "z; # delete pattern-space, NO restart"); /* replace */ } put(mm); mm->buffer.workspace[0] = '\0'; /* clear */ add(mm, "action*"); push(mm); goto parse; } // line numbers are also selectors if (workspaceInClassType(mm, "[0-9]")) { while (((mm->peep >= '0') && ('9' >= mm->peep)) && readc(mm)) {} /* while */ put(mm); mm->buffer.workspace[0] = '\0'; /* clear */ add(mm, "number*"); push(mm); goto parse; } // $ is the last line of the file if (0 == strcmp(mm->buffer.workspace, "$")) { put(mm); mm->buffer.workspace[0] = '\0'; /* clear */ add(mm, "number*"); push(mm); goto parse; } // patterns - only execute commands if lines match if (0 == strcmp(mm->buffer.workspace, "/")) { // save line/char number for error message mm->buffer.workspace[0] = '\0'; /* clear */ add(mm, "near line "); lines(mm); add(mm, ", char "); chars(mm); put(mm); mm->buffer.workspace[0] = '\0'; /* clear */ until(mm, "/"); if (!endsWith(mm->buffer.workspace, "/")) { mm->buffer.workspace[0] = '\0'; /* clear */ add(mm, "Missing '/' to terminate "); get(mm); add(mm, "?\n"); printf("%s", mm->buffer.workspace); /* print */ exit(0); } /* clip */ if (*mm->buffer.workspace != 0) { mm->buffer.workspace[strlen(mm->buffer.workspace)-1] = '\0'; } put(mm); mm->buffer.workspace[0] = '\0'; /* clear */ // add any delimiter for pattern here, or none add(mm, "/"); get(mm); add(mm, "/"); put(mm); mm->buffer.workspace[0] = '\0'; /* clear */ add(mm, "pattern*"); push(mm); goto parse; } // read transliteration commands if (0 == strcmp(mm->buffer.workspace, "y")) { // save line/char number for error message mm->buffer.workspace[0] = '\0'; /* clear */ add(mm, "near line "); lines(mm); add(mm, ", char "); chars(mm); put(mm); mm->buffer.workspace[0] = '\0'; /* clear */ // allow spaces between 'y' and '/' although gnu set doesn't until(mm, "/"); if (!endsWith(mm->buffer.workspace, "/") || !workspaceInClassType(mm, "[ /]")) { mm->buffer.workspace[0] = '\0'; /* clear */ add(mm, "Missing '/' after 'y' transliterate command\n"); add(mm, "Or trailing characters "); get(mm); add(mm, "\n"); printf("%s", mm->buffer.workspace); /* print */ exit(0); } // save line/char number for error message mm->buffer.workspace[0] = '\0'; /* clear */ add(mm, "near line "); lines(mm); add(mm, ", char "); chars(mm); put(mm); mm->buffer.workspace[0] = '\0'; /* clear */ until(mm, "/"); if (!endsWith(mm->buffer.workspace, "/")) { mm->buffer.workspace[0] = '\0'; /* clear */ add(mm, "Missing 2nd '/' after 'y' transliterate command "); get(mm); add(mm, "\n"); printf("%s", mm->buffer.workspace); /* print */ exit(0); } if (0 == strcmp(mm->buffer.workspace, "/")) { mm->buffer.workspace[0] = '\0'; /* clear */ add(mm, "Sed syntax error? \n"); add(mm, " Empty regex after 'y' transliterate command "); get(mm); add(mm, "\n"); printf("%s", mm->buffer.workspace); /* print */ exit(0); } // replace pattern found /* clip */ if (*mm->buffer.workspace != 0) { mm->buffer.workspace[strlen(mm->buffer.workspace)-1] = '\0'; } put(mm); mm->buffer.workspace[0] = '\0'; /* clear */ add(mm, "y/"); get(mm); put(mm); mm->buffer.workspace[0] = '\0'; /* clear */ // save line/char number for error message add(mm, "near line "); lines(mm); add(mm, ", char "); chars(mm); increment(mm); /* ++ */ put(mm); if (mm->tape.currentCell > 0) mm->tape.currentCell--; /* -- */ mm->buffer.workspace[0] = '\0'; /* clear */ until(mm, "/"); if (!endsWith(mm->buffer.workspace, "/")) { mm->buffer.workspace[0] = '\0'; /* clear */ add(mm, "Missing 3rd '/' after 'y' transliterate command "); get(mm); add(mm, "\n"); printf("%s", mm->buffer.workspace); /* print */ exit(0); } /* clip */ if (*mm->buffer.workspace != 0) { mm->buffer.workspace[strlen(mm->buffer.workspace)-1] = '\0'; } swap(mm); add(mm, "/"); get(mm); add(mm, "/"); // y/// does not have modifiers (unlike s///) put(mm); mm->buffer.workspace[0] = '\0'; /* clear */ add(mm, "action*"); push(mm); goto parse; } // various commands that have an option word parameter if (0 == strcmp(mm->buffer.workspace, "b") || 0 == strcmp(mm->buffer.workspace, "e") || 0 == strcmp(mm->buffer.workspace, "q") || 0 == strcmp(mm->buffer.workspace, "Q") || 0 == strcmp(mm->buffer.workspace, "t") || 0 == strcmp(mm->buffer.workspace, "T")) { // ignore intervening space if any put(mm); mm->buffer.workspace[0] = '\0'; /* clear */ while ((strchr(" ", mm->peep) != NULL) && readc(mm)) {} /* while */ mm->buffer.workspace[0] = '\0'; /* clear */ // A bit more permissive that gnu-sed which doesn't allow // read to end in ';'. while (!(strchr(" ;}", mm->peep) != NULL) && readc(mm)) {} /* while */ // word parameters are optional to these commands // just add a space to separate command from parameter if (0 != strcmp(mm->buffer.workspace, "")) { swap(mm); add(mm, " "); swap(mm); } swap(mm); get(mm); if (strncmp(mm->buffer.workspace, "b", strlen("b")) == 0) { add(mm, "; # branch to