mirror of
https://github.com/jorenchik/mdemory.git
synced 2026-03-22 00:26:21 +00:00
Parsing
This commit is contained in:
@@ -7,11 +7,35 @@ import (
|
||||
"strings"
|
||||
)
|
||||
|
||||
var automata map[TokenType][]TokenType
|
||||
|
||||
type SingleAnswerQuestion struct {
|
||||
id string;
|
||||
question string;
|
||||
answer string;
|
||||
section string;
|
||||
}
|
||||
|
||||
type Choice struct {
|
||||
answer string;
|
||||
isCorrect bool;
|
||||
}
|
||||
|
||||
type ChoiceQuestion struct {
|
||||
id string;
|
||||
question string;
|
||||
choices []Choice;
|
||||
section string;
|
||||
}
|
||||
|
||||
type Question interface {}
|
||||
|
||||
func main() {
|
||||
log.Println("Compilation started")
|
||||
|
||||
file, err := os.ReadFile("./input.mdem")
|
||||
if (err != nil) { log.Fatal("Cannot open the input file")
|
||||
file, err := os.ReadFile("/home/jorenchik/Code/mdemory/src/compiler/input.mdem")
|
||||
if (err != nil) {
|
||||
log.Fatalf("Cannot open the input file: %s", err.Error())
|
||||
return
|
||||
}
|
||||
fileContents := string(file)
|
||||
@@ -22,13 +46,56 @@ func main() {
|
||||
return
|
||||
}
|
||||
|
||||
// prettyPrintTokens
|
||||
for i := 0; i < len(tokens); i++ {
|
||||
// defineParserAutomata
|
||||
automata = make(map[TokenType][]TokenType)
|
||||
automata[TextFragment] = []TokenType{
|
||||
QuestionEnd, ElementDashStart, ElementPlusStart, SectionIdentifierStart, SectionStart, EOF, SectionEnd,
|
||||
}
|
||||
automata[QuestionEnd] = []TokenType{
|
||||
ElementDashStart, ElementPlusStart,
|
||||
}
|
||||
automata[ElementDashStart] = []TokenType{
|
||||
IdentifierStart, TextFragment,
|
||||
}
|
||||
automata[ElementPlusStart] = []TokenType{
|
||||
TextFragment,
|
||||
}
|
||||
automata[Identifier] = []TokenType{
|
||||
IdentifierEnd, SectionStart,
|
||||
}
|
||||
automata[IdentifierStart] = []TokenType{
|
||||
Identifier,
|
||||
}
|
||||
automata[IdentifierEnd] = []TokenType{
|
||||
TextFragment,
|
||||
}
|
||||
automata[SectionIdentifierStart] = []TokenType{
|
||||
Identifier,
|
||||
}
|
||||
automata[SectionStart] = []TokenType{
|
||||
ElementDashStart, SectionIdentifierStart, EOF,
|
||||
}
|
||||
automata[SectionEnd] = []TokenType{
|
||||
SectionIdentifierStart, ElementDashStart, EOF,
|
||||
}
|
||||
automata[SOF] = []TokenType{
|
||||
ElementDashStart, SectionIdentifierStart, EOF,
|
||||
}
|
||||
automata[EOF] = []TokenType{}
|
||||
|
||||
// validateGrammar
|
||||
for i := 0; i < len(tokens) - 1; i++ {
|
||||
token := tokens[i]
|
||||
content := token.content
|
||||
if (token.tokenType == TextFragment) {
|
||||
content = strings.Replace(strings.Trim(content, " "), "\n", "\\n", -1)
|
||||
content = strings.Replace(
|
||||
strings.Trim(content, " "),
|
||||
"\n",
|
||||
"\\n",
|
||||
-1,
|
||||
)
|
||||
}
|
||||
nextToken := tokens[i + 1]
|
||||
fmt.Printf(
|
||||
"%s: \"%s\" %d:%d\n",
|
||||
ToString(&token.tokenType),
|
||||
@@ -36,7 +103,148 @@ func main() {
|
||||
token.row,
|
||||
token.column,
|
||||
)
|
||||
if (false) {
|
||||
fmt.Print("Possible next tokens:")
|
||||
for k:=0; k<len(automata[token.tokenType]); k++ {
|
||||
ttype := automata[token.tokenType][k]
|
||||
fmt.Printf(" %s,", ToString(&ttype))
|
||||
}
|
||||
fmt.Print("\n:")
|
||||
}
|
||||
if (!contains(automata[token.tokenType], nextToken.tokenType)) {
|
||||
fmt.Printf(
|
||||
"Token %s cannot precede %s\n",
|
||||
ToString(&token.tokenType),
|
||||
ToString(&nextToken.tokenType),
|
||||
)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// extract questions
|
||||
questions := []Question{}
|
||||
section := ""
|
||||
i := 0
|
||||
for {
|
||||
if (i >= len(tokens)) {
|
||||
break
|
||||
}
|
||||
if (tokens[i].tokenType == ElementDashStart) {
|
||||
id := tokens[i + 2].content
|
||||
question := tokens[i + 4].content
|
||||
quesitonElements := []QuestionElement{}
|
||||
i += 6
|
||||
for {
|
||||
if (i + 1 >= len(tokens) ||
|
||||
!(tokens[i].tokenType == ElementDashStart ||
|
||||
tokens[i].tokenType == ElementPlusStart) ||
|
||||
tokens[i+1].tokenType == IdentifierStart) {
|
||||
break
|
||||
}
|
||||
questionElement := QuestionElement{}
|
||||
if (tokens[i].tokenType == ElementDashStart) {
|
||||
questionElement.isDash = true
|
||||
} else {
|
||||
questionElement.isDash = false
|
||||
}
|
||||
questionElement.content = tokens[i+1].content
|
||||
quesitonElements = append(quesitonElements, questionElement)
|
||||
i += 2
|
||||
}
|
||||
if len(quesitonElements) > 1 {
|
||||
question := ChoiceQuestion{
|
||||
id: id,
|
||||
question: question,
|
||||
}
|
||||
choices := []Choice{}
|
||||
for k := 0; k < len(quesitonElements); k++ {
|
||||
choice := Choice{}
|
||||
choice.answer = quesitonElements[k].content
|
||||
choice.isCorrect = !quesitonElements[k].isDash
|
||||
choices = append(choices, choice)
|
||||
}
|
||||
if (section != "") {
|
||||
question.section = section
|
||||
}
|
||||
question.choices = choices
|
||||
questions = append(questions, question)
|
||||
} else if (len(quesitonElements) == 1) {
|
||||
question := SingleAnswerQuestion{
|
||||
id: id,
|
||||
question: question,
|
||||
answer: quesitonElements[0].content,
|
||||
}
|
||||
if (section != "") {
|
||||
question.section = section
|
||||
}
|
||||
questions = append(questions, question)
|
||||
}
|
||||
} else if (tokens[i].tokenType == SectionIdentifierStart) {
|
||||
section = tokens[i + 1].content
|
||||
i += 3;
|
||||
} else if (tokens[i].tokenType == SectionEnd) {
|
||||
section = ""
|
||||
i += 1
|
||||
} else if (tokens[i].tokenType == EOF) {
|
||||
break
|
||||
} else {
|
||||
log.Fatalf(
|
||||
"Not handled: %s",
|
||||
ToString(&tokens[i].tokenType),
|
||||
)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
for _, element := range questions {
|
||||
switch element.(type) {
|
||||
case SingleAnswerQuestion:
|
||||
fmt.Printf(
|
||||
"<Single choice> (%s) %s: %s\n",
|
||||
element.(SingleAnswerQuestion).section,
|
||||
strings.Trim(element.(SingleAnswerQuestion).question, "\t\n "),
|
||||
strings.Trim(element.(SingleAnswerQuestion).answer, "\t\n "),
|
||||
)
|
||||
case ChoiceQuestion:
|
||||
fmt.Printf(
|
||||
"<Multi choice> (%s) %s\n",
|
||||
element.(ChoiceQuestion).section,
|
||||
element.(ChoiceQuestion).question,
|
||||
)
|
||||
for _, el := range element.(ChoiceQuestion).choices {
|
||||
opener := '-'
|
||||
if (el.isCorrect) {
|
||||
opener = '+'
|
||||
}
|
||||
fmt.Printf("\t%c %s\n", opener, strings.Trim(el.answer, "\t\n "))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
log.Println("Compilation completed")
|
||||
}
|
||||
|
||||
type QuestionElement struct {
|
||||
isDash bool;
|
||||
content string;
|
||||
}
|
||||
|
||||
|
||||
type CompilerErr struct {
|
||||
message string;
|
||||
row int32;
|
||||
column int32;
|
||||
}
|
||||
|
||||
func (e CompilerErr) Error() string {
|
||||
return fmt.Sprintf("%d:%d - %s", e.row, e.column, e.message)
|
||||
}
|
||||
|
||||
func contains(s []TokenType, e TokenType) bool {
|
||||
for _, a := range s {
|
||||
if a == e {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user