#include /** * Program to read jimitext (a very much simplified form of wikitext) * and output the links. Links are in *single* brackets; templates are * in *single* braces. There is no nesting, except for links inside * templates. We want links inside templates to be output with * "Template: " in front of them. So if the input is * * This is a [link] and I can put {[links] [inside] templates}. * * then the output should be * * link * Template: links * Template: inside * * Compile and link with * * gcc -Wall -std=c99 -pedantic -c jimilinks.c * gcc -o Jimilinks jimilinks.o */ // In addition to the compiler and linker, there is a third program involved // in compiling C files: the preprocessor, which you normally won't // run directly. Everything that starts with a # like like #include or // or #define or #ifndef...#endif is a preprocessor instruction. Here we // define four preprocessor variables (macros); when these are used later // in the program, their values are used in place of their names. So, given // these definitions, when we write "int state = TEXT;" in our program, // the compiler actually sees "int state = 0;". We could use constants // as an alternative; preprocessor macros have additional capabilities that // we aren't using here. Run "cpp jimilinks.c" if you want to see the output // of the preprocessor, which will include the files that were #include-d // and the replacement of the symbols defined below. #define TEXT 0 #define TEMPLATE 1 #define TEMPLATE_LINK 2 #define LINK 3 int main() { // set the initial state int state = TEXT; // loop until end of input (start a new line with Control-D to signal // end of input in Unix) int ch = getchar(); while (ch != EOF) { // now a big conditional to handle each state in our state machine switch (state) { case TEXT: // the case for each state then has another conditional with // cases for all the relevant characters; each one of these // cases will correspond to one of the transitions in our diagram if (ch == '{') { // saw an opening brace -- switch to "reading a template" state state = TEMPLATE; } else if (ch == '[') { // saw an opening bracket -- switch to "reading a link" state state = LINK; } break; case TEMPLATE: if (ch == '}') { // closing brace in a template -- back to our initial state state = TEXT; } else if (ch == '[') { // starting a link inside a template -- start the output and // change state state = TEMPLATE_LINK; printf("Template: "); } break; case TEMPLATE_LINK: if (ch == ']') { // closing bracket inside a template -- newline and still in // template printf("\n"); state = TEMPLATE; } else { // all other characters get output putc(ch, stdout); } break; case LINK: if (ch == ']') { // in a link (but not also a template) and link is closing -- // start new line and go back to initial state printf("\n"); state = TEXT; } else { // all other characters get output putc(ch, stdout); } break; } // read character for next time through loop ch = getchar(); } }