summaryrefslogtreecommitdiff
path: root/scanner
diff options
context:
space:
mode:
authorMarc Vertes <mvertes@free.fr>2026-01-06 19:02:29 +0100
committerMarc Vertes <mvertes@free.fr>2026-01-06 19:02:29 +0100
commitbffc031ea83c7176aac3d3828de0060c6630140c (patch)
tree32e30f3bec94884936c2cfc2d53d3ae496e13d61 /scanner
parentf07fc0178831432b68f1b9bd6c96b257aa2e9abe (diff)
fix: correct and simplify parsing of expressions.
The expressions were parsed from right to left, and it was incorrect and cumbersome. Now they are processed from left to right, with a simpler and correct handling of precedence rules. The vm function call syntax has been changed to set the function before the input arguments on the stack, as to follow the declaring order in languages.
Diffstat (limited to 'scanner')
-rw-r--r--scanner/scan.go20
1 files changed, 11 insertions, 9 deletions
diff --git a/scanner/scan.go b/scanner/scan.go
index edd8b1c..cb1549e 100644
--- a/scanner/scan.go
+++ b/scanner/scan.go
@@ -46,8 +46,10 @@ func (t *Token) Name() string {
func (t *Token) String() string {
s := t.Tok.String()
if t.Tok.IsLiteral() || t.Tok.IsBlock() || t.Tok == lang.Ident || t.Tok == lang.Comment ||
- t.Tok == lang.Period || t.Tok == lang.Label || t.Tok == lang.Goto {
+ t.Tok == lang.Period || t.Tok == lang.Label || t.Tok == lang.Goto || t.Tok == lang.JumpSetFalse || t.Tok == lang.JumpSetTrue || t.Tok == lang.JumpFalse || t.Tok == lang.Colon || t.Tok == lang.Composite {
s += strconv.Quote(t.Str)
+ } else if t.Tok == lang.Call {
+ s += "(" + strconv.Itoa(t.Beg) + ")"
}
return s
}
@@ -119,8 +121,8 @@ func (sc *Scanner) Scan(src string, semiEOF bool) (tokens []Token, err error) {
if len(tokens) > 0 && t.Str == "\n" {
// Check for automatic semi-colon insertion after newline.
last := tokens[len(tokens)-1]
- if last.Tok.IsKeyword() && sc.TokenProps[last.Str].SkipSemi ||
- last.Tok.IsOperator() && !sc.TokenProps[last.Str].SkipSemi {
+ if last.Tok.IsKeyword() && sc.TokenProps[last.Tok].SkipSemi ||
+ last.Tok.IsOperator() && !sc.TokenProps[last.Tok].SkipSemi {
skip = true
} else {
t.Tok = lang.Semicolon
@@ -142,8 +144,8 @@ func (sc *Scanner) Scan(src string, semiEOF bool) (tokens []Token, err error) {
if last.Str == ";" {
return tokens, nil
}
- if last.Tok == lang.Ident && sc.TokenProps[last.Str].SkipSemi ||
- last.Tok.IsOperator() && !sc.TokenProps[last.Str].SkipSemi {
+ if last.Tok == lang.Ident && sc.TokenProps[last.Tok].SkipSemi ||
+ last.Tok.IsOperator() && !sc.TokenProps[last.Tok].SkipSemi {
return tokens, nil
}
tokens = append(tokens, Token{Tok: lang.Semicolon, Str: ";"})
@@ -179,7 +181,7 @@ func (sc *Scanner) Next(src string) (tok Token, err error) {
return Token{}, nil
case sc.isGroupSep(r):
// TODO: handle group separators.
- return Token{Tok: sc.TokenProps[string(r)].Token, Pos: p + i, Str: string(r)}, nil
+ return Token{Tok: sc.Tokens[string(r)], Pos: p + i, Str: string(r)}, nil
case sc.isLineSep(r):
return Token{Pos: p + i, Str: "\n"}, nil
case sc.isStr(r):
@@ -194,12 +196,12 @@ func (sc *Scanner) Next(src string) (tok Token, err error) {
err = ErrBlock
}
tok := Token{Pos: p + i, Str: b, Beg: 1, End: 1}
- tok.Tok = sc.TokenProps[tok.Name()].Token
+ tok.Tok = sc.Tokens[tok.Name()]
return tok, err
case sc.isOp(r):
op, isOp := sc.getOp(src[i:])
if isOp {
- t := sc.TokenProps[op].Token
+ t := sc.Tokens[op]
if t == lang.Illegal {
err = fmt.Errorf("%w: %s", ErrIllegal, op)
}
@@ -218,7 +220,7 @@ func (sc *Scanner) Next(src string) (tok Token, err error) {
default:
t, isDefined := sc.getToken(src[i:])
if isDefined {
- ident := sc.TokenProps[t].Token
+ ident := sc.Tokens[t]
if ident == lang.Illegal {
ident = lang.Ident
}