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 + -
显示快捷键?