diff options
Diffstat (limited to 'grammar')
-rw-r--r-- | grammar/first_test.go | 10 | ||||
-rw-r--r-- | grammar/follow_test.go | 10 | ||||
-rw-r--r-- | grammar/grammar.go | 40 | ||||
-rw-r--r-- | grammar/lalr1_test.go | 2 | ||||
-rw-r--r-- | grammar/lr0_test.go | 4 | ||||
-rw-r--r-- | grammar/parsing_table_test.go | 4 | ||||
-rw-r--r-- | grammar/semantic_error.go | 1 | ||||
-rw-r--r-- | grammar/slr1_test.go | 2 |
8 files changed, 71 insertions, 2 deletions
diff --git a/grammar/first_test.go b/grammar/first_test.go index 041f411..578825e 100644 --- a/grammar/first_test.go +++ b/grammar/first_test.go @@ -24,6 +24,8 @@ func TestGenFirst(t *testing.T) { { caption: "productions contain only non-empty productions", src: ` +%name test + expr : expr add term | term @@ -61,6 +63,8 @@ id: "[A-Za-z_][0-9A-Za-z_]*"; { caption: "productions contain the empty start production", src: ` +%name test + s : ; @@ -73,6 +77,8 @@ s { caption: "productions contain an empty production", src: ` +%name test + s : foo bar ; @@ -90,6 +96,8 @@ bar: "bar"; { caption: "a start production contains a non-empty alternative and empty alternative", src: ` +%name test + s : foo | @@ -105,6 +113,8 @@ foo: "foo"; { caption: "a production contains non-empty alternative and empty alternative", src: ` +%name test + s : foo ; diff --git a/grammar/follow_test.go b/grammar/follow_test.go index 3500d14..ba2d973 100644 --- a/grammar/follow_test.go +++ b/grammar/follow_test.go @@ -22,6 +22,8 @@ func TestFollowSet(t *testing.T) { { caption: "productions contain only non-empty productions", src: ` +%name test + expr : expr add term | term @@ -50,6 +52,8 @@ id: "[A-Za-z_][0-9A-Za-z_]*"; { caption: "productions contain an empty start production", src: ` +%name test + s : ; @@ -62,6 +66,8 @@ s { caption: "productions contain an empty production", src: ` +%name test + s : foo ; @@ -78,6 +84,8 @@ foo { caption: "a start production contains a non-empty alternative and empty alternative", src: ` +%name test + s : foo | @@ -92,6 +100,8 @@ foo: "foo"; { caption: "a production contains non-empty alternative and empty alternative", src: ` +%name test + s : foo ; diff --git a/grammar/grammar.go b/grammar/grammar.go index 39a10a8..2294219 100644 --- a/grammar/grammar.go +++ b/grammar/grammar.go @@ -82,6 +82,7 @@ func (pa *precAndAssoc) productionAssociativity(prod productionNum) assocType { const reservedSymbolNameError = "error" type Grammar struct { + name string lexSpec *mlspec.LexSpec skipLexKinds []mlspec.LexKindName kindAliases map[symbol]string @@ -104,6 +105,37 @@ type GrammarBuilder struct { } func (b *GrammarBuilder) Build() (*Grammar, error) { + var specName string + { + errOccurred := false + for _, md := range b.AST.MetaData { + if md.Name != "name" { + continue + } + + if len(md.Parameters) != 1 || md.Parameters[0].ID == "" { + b.errs = append(b.errs, &verr.SpecError{ + Cause: semErrMDInvalidParam, + Detail: fmt.Sprintf("'name' takes just one ID parameter"), + Row: md.Pos.Row, + Col: md.Pos.Col, + }) + + errOccurred = true + break + } + + specName = md.Parameters[0].ID + break + } + + if specName == "" && !errOccurred { + b.errs = append(b.errs, &verr.SpecError{ + Cause: semErrMDMissingName, + }) + } + } + symTabAndLexSpec, err := b.genSymbolTableAndLexSpec(b.AST) if err != nil { return nil, err @@ -167,10 +199,10 @@ func (b *GrammarBuilder) Build() (*Grammar, error) { return nil, b.errs } - // FIXME - symTabAndLexSpec.lexSpec.Name = "lex" + symTabAndLexSpec.lexSpec.Name = specName return &Grammar{ + name: specName, lexSpec: symTabAndLexSpec.lexSpec, skipLexKinds: symTabAndLexSpec.skip, kindAliases: symTabAndLexSpec.aliases, @@ -868,6 +900,9 @@ func (b *GrammarBuilder) genPrecAndAssoc(symTab *symbolTable, prods *productionS assocTy = assocTypeLeft case "right": assocTy = assocTypeRight + case "name": + // Since `name` is used for a purpose other than priority, we will ignore it here. + continue default: return nil, &verr.SpecError{ Cause: semErrMDInvalidName, @@ -1150,6 +1185,7 @@ func Compile(gram *Grammar, opts ...CompileOption) (*spec.CompiledGrammar, error } return &spec.CompiledGrammar{ + Name: gram.name, LexicalSpecification: &spec.LexicalSpecification{ Lexer: "maleeni", Maleeni: &spec.Maleeni{ diff --git a/grammar/lalr1_test.go b/grammar/lalr1_test.go index 1cf8762..beb2707 100644 --- a/grammar/lalr1_test.go +++ b/grammar/lalr1_test.go @@ -10,6 +10,8 @@ import ( func TestGenLALR1Automaton(t *testing.T) { // This grammar belongs to LALR(1) class, not SLR(1). src := ` +%name test + S: L eq R | R; L: ref R | id; R: L; diff --git a/grammar/lr0_test.go b/grammar/lr0_test.go index 4a613dd..cde3f0a 100644 --- a/grammar/lr0_test.go +++ b/grammar/lr0_test.go @@ -17,6 +17,8 @@ type expectedLRState struct { func TestGenLR0Automaton(t *testing.T) { src := ` +%name test + expr : expr add term | term @@ -225,6 +227,8 @@ id: "[A-Za-z_][0-9A-Za-z_]*"; func TestLR0AutomatonContainingEmptyProduction(t *testing.T) { src := ` +%name test + s : foo bar ; diff --git a/grammar/parsing_table_test.go b/grammar/parsing_table_test.go index feec74a..833a4d4 100644 --- a/grammar/parsing_table_test.go +++ b/grammar/parsing_table_test.go @@ -16,6 +16,8 @@ type expectedState struct { func TestGenLALRParsingTable(t *testing.T) { src := ` +%name test + S: L eq R | R; L: ref R | id; R: L; @@ -286,6 +288,8 @@ id: "[A-Za-z0-9_]+"; func TestGenSLRParsingTable(t *testing.T) { src := ` +%name test + expr : expr add term | term diff --git a/grammar/semantic_error.go b/grammar/semantic_error.go index c4ab9f6..d540c03 100644 --- a/grammar/semantic_error.go +++ b/grammar/semantic_error.go @@ -17,6 +17,7 @@ func (e *SemanticError) Error() string { var ( semErrMDInvalidName = newSemanticError("invalid meta data name") semErrMDInvalidParam = newSemanticError("invalid parameter") + semErrMDMissingName = newSemanticError("name is missing") semErrUnusedProduction = newSemanticError("unused production") semErrUnusedTerminal = newSemanticError("unused terminal") semErrTermCannotBeSkipped = newSemanticError("a terminal used in productions cannot be skipped") diff --git a/grammar/slr1_test.go b/grammar/slr1_test.go index c773c6a..954446f 100644 --- a/grammar/slr1_test.go +++ b/grammar/slr1_test.go @@ -9,6 +9,8 @@ import ( func TestGenSLR1Automaton(t *testing.T) { src := ` +%name test + expr : expr add term | term |