COSC345 Little Language Example

QA.dat

R Script : QA.dat
R Author : Richard A. O'Keefe
R Edited : 2013.02.22
R Purpose: Demonstrate QA little language.

R This is the PILOT example of COSC345 Lecture 2 converted to QA.
R Remarks begin with R.  Questions begin with Q and end with E.
R A begins a right answer, D a distractor, where exactly one answer is right.
R T begins a true answer, F a false one, where many answers may be picked.
R When several answers can be picked, they must be entered in alphabetic order.

Q In the context of COMP160,
Q which of the following is an example of a run time error?
D a false start at a track and field event
D an overflowing bathtub
D leaving the cricket crease early
A an error in coding which compiles correctly but does not run
E

Q Which of the following statements about local variables are true?
F Local variables may have a specified visibility.
F Local variables can be declared as static.
T Local variables are defined within methods.
T Local variables are automatically initialised.
F None of them.
E

QAI.awk

#!/bin/awk
#   Script : QAI.awk
#   Author : Richard A. O'Keefe
#   Updated: 2013.02.22
#   Purpose: Question-Answer Interpreter

BEGIN {
    right = 0
    wrong = 0
}

/^Q / {
    print substr($0, 3)
    position = 0
    expect = ""
    next
}

/^[DAFT] / {
    position++
    label = substr("ABCDEFGHIJKLMNOPQRSTUVWXYZ", position, 1)
    print "(" label ") " substr($0, 3)
    if ($0 ~ /^[AT]/) expect = expect label
    next
}

/^E/ {
    getline answer <"/dev/tty"
    gsub(/[^A-Za-z]+/, "", answer)
    if (toupper(answer) == expect) {
        print "Correct."
        right++
    } else {
        print "Sorry, the right answer is " expect "."
        wrong++
    }
    print ""
    next
}

/^[^QDAFTER]/ {
    printf "Oh dear, there is an error at line %d of the script %s.\n" \
           "This is our fault, not yours.\n<%s>\n", FNR, FILENAME, $0  \
           >"/dev/stderr"
    exit 1
}

END {
    print "You got", right, "questions right out of", right+wrong
    if (wrong == 0) print "Congratulations!"
}

QAC.awk

#!/bin/awk
#   Script : QAC.awk
#   Author : Richard A. O'Keefe
#   Updated: 2013.02.22
#   Purpose: Question-Answer Compiler : QA -> C89.

BEGIN {
    print "#include <ctype.h>"       # toupper()
    print "#include <stdio.h>"       # gets(), puts(), printf()
    print "#include <stdlib.h>"      # EXIT_SUCCESS, EXIT_FAILURE
    print "#include <string.h>"      # strchr()
    print ""
    print "static int right = 0;"
    print "static int wrong = 0;"
    print ""
    print "static void check(char const *expected) {"
    print "    char buffer[128];"
    print "    int i;"
    print "    int flag = 1;"
    print ""
 ## This used to generate a call to gets(), which is a security hole,
 ## but for this application, who cared?  MacOS X now whinges about
 ## it every time you run a program that uses gets(), whether it ever
 ## calls it or not, so now we generate a call to fgets(), which is a
 ## much nastier function to use.  In this program we get lucky.
    print "    if (fgets(buffer, sizeof buffer, stdin) == 0) abort();"
    print "    for (i = 0; buffer[i] != '\\0'; i++) {"
    print "        buffer[i] = toupper(buffer[i]);"
    print "    }"
    print "    for (i = 0; expected[i] != 0; i++) {"
    print "        if (strchr(buffer, expected[i]) == 0) flag = 0;"
    print "    }"
    print "    if (flag) {"
    print "        puts(" to_C_string("Correct.") ");"
    print "        right++;"
    print "    } else {"
    print "        printf(\"Sorry, the right answer is %s.\\n\", expected);"
    print "        wrong++;"
    print "    }"
    print "}"
    print ""
    print "int main(void) {"
}

function to_C_string(s) {
    gsub(/\\/, "\\\\", s)
    gsub(/"/,  "\\\"", s)
    gsub(/\t/, "\\t",  s)
    return "\"" s "\""
}

/^Q / {
    print "    puts(" to_C_string(substr($0, 3)) ");"
    position = 0
    expect = ""
    next
}

/^[DAFT] / {
    position++
    label = substr("ABCDEFGHIJKLMNOPQRSTUVWXYZ", position, 1)
    print "    puts(" to_C_string("(" label ") " substr($0, 3)) ");"
    if ($0 ~ /^[AT]/) expect = expect label
    next
}

/^E/ {
    print "    check(" to_C_string(expect) ");"
    print ""
    next
}

