fake_demand_epp.erl
来自「OTP是开放电信平台的简称」· ERL 代码 · 共 848 行 · 第 1/2 页
ERL
848 行
%% ``The contents of this file are subject to the Erlang Public License,%% Version 1.1, (the "License"); you may not use this file except in%% compliance with the License. You should have received a copy of the%% Erlang Public License along with this software. If not, it can be%% retrieved via the world wide web at http://www.erlang.org/.%% %% Software distributed under the License is distributed on an "AS IS"%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See%% the License for the specific language governing rights and limitations%% under the License.%% %% The Initial Developer of the Original Code is Ericsson Utvecklings AB.%% Portions created by Ericsson are Copyright 1999, Ericsson Utvecklings%% AB. All Rights Reserved.''%% %% $Id$%%-module(epp).%% An Erlang code preprocessor.-export([open/2,open/3,close/1,format_error/1]).-export([open_io/2,open_io/3]).-export([scan_erl_form/1,parse_erl_form/1,macro_defs/1]).-export([parse_file/3]).%% Epp state record.-record(epp, {file, %Current file line=1, %Current line number name="", %Current file name istk=[], %Ifdef stack sstk=[], %State stack macs=dict:new(), %Macros uses=dict:new() %Macro use structure }).%%% Note on representation: as tokens, both {var, Line, Name} and%%% {atom, Line, Name} can occur as macro identifiers. However, keeping%%% this distinction here is done for historical reasons only: previously,%%% ?FOO and ?'FOO' were not the same, but now they are. Removing the%%% distinction in the internal representation would simplify the code%%% a little.%% open(FileName, IncludePath)%% open(FileName, IncludePath, PreDefMacros)%% close(Epp)%% scan_erl_form(Epp)%% parse_erl_form(Epp)%% macro_defs(Epp)open(File, Path) -> open(File, Path, []).open(File, Path, Pdm) -> Self = self(), %The caller's pid Epp = spawn_link(fun () -> file_server(Self, File, Path, Pdm) end), wait_epp_reply(Epp).close(Epp) -> epp_request(Epp, close), wait_epp_reply(Epp).scan_erl_form(Epp) -> epp_request(Epp, scan_erl_form), wait_epp_reply(Epp).parse_erl_form(Epp) -> epp_request(Epp, scan_erl_form), case wait_epp_reply(Epp) of {ok,Toks} -> erl_parse:parse_form(Toks); Other -> Other end.macro_defs(Epp) -> epp_request(Epp, macro_defs), wait_epp_reply(Epp).%% format_error(ErrorDescriptor) -> String%% Return a string describing the error.format_error({bad,W}) -> io_lib:format("badly formed '~s'", [W]);format_error({call,What}) -> io_lib:format("illegal macro call '~s'",[What]);format_error({undefined,M}) -> io_lib:format("undefined macro '~w'", [M]);format_error({depth,What}) -> io_lib:format("~s too deep",[What]);format_error({mismatch,M}) -> io_lib:format("argument mismatch for macro '~w'", [M]);format_error({arg_error,M}) -> io_lib:format("badly formed argument for macro '~w'", [M]);format_error({redefine,M}) -> io_lib:format("redefining macro '~w'", [M]);format_error({circular,M}) -> io_lib:format("circular macro '~w'", [M]);format_error({include,W,F}) -> io_lib:format("can't find include ~s \"~s\"", [W,F]);format_error({illegal,How,What}) -> io_lib:format("~s '-~s'", [How,What]);format_error({'NYI',What}) -> io_lib:format("not yet implemented '~s'", [What]).%% parse_file(FileName, IncludePath, [PreDefMacro]) ->%% {ok,[Form]} | {error,OpenError}parse_file(Ifile, Path, Predefs) -> case open(Ifile, Path, Predefs) of {ok,Epp} -> Forms = parse_file(Epp), close(Epp), {ok,Forms}; {error,E} -> {error,E} end.%% parse_file(Epp) ->%% [Form]parse_file(Epp) -> case parse_erl_form(Epp) of {ok,Form} -> [Form|parse_file(Epp)]; {error,E} -> [{error,E}|parse_file(Epp)]; {eof,Line} -> [{eof,Line}] end.%% open_io(IoStream, IncludePath)%% open_io(IoStream, IncludePath, PredefMacros)open_io(Io, Path) -> open_io(Io, Path, []).open_io(Io, Path, Pdm) -> Self = self(), %The caller's pid Epp = spawn(fun () -> io_server(Self, Io, "iostream", Path, Pdm) end), wait_epp_reply(Epp).%% file_server(StarterPid, FileName, Path, PreDefMacros)%% io_server(StarterPid, IoStream, FileName, Path, PreDefMacros)file_server(Pid, Name, Path, Pdm) -> process_flag(trap_exit, true), case file:open(Name, read) of {ok,File} -> io_server(Pid, File, Name, Path, Pdm); {error,E} -> epp_reply(Pid, {error,E}) end.io_server(Pid, Io, Name, Path, Pdm) -> put(sys_path, Path), put(user_path, Path), Ms0 = predef_macros(Name), case user_predef(Pdm, Ms0) of {ok,Ms1} -> epp_reply(Pid, {ok,self()}), St = #epp{file=Io,name=Name,macs=Ms1}, From = wait_request(St), enter_file_reply(From, Name, 1), wait_req_scan(St); {error,E} -> epp_reply(Pid, {error,E}) end.%% predef_macros(FileName) -> Macrodict%% Initialise the macro dictionary with the default predefined macros,%% FILE, LINE, MODULE as undefined, MACHINE and MACHINE value.predef_macros(File) -> Ms0 = dict:new(), Ms1 = dict:store({atom,'FILE'}, {none,[{string,1,File}]}, Ms0), Ms2 = dict:store({atom,'LINE'}, {none,[{integer,1,1}]}, Ms1), Ms3 = dict:store({atom,'MODULE'}, undefined, Ms2), Ms31 = dict:store({atom,'MODULE_STRING'}, undefined, Ms3), Machine = list_to_atom(erlang:system_info(machine)), Ms4 = dict:store({atom,'MACHINE'}, {none,[{atom,1,Machine}]}, Ms31), dict:store({atom,Machine}, {none,[{atom,1,true}]}, Ms4).%% user_predef(PreDefMacros, Macros) ->%% {ok,MacroDict} | {error,E}%% Add the predefined macros to the macros dictionary. A macro without a%% value gets the value 'true'.user_predef([{M,Val}|Pdm], Ms) when atom(M) -> case dict:find({atom,M}, Ms) of {ok,Def} -> {error,{redefine,M}}; error -> Exp = erl_parse:tokens(erl_parse:abstract(Val)), user_predef(Pdm, dict:store({atom,M}, {none,Exp}, Ms)) end;user_predef([M|Pdm], Ms) when atom(M) -> case dict:find({atom,M}, Ms) of {ok,Def} -> {error,{redefine,M}}; error -> user_predef(Pdm, dict:store({atom,M}, {none,[{atom,1,true}]}, Ms)) end;user_predef([Md|Pdm], Ms) -> {error,{bad,Md}};user_predef([], Ms) -> {ok,Ms}.%% wait_request(EppState) -> RequestFrom%% wait_req_scan(EppState)%% wait_req_skip(EppState, SkipIstack)%% Handle requests, processing trivial requests directly. Either return%% requestor or scan/skip tokens.wait_request(St) -> receive {epp_request,From,scan_erl_form} -> From; {epp_request,From,macro_defs} -> epp_reply(From, dict:dict_to_list(St#epp.macs)), wait_request(St); {epp_request,From,close} -> epp_reply(From, ok), exit(normal); {'EXIT',_,R} -> exit(R); Other -> io:fwrite("Epp: unknown '~w'\n", [Other]), wait_request(St) end.wait_req_scan(St) -> From = wait_request(St), scan_toks(From, St).wait_req_skip(St, Sis) -> From = wait_request(St), skip_toks(From, St, Sis). %% enter_file(Path, FileName, IncludeLine, From, EppState)%% leave_file(From, EppState)%% Handle entering and leaving included files. Notify caller when the%% current file is changed. Note it is an error to exit a file if we are%% in a conditional. These functions never return.enter_file(Path, NewName, Li, From, St) when length(St#epp.sstk) >= 8 -> epp_reply(From, {error,{Li,epp,{depth,"include"}}}), wait_req_scan(St);enter_file(Path, NewName, Li, From, St) -> case file:path_open(Path, NewName, read) of {ok,NewF,Pname} -> wait_req_scan(enter_file(NewF, Pname, From, St)); {error,E} -> epp_reply(From, {error,{Li,epp,{include,file,NewName}}}), wait_req_scan(St) end.%% enter_file(File, FullName, From, EppState) -> EppState.%% Set epp to use this file and "enter" it.enter_file(NewF, Pname, From, St) -> enter_file_reply(From, Pname, 1), Ms = dict:store({atom,'FILE'}, {none,[{string,1,Pname}]}, St#epp.macs), #epp{file=NewF,name=Pname,sstk=[St|St#epp.sstk],macs=Ms}.enter_file_reply(From, Name, Line) -> Rep = {ok, [{'-',Line},{atom,Line,file},{'(',Line}, {string,Line,file_name(Name)},{',',Line}, {integer,Line,Line},{')',Line},{dot,Line}]}, epp_reply(From, Rep).%% Flatten filename to a string. Must be a valid filename.file_name([C | T]) when integer(C), C > 0, C =< 255 -> [C | file_name(T)];file_name([H|T]) -> file_name(H) ++ file_name(T);file_name([]) -> [];file_name(N) when atom(N) -> atom_to_list(N).leave_file(From, St) -> case St#epp.istk of [I|Cis] -> epp_reply(From, {error,{St#epp.line,epp, {illegal,"unterminated",I}}}), leave_file(wait_request(St),St#epp{istk=Cis}); [] -> case St#epp.sstk of [OldSt|Sts] -> file:close(St#epp.file), enter_file_reply(From, OldSt#epp.name, OldSt#epp.line), Ms = dict:store({atom,'FILE'}, {none, [{string,OldSt#epp.line,OldSt#epp.name}]}, St#epp.macs), wait_req_scan(OldSt#epp{sstk=Sts,macs=Ms}); [] -> epp_reply(From, {eof,St#epp.line}), wait_req_scan(St) end end.%% scan_toks(From, EppState)%% scan_toks(Tokens, From, EppState)scan_toks(From, St) -> case io:scan_erl_form(St#epp.file, '', St#epp.line) of {ok,Toks,Cl} -> scan_toks(Toks, From, St#epp{line=Cl}); {error,E,Cl} -> epp_reply(From, {error,E}), wait_req_scan(St#epp{line=Cl}); {eof,Cl} -> leave_file(From, St#epp{line=Cl}); {error,E} -> epp_reply(From, {error,E}), true %This serious, just exit! end.scan_toks([{'-',Lh},{atom,Ld,define}|Toks], From, St) -> scan_define(Toks, Ld, From, St);scan_toks([{'-',Lh},{atom,Ld,undef}|Toks], From, St) -> scan_undef(Toks, Ld, From, St);scan_toks([{'-',Lh},{atom,Li,include}|Toks], From, St) -> scan_include(Toks, Li, From, St);scan_toks([{'-',Lh},{atom,Li,include_lib}|Toks], From, St) -> scan_include_lib(Toks, Li, From, St);scan_toks([{'-',Lh},{atom,Li,ifdef}|Toks], From, St) -> scan_ifdef(Toks, Li, From, St);scan_toks([{'-',Lh},{atom,Li,ifndef}|Toks], From, St) -> scan_ifndef(Toks, Li, From, St);scan_toks([{'-',Lh},{atom,Le,else}|Toks], From, St) -> scan_else(Toks, Le, From, St);scan_toks([{'-',Lh},{atom,Le,'if'}|Toks], From, St) -> scan_if(Toks, Le, From, St);scan_toks([{'-',Lh},{atom,Le,elif}|Toks], From, St) -> scan_elif(Toks, Le, From, St);scan_toks([{'-',Lh},{atom,Le,endif}|Toks], From, St) -> scan_endif(Toks, Le, From, St);scan_toks(Toks0, From, St) -> case catch expand_macros(Toks0, {St#epp.macs, St#epp.uses}) of Toks1 when list(Toks1) -> epp_reply(From, {ok,Toks1}), wait_req_scan(St#epp{macs=scan_module(Toks1, St#epp.macs)}); {error,ErrL,What} -> epp_reply(From, {error,{ErrL,epp,What}}), wait_req_scan(St) end.scan_module([{'-',_Lh},{atom,_Lm,module},{'(',_Ll}|Ts], Ms) -> scan_module_1(Ts,[],Ms);scan_module(_Ts, Ms) -> Ms.scan_module_1([{atom,Ln,A},{')',_Lr}|_Ts], As, Ms) -> Mod = lists:concat(lists:reverse([A|As])), Ms1 = dict:store({atom,'MODULE'}, {none,[{atom,Ln,list_to_atom(Mod)}]}, Ms), dict:store({atom,'MODULE_STRING'}, {none,[{string,Ln,Mod}]},Ms1);scan_module_1([{atom,_Ln,A},{'.',_Lr}|Ts], As, Ms) -> scan_module_1(Ts, [".",A|As], Ms);scan_module_1([{'.',_Lr}|Ts], As, Ms) -> scan_module_1(Ts, As, Ms);scan_module_1(_Ts, _As, Ms) -> Ms.%% scan_define(Tokens, DefineLine, From, EppState)scan_define([{'(',Lp},{atom,Lm,M},{',',Lc}|Toks], Ld, From, St) -> case dict:find({atom,M}, St#epp.macs) of {ok,Def} -> epp_reply(From, {error,{Lm,epp,{redefine,M}}}), wait_req_scan(St); error -> scan_define_cont(From, St, {atom, M}, {none,macro_expansion(Toks)}) end;scan_define([{'(',Lp},{atom,Lm,M},{'(',Lc}|Toks], Ld, From, St) -> case dict:find({atom,M}, St#epp.macs) of {ok,Def} -> epp_reply(From, {error,{Lm,epp,{redefine,M}}}), wait_req_scan(St); error -> case catch macro_pars(Toks, []) of {ok, {As, Me}} -> scan_define_cont(From, St, {atom, M}, {As, Me}); _ -> epp_reply(From, {error,{Ld,epp,{bad,define}}}), wait_req_scan(St) end end;scan_define([{'(',Lp},{var,Lm,M},{',',Lc}|Toks], Ld, From, St) -> case dict:find({atom,M}, St#epp.macs) of {ok,Def} -> epp_reply(From, {error,{Lm,epp,{redefine,M}}}), wait_req_scan(St); error -> scan_define_cont(From, St, {atom, M}, {none,macro_expansion(Toks)}) end;scan_define([{'(',Lp},{var,Lm,M},{'(',Lc}|Toks], Ld, From, St) -> case dict:find({atom,M}, St#epp.macs) of {ok,Def} -> epp_reply(From, {error,{Lm,epp,{redefine,M}}}), wait_req_scan(St); error -> case catch macro_pars(Toks, []) of {ok, {As, Me}} -> scan_define_cont(From, St, {atom, M}, {As, Me}); _ -> epp_reply(From, {error,{Ld,epp,{bad,define}}}), wait_req_scan(St) end end;scan_define(Toks, Ld, From, St) -> epp_reply(From, {error,{Ld,epp,{bad,define}}}), wait_req_scan(St).%%% Detection of circular macro expansions (which would either keep%%% the compiler looping forever, or run out of memory):
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?