ref: 9b51700784b0b76155ad10591b9c224cf80cf3a6
dir: /parse.myr/
use std use "types.use" pkg bld = const parse : (p : parser# -> bool) ;; const failparse = {p : parser#, msg, args : ... var buf : byte[1024] var ap var n ap = std.vastart(&args) n = std.bfmtv(buf[:], msg, ap) std.fput(1, "%s:%i: %s", p.fname, p.line, buf[:n]) std.exit(1) } const parse = {p while true skipspace(p) if !target(p) break ;; ;; skipspace(p) if p.rest.len > 0 failparse(p, "junk in file near %s", p.rest[:std.min(p.rest.len, 10)]) -> false else -> true ;; } const target = {p : parser# match word(p) | `std.Some "bin": bintarget(p) | `std.Some "lib": libtarget(p) | `std.Some "sub": subtarget(p) | `std.Some "man": mantarget(p) | `std.Some targtype: failparse(p, "unknown targtype type %s\n", targtype) | `std.None: -> false ;; -> true } const bintarget = {p p.targs = std.slpush(p.targs, `Bin myrtarget(p, "bin")) } const libtarget = {p p.targs = std.slpush(p.targs, `Lib myrtarget(p, "lib")) } const subtarget = {p p.targs = std.slpush(p.targs, `Sub anontarget(p, "sub")) } const mantarget = {p p.targs = std.slpush(p.targs, `Man anontarget(p, "man")) } const myrtarget = {p, targ var name, inputs, attrs var ldscript, runtime, inst match word(p) | `std.Some n: name = n | `std.None: failparse(p, "expected target name after '%s'\n", targ) ;; skipspace(p) if matchc(p, '{') match attrlist(p) | `std.Some al: attrs = al | `std.None: failparse(p, "invalid attr list for %s %s", targ, name) ;; else attrs = [][:] ;; skipspace(p) if !matchc(p, '=') failparse(p, "expected '=' after '%s %s'", targ, name) ;; match wordlist(p) | `std.Some wl: inputs = wl | `std.None: failparse(p, "expected list of file names after '%s %s'\n", targ, name) ;; skipspace(p) if !matchc(p, ';') failparse(p, "expected ';' terminating input list, got %c\n", peekc(p)) ;; inst = true ldscript = "" runtime = "" for elt in attrs match elt | ("ldscript", lds): ldscript = std.sldup(lds) | ("runtime", rt): runtime = std.sldup(rt) | ("noinst", val): if val.len != 0 failparse(p, "noinst attr does not take argument\n") ;; inst = false ;; ;; -> [ .name=name, .inputs=inputs, .install=inst, .ldscript=ldscript, .runtime=runtime ] } const anontarget = {p, targ var inputs skipspace(p) if !matchc(p, '=') failparse(p, "expected '=' after '%s' target", targ) ;; match wordlist(p) | `std.None: failparse(p, "expected list of file names after '%s' target\n", targ) | `std.Some wl: inputs = wl ;; skipspace(p) if !matchc(p, ';') failparse(p, "expected ';' terminating input list\n") ;; -> inputs } const attrlist = {p var al al = [][:] while true match word(p) | `std.Some k: skipspace(p) if matchc(p, '=') match word(p) | `std.Some v: al = std.slpush(al, (k, v)) | `std.None: failparse(p, "invalid attr in attribute list\n") ;; else al = std.slpush(al, (k, [][:])) ;; | `std.None: break ;; ;; if !matchc(p, '}') failparse(p, "expected '}' at end of attr list\n") ;; if al.len == 0 -> `std.None else -> `std.Some al ;; } const wordlist = {p var wl wl = [][:] while true match word(p) | `std.Some w: wl = std.slpush(wl, w) | `std.None: break ;; ;; if wl.len == 0 -> `std.None else -> `std.Some wl ;; } const word = {p : parser# var c, r, n var start skipspace(p) r = p.rest start = r n = 0 while r.len > 0 c = peekc(p) if wordchar(c) nextc(p) n += std.charlen(c) else break ;; ;; if n > 0 -> `std.Some std.sldup(start[:n]) else -> `std.None ;; } const wordchar = {c -> std.isalnum(c) || \ c == '.' || c == '_' || c == '$' || c == '-' || \ c == '/' || c == ':' || c == '!' || c == '~' } const skipspace = {p : parser# var c, r r = p.rest while r.len > 0 c = peekc(p) match c | ' ': nextc(p) | '\t': nextc(p) | '\n': nextc(p) p.line++ | '#': while p.rest.len > 0 && peekc(p) != '\n' nextc(p) ;; | _: break ;; ;; } const matchc = {p, c var chr, s if p.rest.len == 0 -> false ;; (chr, s) = std.striter(p.rest) if c == chr p.rest = s -> true else -> false ;; } const peekc = {p -> std.decode(p.rest) } const nextc = {p var c, s (c, s) = std.striter(p.rest) p.rest = s -> c }