/* 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, convert to java comments if (0 == strcmp(mm->buffer.workspace, "#")) { mm->buffer.workspace[0] = '\0'; /* clear */ add(mm, "/* "); until(mm, "\n"); if (endsWith(mm->buffer.workspace, "\n")) { /* clip */ if (*mm->buffer.workspace != 0) { mm->buffer.workspace[strlen(mm->buffer.workspace)-1] = '\0'; } } add(mm, " */\n"); put(mm); mm->buffer.workspace[0] = '\0'; /* clear */ // uncomment line below to include comments in output // 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, "=")) { mm->buffer.workspace[0] = '\0'; /* clear */ // print line-number + newline add(mm, "System.out.println(mm.linesRead); /* '=' */"); } if (0 == strcmp(mm->buffer.workspace, "d")) { mm->buffer.workspace[0] = '\0'; /* clear */ // 'd' delete pattern-space, restart // the if true trick is necessary to avoid 'unreachable statement' // java compile errors (when multiple 'd' commands are given) add(mm, "if (true) { mm.patternSpace.setLength(0); continue; } /* 'd' */"); } if (0 == strcmp(mm->buffer.workspace, "D")) { mm->buffer.workspace[0] = '\0'; /* clear */ // add "/* 'D' delete pattern-space to 1st \\n, restart */"; add(mm, "if (mm.patternSpace.indexOf(\"\\n\") > -1) {\n"); add(mm, " mm.patternSpace.delete(0, mm.patternSpace.indexOf(\"\\n\"));\n"); add(mm, " mm.readNext = false; if (true) continue; \n"); add(mm, "} else { mm.patternSpace.setLength(0); continue; } /* 'd' */"); } if (0 == strcmp(mm->buffer.workspace, "F")) { // F: print input filename + newline // maybe unsupported in java mm->buffer.workspace[0] = '\0'; /* clear */ add(mm, "System.out.println(\"\"); /* F */"); } if (0 == strcmp(mm->buffer.workspace, "g")) { // g: replace patt-space with hold-space mm->buffer.workspace[0] = '\0'; /* clear */ add(mm, "mm.patternSpace.setLength(0); \n"); add(mm, "mm.patternSpace.append(mm.holdSpace); /* 'g' */"); } if (0 == strcmp(mm->buffer.workspace, "G")) { // G; append hold-space to patt-space + \\n" mm->buffer.workspace[0] = '\0'; /* clear */ add(mm, "mm.patternSpace.append(\"\\n\" + mm.holdSpace); /* 'G' */"); } if (0 == strcmp(mm->buffer.workspace, "h")) { // h: replace hold-space with patt-space mm->buffer.workspace[0] = '\0'; /* clear */ add(mm, "mm.holdSpace.setLength(0); \n"); add(mm, "mm.holdSpace.append(mm.patternSpace); /* 'h' */"); } if (0 == strcmp(mm->buffer.workspace, "H")) { // H: append patt-space to hold-space + newline mm->buffer.workspace[0] = '\0'; /* clear */ add(mm, "mm.holdSpace.append(\"\\n\" + mm.patternSpace); /* 'H' */"); } if (0 == strcmp(mm->buffer.workspace, "l")) { // print pattern-space unambiguously, synonym for p ? mm->buffer.workspace[0] = '\0'; /* clear */ add(mm, "System.out.println(mm.patternSpace); /* 'l' */"); } if (0 == strcmp(mm->buffer.workspace, "n")) { // n: print patt-space, get next line into patt-space mm->buffer.workspace[0] = '\0'; /* clear */ add(mm, "if (mm.autoPrint) { System.out.println(mm.patternSpace); }\n"); add(mm, "mm.patternSpace.setLength(0);\n"); add(mm, "mm.readLine(); /* 'n' */"); } if (0 == strcmp(mm->buffer.workspace, "N")) { // N: append next line to patt-space + newline mm->buffer.workspace[0] = '\0'; /* clear */ add(mm, "mm.patternSpace.append('\\n'); "); add(mm, "mm.readLine(); /* 'N' */"); } if (0 == strcmp(mm->buffer.workspace, "p")) { mm->buffer.workspace[0] = '\0'; /* clear */ add(mm, "System.out.println(mm.patternSpace); /* 'p' */"); } if (0 == strcmp(mm->buffer.workspace, "P")) { // P: print pattern-space up to 1st newline" mm->buffer.workspace[0] = '\0'; /* clear */ add(mm, "if (mm.patternSpace.indexOf(\"\\n\") > -1) {\n"); add(mm, " System.out.println(\n"); add(mm, " mm.patternSpace.substring(0, mm.patternSpace.indexOf(\"\\n\")));\n"); add(mm, "} else { System.out.println(mm.patternSpace); }"); } if (0 == strcmp(mm->buffer.workspace, "x")) { // x: # swap pattern-space with hold-space mm->buffer.workspace[0] = '\0'; /* clear */ add(mm, "mm.swap(); /* x */"); } if (0 == strcmp(mm->buffer.workspace, "z")) { // z: delete pattern-space, NO restart mm->buffer.workspace[0] = '\0'; /* clear */ add(mm, "mm.patternSpace.setLenth(0); /* z */"); } 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/char "); lines(mm); add(mm, ":"); 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'; } // java .matches method matches whole string not substring // so we need to add .* at beginning and end, but not if regex // begins with ^ or ends with $. complicated hey if (!endsWith(mm->buffer.workspace, "$")) { add(mm, ".*$"); } if (strncmp(mm->buffer.workspace, "^", strlen("^")) != 0) { put(mm); mm->buffer.workspace[0] = '\0'; /* clear */ add(mm, "^.*"); get(mm); } 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 // e has two variants // "e" { replace "e" "e; # exec patt-space command and replace"; } 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); // hard to implement because java has no goto ? if (strncmp(mm->buffer.workspace, "b", strlen("b")) == 0) { add(mm, "; # branch to