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.