-- if expressions must short-circuit --without warning include graphics.e ? text_rows(50) include smart.e with trace include token.e function readfile(sequence filename, ) sequence text integer handle object data text="" handle = open(filename, "r") data = gets(handle) if sequence (data) and match("#!",data)=1 then data = gets(handle) end if while sequence(data) do text &= data data = gets(handle) end while close(handle) return text end function --? 1.1e1 --smart_printc(tokenize(readfile("cv.ex"))) --smart_printc(tokenize("include c:\\test.e ...")) --smart_printc(tokenize(">= >< <= += ")) --smart_printc(getenv("EUDIR")&"\\demo\\sanity.ex") --trace(1) --smart_printc(tokenize("'")) --smart_printc(tokenize("1.5e\n")) --smart_printc(tokenize("1.1e5\n\"ffff\nxx")) --abort(1) with trace constant precedence = { {"and","or","xor"}, {"<",">","<=",">=","=","!="}, {"&"}, {"+","-"}, {"*","/"} } function expression(integer depth) sequence result if depth <= length(precedence) then result = expression(depth+1) while find(token, precedence[depth]) do result = {token, result, 3} next_token() result[3] = expression(depth+1) end while else if test("(") then result = expression(1) expect(")") elsif test("{") then result = {"{"} if not test("}") then result &= {expression(1)} while test(",") do result &= {expression(1)} end while expect("}") end if elsif test("not") then result = {"not", expression(depth)} elsif test("+") then result = expression(depth) elsif test("-") then result = {"neg", expression(depth)} elsif test(NUMERIC) then result = {"numeric", last_token} elsif test(STRING) then result = {"string", last_token} elsif test(IDENTIFIER) then result = {1, last_token} if test("(") then result[1] = "function_call" -- function call if not test(")") then result &= {expression(1)} while test(",") do result &= {expression(1)} end while expect(")") end if elsif test("[") then result[1] = "subscripted_variable" -- variable subscript while 1 do result &= {expression(1)} if test("..") then result &= {expression(1)} expect("]") exit end if expect("]") if not test("[") then exit end if end while else result[1] = "variable" end if end if end if return result end function sequence routine_kind routine_kind = "" function statement_block() sequence result result = "" while token_type do if test("global") then end if if test("include") then expect(IDENTIFIER) expect(".") expect(IDENTIFIER) elsif test("with") or test("without") then if test("profile_time") then expect(NUMERIC) elsif not test(NUMERIC) then if not test(IDENTIFIER) then syntax_error("unknown with/without option") end if end if elsif test("function") or test("procedure") or test("type") then routine_kind = last_token expect(IDENTIFIER) expect("(") while not test(")") do expect(IDENTIFIER) expect(IDENTIFIER) if not test(",") then if not equal(token, ")") then syntax_error("badly-formed list of parameters - expected ',' or ')'") end if end if end while result = statement_block() expect(routine_kind) routine_kind = "" elsif test("constant") then while 1 do expect(IDENTIFIER) --puts(1, "declared constant: "&last_token&"\n") expect("=") result = expression(1) if not test(",") then exit end if end while elsif test("while") then result = {"while", expression(1)} expect("do") result &= statement_block() expect("while") elsif test("for") then expect(IDENTIFIER) result = {"for", last_token, 0, 0, 1} expect("=") result[3] = expression(1) expect("to") result[4] = expression(1) if test("by") then result[5] = expression(1) end if expect("do") result &= statement_block() expect("for") elsif test("if") then result = {"if", expression(1)} expect("then") result &= {statement_block()} while equal(last_token, "elsif") do result &= {{"elsif", expression(1)}} expect("then") result[length(result)] &= {statement_block()} end while if equal(last_token, "else") then result &= {{"else"}} result[length(result)] &= {statement_block()} end if expect("if") elsif test("exit") then result = {"exit"} elsif test("return") then result = {"return"} if equal(routine_kind, "") then syntax_error("return must be inside a procedure or a function") elsif not equal(routine_kind, "procedure") then result &= {expression(1)} end if elsif test("end") or test("else") or test("elsif") then return result elsif test(IDENTIFIER) then result = {1, last_token} if test("(") then -- procedure call result[1] = "procedure_call" if not test(")") then result &= {expression(1)} while test(",") do result &= {expression(1)} end while expect(")") end if elsif test(IDENTIFIER) then -- declaration while 1 do --printf(1,"declared: %s\n", {last_token}) if not test(",") then exit elsif not test(IDENTIFIER) then syntax_error("a variable name is expected here") end if end while else result[1] = "assign" if test("[") then -- subscripted assignment while 1 do result = {expression(1)} if test("..") then result &= {expression(1)} expect("]") exit end if expect("]") if not test("[") then exit end if end while end if if test("=") or test("&=") or test("+=") or test("-=") or test("*=") or test("/=") then result &= {expression(1)} end if --smart_printc(result) end if elsif test("?") then result = {"?", expression(1)} else syntax_error("unknown command: "&token) end if end while return result end function --token_init(readfile(getenv("EUDIR")&"\\demo\\sanity.ex")) --token_init(readfile("cv.ex")) --ignored_tokens = {WHITESPACE, COMMENT} --token_echo = 1 --next_token() --smart_printc(statement_block()) token_init("if 1 then ? 1 else ? 2 end if") ignored_tokens = {WHITESPACE, COMMENT} token_echo = 0 next_token() smart_printc(statement_block()) token_init("? 1+2\n") ignored_tokens = {WHITESPACE, COMMENT} token_echo = 0 next_token() function nop_(object a) return a end function function or_(object a, object b) return a or b end function function and_(object a, object b) return a and b end function function xor_(object a, object b) return a xor b end function function add_(object a, object b) return a + b end function function sub_(object a, object b) return a - b end function function mul_(object a, object b) return a * b end function function div_(object a, object b) return a / b end function function gt_(object a, object b) return a > b end function function lt_(object a, object b) return a < b end function function gte_(object a, object b) return a >= b end function function lte_(object a, object b) return a <= b end function function eq_(object a, object b) return a = b end function function neq_(object a, object b) return a != b end function function cat_(object a, object b) return a & b end function function neg_(object a) return -a end function function not_(object a) return not a end function procedure qprint(object a) ? a end procedure constant ids = { routine_id("nop_"), routine_id("or_"), routine_id("and_"), routine_id("xor_"), routine_id("add_"), routine_id("sub_"), routine_id("mul_"), routine_id("div_"), routine_id("gt_"), routine_id("lt_"), routine_id("gte_"), routine_id("lte_"), routine_id("eq_"), routine_id("neq_"), routine_id("cat_"), routine_id("neg_"), routine_id("not_"), routine_id("qprint")} constant ops = { "", "or","and","xor", "+","-","*", "/",">","<", ">=","<=","=", "!=","&","neg", "not", "?"} include get.e function generate_code(sequence code) integer id id = find(code[1], ops) if id then code[1] = ids[id] for i = 2 to length(code) do code[i] = generate_code(code[i]) end for elsif equal(code[1], "numeric") then code = value(code[2]) end if return code end function function fun_code(sequence code) for i = 2 to length(code) do if code[i][1] then code[i] = fun_code(code[i]) else code[i] = code[i][2] end if end for return call_func(code[1], code[2..length(code)]) end function procedure run_code(sequence code) for i = 2 to length(code) do if code[i][1] then code[i] = fun_code(code[i]) else code[i] = code[i][2] end if end for call_proc(code[1], code[2..length(code)]) end procedure --run_code(generate_code({"?",{"+",{"numeric","1"},{"numeric","2"}}})) run_code(generate_code(statement_block()))