I'm following up on a post that was done in 2014 (to which I am unable to reply, perhaps because it's too old?).
GIFT (or something like it) is a great format because it requires much less clicking to create a lot of questions for quizzes. You can save GIFT in your own text file, in an email, etc. It's an example of a domain-specific language; they are developed to aid in crafting solutions to problems that are specific to certain domains. Creating quiz questions is one such domain.
I recently used PEG.js in a project to create a parser for a domain-specific language. It could be useful to consider PEG.js to parse GIFT format.
The really cool thing about PEG.js is there's a web page that makes grammar development really easy. It's not an IDE, so you have to save your results in a real text file from time to time. You can use sample input, and see the error messages that come from your grammar when it doesn't parse properly.
Here's a start on a grammar that recognizes trivial T/F and MC questions (the input file follows):
Expression = Spacing Rule+ EndOfFile Rule = title:QuestionTitle? stem:QuestionStem questionType:SpecificQuestion Space* EndOfLine* { return questionType + ' question:\n ' + title + "\n" + stem } / Comment EndOfLine* SpecificQuestion "(specific question)" = TrueFalseQuestion / MCQuestion TrueFalseQuestion "True/False Question" = '{' isTrue:('T'/'F') '}' { return isTrue; } MCQuestion "Multiple-choice Question" = '{' EndOfLine choices:(Choice)+ '}' { return "Multiple-choice"; } Choice "Choice" = CorrectChoice / IncorrectChoice CorrectChoice "(correct choice)" = '=' correctChoice:RichText EndOfLine { return 'correct choice: ' + correctChoice;} IncorrectChoice "(correct choice)" = '~' incorrectChoice:RichText EndOfLine { return 'incorrect choice: ' + incorrectChoice;} QuestionTitle = '::' title:Title '::' { return ' title: ' + title } QuestionStem = stem:RichText { return ' stem: ' + stem; } Text "(text)" = [ A-Za-z0-9.+] RichText = Text* { return 'RichText:' + text() } Title = Text* { return text() } _ "whitespace" = [ \t]* Spacing = (Space / Comment)* Comment "(comment)" = '//' (!EndOfLine .)* EndOfLine { return 'comment';} Space "(space)" = ' ' / '\t' EndOfLine "(end of line)" = '\r\n' / '\n' / '\r' EndOfFile = !. { return "EOF"; }
Here's a sample input that parses:
// comment at top ::True statement about Grant::Grant was buried in a tomb in New York City.{T} ::False statement about Grant::Grant was never buried.{F} // comment in middle ::Math question:: What is 1+2 { =3 ~4 ~2 }
I'm pretty sure my grammar above is not perfect - it needs more testing. For example, it doesn't support feedback on answers (e.g. the '#' option). The goal is to show what can be done with PEG and why a grammar for GIFT would be great.