-- fe.e -- Front end - translates text into tokens, then into intermediate form -- Pete Eberlein -- ????13 Sep 2002 -- (if-expressions must short-circuit for this to work correctly) -- so you can ignore warnings: "call to test() might be short-circuited" include token.e include cg.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) data[1..2] = "--" end if while sequence(data) do text &= data data = gets(handle) end while close(handle) return text end function constant precedence = { {"and","or","xor"}, {"<",">","<=",">=","=","!="}, {"&"}, {"+","-"}, {"*","/"} } constant prec_table = { {AND, OR, XOR}, {LESS_THAN, GREATER_THAN, LESS_EQUALS, GREATER_EQUALS, EQUALS, NOT_EQUALS}, {CAT}, {ADD,SUB}, {MUL,DIV} } function expression(integer depth) sequence result if depth <= length(precedence) then result = expression(depth+1) while find(token, precedence[depth]) do result = {prec_table[depth][find(token, precedence[depth])], 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 = {CONST, last_token} elsif test(STRING) then result = {"string", last_token} elsif test(IDENTIFIER) then result = {1, last_token} if test("(") then result[1] = CALLFUNC -- 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] = VAR end if end if end if return result end function sequence routine_kind routine_kind = "" function statement_block() sequence result, stmt 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 if length(routine_kind) then syntax_error(last_token & " declaration cannot be nested inside a " & routine_kind & " declaration") end if 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 stmt = statement_block() expect(routine_kind) routine_kind = "" elsif test("constant") then while 1 do expect(IDENTIFIER) --puts(1, "declared constant: "&last_token&"\n") expect("=") stmt = expression(1) if not test(",") then exit end if end while elsif test("while") then stmt = {WHILE, expression(1)} expect("do") stmt &= statement_block() expect("while") elsif test("for") then expect(IDENTIFIER) stmt = {"for", last_token, 0, 0, 1} expect("=") stmt[3] = expression(1) expect("to") stmt[4] = expression(1) if test("by") then stmt[5] = expression(1) end if expect("do") stmt &= statement_block() expect("for") elsif test("if") then stmt = {IF, expression(1)} expect("then") stmt &= {{statement_block()}} while equal(last_token, "elsif") do stmt &= {{"elsif", expression(1)}} expect("then") stmt[length(stmt)] &= {statement_block()} end while if equal(last_token, "else") then stmt[length(stmt)] &= {statement_block()} end if expect("if") elsif test("exit") then stmt = {EXIT} elsif test("return") then stmt = {RETURN} if equal(routine_kind, "") then syntax_error("return must be inside a procedure or a function") elsif not equal(routine_kind, "procedure") then stmt &= {expression(1)} end if elsif test("end") or test("else") or test("elsif") then return result elsif test(IDENTIFIER) then stmt = {1, last_token} if test("(") then -- procedure call stmt[1] = CALLPROC if not test(")") then stmt &= {expression(1)} while test(",") do stmt &= {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 stmt[1] = ASSIGN if test("[") then -- subscripted assignment while 1 do stmt = {expression(1)} if test("..") then stmt &= {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 stmt &= {expression(1)} end if --smart_printc(result) end if elsif test("?") then stmt = {"?", expression(1)} else syntax_error("unknown command: "&token) end if result &= {stmt} end while return result end function token_init("if 1 then ? 1 ? 2 else ? 2 ? 3 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() smart_printc(statement_block())