4 local function read(expected)
\r
7 ch = last; last = nil;
\r
8 else ch = file:read(1); end
\r
9 if expected and ch ~= expected then error("expected: "..expected.."; got: "..(ch or "nil")); end
\r
12 local function pushback(ch)
\r
13 if last then error(); end
\r
16 local function peek()
\r
17 if not last then last = read(); end
\r
21 local _A, _a, _Z, _z, _0, _9, __, _space = string.byte("AaZz09_ ", 1, 8);
\r
22 local function isAlpha(ch)
\r
23 ch = string.byte(ch) or 0;
\r
24 return (ch >= _A and ch <= _Z) or (ch >= _a and ch <= _z);
\r
26 local function isNumeric(ch)
\r
27 ch = string.byte(ch) or 0;
\r
28 return (ch >= _0 and ch <= _9);
\r
30 local function isVar(ch)
\r
31 ch = string.byte(ch) or 0;
\r
32 return (ch >= _A and ch <= _Z) or (ch >= _a and ch <= _z) or (ch >= _0 and ch <= _9) or ch == __;
\r
34 local function isSpace(ch)
\r
35 ch = string.byte(ch) or "x";
\r
36 return ch <= _space;
\r
39 local function readString()
\r
40 read("\""); -- skip quote
\r
45 if ch == "\"" and not slash then break; end
\r
48 str = str:gsub("\\.", {["\\b"]="\b", ["\\d"]="\d", ["\\e"]="\e", ["\\f"]="\f", ["\\n"]="\n", ["\\r"]="\r", ["\\s"]="\s", ["\\t"]="\t", ["\\v"]="\v", ["\\\""]="\"", ["\\'"]="'", ["\\\\"]="\\"});
\r
51 local function readSpecialString()
\r
52 read("<"); read("<"); -- read <<
\r
54 if peek() == "\"" then
\r
55 local str = readString();
\r
56 elseif peek() ~= ">" then
\r
59 read(">"); read(">"); -- read >>
\r
62 local function readVar()
\r
64 while isVar(peek()) do
\r
69 local function readNumber()
\r
71 while isNumeric(peek()) do
\r
74 return tonumber(num);
\r
76 local readItem = nil;
\r
77 local function readTuple()
\r
79 read(); -- read { or [
\r
81 local item = readItem();
\r
82 if not item then break; end
\r
83 table.insert(t, item);
\r
85 read(); -- read } or ]
\r
88 readItem = function()
\r
90 if ch == nil then return nil end
\r
91 if ch == "{" or ch == "[" then
\r
93 elseif isAlpha(ch) then
\r
95 elseif isNumeric(ch) then
\r
96 return readNumber();
\r
97 elseif ch == "\"" then
\r
98 return readString();
\r
99 elseif ch == "<" then
\r
100 return readSpecialString();
\r
101 elseif isSpace(ch) or ch == "," or ch == "|" then
\r
105 --print("Unknown char: "..ch);
\r
109 local function readChunk()
\r
110 local x = readItem();
\r
111 if x then read("."); end
\r
114 local function readFile(filename)
\r
115 file = io.open(filename);
\r
116 if not file then error("File not found: "..filename); os.exit(0); end
\r
118 local x = readChunk();
\r
119 if not x and peek() then error("Invalid char: "..peek()); end
\r
126 function parseFile(file)
\r
127 return readFile(file);
\r