mirror of
https://github.com/jorenchik/mdemory.git
synced 2026-03-22 00:26:21 +00:00
Parser refactoring
This commit is contained in:
@@ -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;
|
||||||
func main() {
|
content string;
|
||||||
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
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// defineParserAutomata
|
var automata map[TokenType][]TokenType
|
||||||
automata = make(map[TokenType][]TokenType)
|
|
||||||
|
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
|
||||||
|
}
|
||||||
|
|
||||||
|
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{
|
||||||
|
message: fmt.Sprintf(
|
||||||
"Token %s cannot precede %s\n",
|
"Token %s cannot precede %s\n",
|
||||||
ToString(&token.tokenType),
|
ToString(&token.tokenType),
|
||||||
ToString(&nextToken.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
|
|
||||||
}
|
|
||||||
|
|||||||
Reference in New Issue
Block a user