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:
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))
}