Parser refactoring

This commit is contained in:
jorenchik
2024-08-04 15:06:24 +03:00
parent 64a250bb77
commit 70db69ed88

View File

@@ -7,7 +7,7 @@ import (
"strings" "strings"
) )
var automata map[TokenType][]TokenType type Question interface {}
type SingleAnswerQuestion struct { type SingleAnswerQuestion struct {
id string; id string;
@@ -21,33 +21,41 @@ type Choice struct {
isCorrect bool; isCorrect bool;
} }
type ChoiceQuestion struct { type MultipleChoiceQuestion struct {
id string; id string;
question string; question string;
choices []Choice; choices []Choice;
section string; section string;
} }
type Question interface {} type QuestionElement struct {
isDash bool;
content string;
}
func main() { var automata map[TokenType][]TokenType
log.Println("Compilation started")
file, err := os.ReadFile("/home/jorenchik/Code/mdemory/src/compiler/input.mdem") type CompilerErr struct {
if (err != nil) { message string;
log.Fatalf("Cannot open the input file: %s", err.Error()) row int32;
return column int32;
} }
fileContents := string(file)
tokens, err := tokenize([]rune(fileContents)) func (e CompilerErr) Error() string {
if (err != nil) { return fmt.Sprintf("%d:%d - %s", e.row, e.column, e.message)
fmt.Printf("%s\n", err.Error()) }
return
}
// defineParserAutomata func contains(s []TokenType, e TokenType) bool {
automata = make(map[TokenType][]TokenType) for _, a := range s {
if a == e {
return true
}
}
return false
}
func parserAutomata() map[TokenType][]TokenType {
automata := make(map[TokenType][]TokenType)
automata[TextFragment] = []TokenType{ automata[TextFragment] = []TokenType{
QuestionEnd, ElementDashStart, ElementPlusStart, SectionIdentifierStart, SectionStart, EOF, SectionEnd, QuestionEnd, ElementDashStart, ElementPlusStart, SectionIdentifierStart, SectionStart, EOF, SectionEnd,
} }
@@ -82,8 +90,10 @@ func main() {
ElementDashStart, SectionIdentifierStart, EOF, ElementDashStart, SectionIdentifierStart, EOF,
} }
automata[EOF] = []TokenType{} automata[EOF] = []TokenType{}
return automata
}
// validateGrammar func validateGrammar() error {
for i := 0; i < len(tokens) - 1; i++ { for i := 0; i < len(tokens) - 1; i++ {
token := tokens[i] token := tokens[i]
content := token.content content := token.content
@@ -112,16 +122,21 @@ func main() {
fmt.Print("\n:") fmt.Print("\n:")
} }
if (!contains(automata[token.tokenType], nextToken.tokenType)) { if (!contains(automata[token.tokenType], nextToken.tokenType)) {
fmt.Printf( return CompilerErr{
"Token %s cannot precede %s\n", message: fmt.Sprintf(
ToString(&token.tokenType), "Token %s cannot precede %s\n",
ToString(&nextToken.tokenType), ToString(&token.tokenType),
) ToString(&nextToken.tokenType),
return ),
row: token.row,
column: token.column,
}
} }
} }
return nil
}
// extract questions func ParseQuestions(tokens []Token) ([]Question, error) {
questions := []Question{} questions := []Question{}
section := "" section := ""
i := 0 i := 0
@@ -152,7 +167,7 @@ func main() {
i += 2 i += 2
} }
if len(quesitonElements) > 1 { if len(quesitonElements) > 1 {
question := ChoiceQuestion{ question := MultipleChoiceQuestion{
id: id, id: id,
question: question, question: question,
} }
@@ -192,10 +207,42 @@ func main() {
"Not handled: %s", "Not handled: %s",
ToString(&tokens[i].tokenType), ToString(&tokens[i].tokenType),
) )
return return nil, CompilerErr{
message: "",
row: tokens[i].row,
column: tokens[i].column,
}
} }
} }
return questions, nil
}
func main() {
log.Println("Compilation started")
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)
tokens, err := tokenize([]rune(fileContents))
if (err != nil) {
fmt.Printf("%s\n", err.Error())
return
}
automata = parserAutomata()
err = validateGrammar()
if (err != nil) {
log.Fatal(err.Error())
}
questions, err := ParseQuestions(tokens)
if (err != nil) {
log.Fatal(err.Error())
}
for _, element := range questions { for _, element := range questions {
switch element.(type) { switch element.(type) {
case SingleAnswerQuestion: case SingleAnswerQuestion:
@@ -205,13 +252,13 @@ func main() {
strings.Trim(element.(SingleAnswerQuestion).question, "\t\n "), strings.Trim(element.(SingleAnswerQuestion).question, "\t\n "),
strings.Trim(element.(SingleAnswerQuestion).answer, "\t\n "), strings.Trim(element.(SingleAnswerQuestion).answer, "\t\n "),
) )
case ChoiceQuestion: case MultipleChoiceQuestion:
fmt.Printf( fmt.Printf(
"<Multi choice> (%s) %s\n", "<Multi choice> (%s) %s\n",
element.(ChoiceQuestion).section, element.(MultipleChoiceQuestion).section,
element.(ChoiceQuestion).question, element.(MultipleChoiceQuestion).question,
) )
for _, el := range element.(ChoiceQuestion).choices { for _, el := range element.(MultipleChoiceQuestion).choices {
opener := '-' opener := '-'
if (el.isCorrect) { if (el.isCorrect) {
opener = '+' opener = '+'
@@ -223,28 +270,3 @@ func main() {
log.Println("Compilation completed") 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
}