diff options
Diffstat (limited to 'src/parse.cff')
| -rw-r--r-- | src/parse.cff | 83 |
1 files changed, 83 insertions, 0 deletions
diff --git a/src/parse.cff b/src/parse.cff index f659322..d672173 100644 --- a/src/parse.cff +++ b/src/parse.cff @@ -80,6 +80,20 @@ fn issep(c u8) bool { return #f; } +fn readtilsep(P *Parser, buf [#]u8, dot bool) int { + let i = 0, + c u8 #?; + while (not issep(c = chrpeek(P))) or (dot and c == '.') { + chr(P); + if i >= buf.#len - 1 { + return -1; + } + buf[i++] = c; + } + buf[i++] = 0; + return i; +} + fn eatspaces(P *Parser) void { for ;;chr(P) { if not isspace(chrpeek(P)) { @@ -115,6 +129,59 @@ fn str2keyword(s *const u8) int { return -1; } +fn readnumber(s *const u8) Option<Tok> { + let c u8 #?, + acc = 0u64, + accf = 0.0f64, + fmul = 0.1, + base = 10, + flt = #f, + nused = 0, + suffix *const u8 = #null; + + for let i = 0; (c = s[i]) != 0; ++i { + if i == 0 and c == '0' { + --nused; + } + if i == 1 and tolower(c) == 'x' { + base = 16; + continue; + } + if not flt and c == '.' and base == 10 { + flt = #t; + accf = acc; + continue; + } + if nused > 0 and c == '_' { continue; } + if (base == 16 and not isdigit(c)) + or (base != 16 and (c < '0' or c > ('0' + base) - 1)) { + suffix = s + i; + } + + ++nused; + if flt { + accf = accf + ((c - '0') * fmul); + fmul *= 0.1; + } else { + c = tolower(c); + acc = (acc * base) + (c <= '9' ? c - '0' : (c - 'a') + 10); + } + } + + let tok = Tok {}; + if flt { + tok.t = :flo; + tok.u.flo = accf; + return :Some tok; + } else { + tok.t = :int; + tok.u.uint = acc; + return :Some tok; + } + + return :None; +} + fn lex(P *Parser) Tok { let c int #?; let tok Tok = {}; @@ -129,7 +196,22 @@ fn lex(P *Parser) Tok { tok.loc = (P.tokloc = P.curloc); if isdigit(c = chrpeek(P)) { let s [80]u8 = {}; + if readtilsep(P, s[0::], #t) < 0 { + // fatal + } + switch readnumber(s) { + case None; + fatal(P, tok.loc, "bad number literal %qs", s); + case Some tok; + tok.loc = P.tokloc; + return tok; + } + } + if c == EOF { + tok.t = :eof; + return tok; } + fatal(P, tok.loc, "stray %qc in program", c); } extern fn parse(P *Parser) [#]Decl { @@ -137,6 +219,7 @@ extern fn parse(P *Parser) [#]Decl { } extern fn parser_init(P *Parser, path *const u8) void { + assert(NUM_KEYWORDS - 1 < '!', "2manykw"); *P = {}; P.curfile = path; if (P.fp = fopen(path, "r")) == #null { |