/^[^QDAFTER]/ {
    printf "Oh dear, there is an error at line %d of the script %s.\n" \
           "This is our fault, not yours.\n<%s>\n", FNR, FILENAME, $0  \
           >"/dev/stderr"
    exit 1
}

END {
    print "    printf(\"You got %d questions right out of %d.\\n\","
    print "        right, right+wrong);"
    print "    if (wrong == 0) puts(\"Congratulations!\");"
    print "    return wrong == 0 ? EXIT_SUCCESS : EXIT_FAILURE;"
    print "}"
    print ""
}

QA.c

This is generated from QA.dat by QAC.awk.

#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

static int right = 0;
static int wrong = 0;

static void check(char const *expected) {
    char buffer[128];
    int i;
    int flag = 1;

    if (fgets(buffer, sizeof buffer, stdin) == 0) abort();
    for (i = 0; buffer[i] != '\0'; i++) {
        buffer[i] = toupper(buffer[i]);
    }
    for (i = 0; expected[i] != 0; i++) {
        if (strchr(buffer, expected[i]) == 0) flag = 0;
    }
    if (flag) {
        puts("Correct.");
        right++;
    } else {
        printf("Sorry, the right answer is %s.\n", expected);
        wrong++;
    }
}

int main(void) {
    puts("In the context of COMP160,");
    puts("which of the following is an example of a run time error?");
    puts("(A) a false start at a track and field event");
    puts("(B) an overflowing bathtub");
    puts("(C) leaving the cricket crease early");
    puts("(D) an error in coding which compiles correctly but does not run");
    check("D");

    puts("Which of the following statements about local variables are true?");
    puts("(A) Local variables may have a specified visibility.");
    puts("(B) Local variables can be declared as static.");
    puts("(C) Local variables are defined within methods.");
    puts("(D) Local variables are automatically initialised.");
    puts("(E) None of them.");
    check("CD");

    printf("You got %d questions right out of %d.\n",
        right, right+wrong);
    if (wrong == 0) puts("Congratulations!");
    return wrong == 0 ? EXIT_SUCCESS : EXIT_FAILURE;
}

QAF.awk

#!/bin/awk
#   Script : QAF.awk
#   Author : Richard A. O'Keefe
#   Updated: 2013.02.22
#   Purpose: Question-Answer Formatter
#   Usage  : mawk -f common.awk -f latex.awk -f QAF.awk QA.dat >QA.tex
#          : pdflatex QA.tex

#   Note:  this uses a small part (common.awk, latex.awk) of an existing
#   library for converting SGML/XML files to LaTeX/Troff/HTML.  This code
#   that was written for this example is just this file.

BEGIN {
    begin_document()
    begin_numbered_list()
    state = "B"
}

/^Q / {
    if (state != "Q") {
        if (state == "E") end_item()
        begin_item()
        state = "Q"
    }
    put_text(substr($0, 3))
    position = 0
    expect = ""
    next
}

/^[DAFT] / {
    if (state == "Q") {
        begin_unordered_list()
        state = "A"
    } else {
        end_item()
    }
    position++
    label = substr("ABCDEFGHIJKLMNOPQRSTUVWXYZ", position, 1)
    begin_item("(" label ")")
    put_text(substr($0, 3))
    if ($0 ~ /^[AT]/) expect = expect label
    next
}

/^E/ {
    end_item()
    end_unordered_list()
    state = "E"
    next
}

/^[^QDAFTER]/ {
    printf "Oh dear, there is an error at line %d of the script %s.\n" \
           "This is our fault, not yours.\n<%s>\n", FNR, FILENAME, $0  \
           >"/dev/stderr"
    exit 1
}

END {
    end_item()
    end_numbered_list()
    end_document()
}

QA.tex

This is generated from QA.dat by QAF.awk

\documentclass[a4paper]{report}
\usepackage{a4wide}
\begin{document}
\begin{enumerate}
\item{}
In the context of COMP160,
which of the following is an example of a run time error{?}
\begin{itemize}
\item[(A)]
a false start at a track and field event
\item[(B)]
an overflowing bathtub
\item[(C)]
leaving the cricket crease early
\item[(D)]
an error in coding which compiles correctly but does not run
\end{itemize}
\item{}
Which of the following statements about local variables are true{?}
\begin{itemize}
\item[(A)]
Local variables may have a specified visibility.
\item[(B)]
Local variables can be declared as static.
\item[(C)]
Local variables are defined within methods.
\item[(D)]
Local variables are automatically initialised.
\item[(E)]
None of them.
\end{itemize}
\end{enumerate}
\end{document}