miki

Miki: personal wiki with the fmd markup format
git clone https://wtenison.com/repo/miki.git
Log | Files | Refs | README | LICENSE

commit e0ab93a77f243af664423974da884ec30a4876c5
parent acf3ea53f035cf711f77cc403fe9c24391e152cb
Author: weetat <wtenison@protonmail.com>
Date:   Fri, 28 Feb 2025 18:25:28 +0000

Add EBNF grammar for fmd

Also rename tokenLiteral to tokenWord, add ( and ) to the lexer symbols,
and comment what each keyword does.

Diffstat:
Asrc/fmd/fmd.ebnf | 16++++++++++++++++
Msrc/fmd/lexer.go | 18++++++++++++++----
Msrc/fmd/parser.go | 5+++--
3 files changed, 33 insertions(+), 6 deletions(-)

diff --git a/src/fmd/fmd.ebnf b/src/fmd/fmd.ebnf @@ -0,0 +1,15 @@ +<fmd> ::= (<command> | <block>)* + +<command> ::= <keyword> ":" <word>| + <keyword> ":" "{" <block> "}" | + <keyword> "(" <block> ")" ":" <word> | + <keyword> "(" <block> ")" ":" "{" <block> "}" | + +<block> ::= (<word> | <space>)+ +<word> ::= (<letter> | <number> | <symbol>)+ +<keyword> ::= "b" | "i" | "h" [1-6] | "@" | "^" | "#" + +<space> ::= " " +<letter> ::= [a-z] | [A-Z] +<number> ::= [0-9]+ | (<number> "." <number>) +<symbol> ::= "." | "," | ";" | "-" | "!" | "#" | "$" | "%" | "^" | "&" | "*" | "(" | ")" +\ No newline at end of file diff --git a/src/fmd/lexer.go b/src/fmd/lexer.go @@ -11,7 +11,7 @@ type tokenType int const ( // WORDS - tokenLiteral tokenType = iota // 0. (letters, numbers, symbols)+ + tokenWord tokenType = iota // 0. (letters, numbers, symbols)+ tokenKeyword // 1. (valid keywords) // SPACING @@ -24,6 +24,8 @@ const ( tokenColon // 6. : tokenLBrace // 7. { tokenRBrace // 8. } + tokenLParen // 9. ( + tokenRParen // 10. ) ) type token struct { @@ -31,9 +33,17 @@ type token struct { Value string } -var symbols = []string{" ", "\n", "\t", "\\", ":", "{", "}"} +var symbols = []string{" ", "\n", "\t", "\\", ":", "{", "}", "(", ")"} var keywords = []string{ - "b", "i", "h1", "h2", "h3", "h4", "h5", "h6", "@", "#", "col", "img", "_"} + "b", // bold + "i", // italic + "h1", "h2", "h3", "h4", "h5", "h6", // header + "@", // link + "#", // tag + "col", // column container + "img", // image + "_", // empty container (<div>) +} type lexer struct { input []byte // text input to scan @@ -85,7 +95,7 @@ func (l *lexer) Exec() []token { if slices.Contains(keywords, _tokenString) { l.tokens = append(l.tokens, token{tokenKeyword, _tokenString}) } else if _tokenString != "" { - l.tokens = append(l.tokens, token{tokenLiteral, _tokenString}) + l.tokens = append(l.tokens, token{tokenWord, _tokenString}) } } } diff --git a/src/fmd/parser.go b/src/fmd/parser.go @@ -91,14 +91,14 @@ func (p *parser) parseBlock() node { } func (p *parser) parseLiteral() node { - _literal := node{nType: nodeLiteral, value: p.consume(tokenLiteral).Value} + _literal := node{nType: nodeLiteral, value: p.consume(tokenWord).Value} return _literal } func (p *parser) isNextCommand() bool { return p.peekNextN(tokenKeyword, 0) && p.peekNextN(tokenColon, 1) && - p.peekNextN(tokenLiteral, 2) || + p.peekNextN(tokenWord, 2) || p.peekNextN(tokenLBrace, 2) } @@ -113,6 +113,7 @@ func (p *parser) consume(t tokenType) token { p.pos++ return token } + // TODO: Error out gracefully and send empty AST. panic(fmt.Sprintf("__PANIC\tfmd:parser:Invalid token:%v", t)) }