ictype.erl
来自「OTP是开放电信平台的简称」· ERL 代码 · 共 1,412 行 · 第 1/3 页
ERL
1,412 行
?STDDBG, tktab_add(G, S, N, X), X#module{body=check_list(G, S, [ic_forms:get_id2(X) | N], ic_forms:get_body(X))};check(G, S, N, X) when record(X, typedef) -> ?STDDBG, TKbase = tk(G, S, N, X), X#typedef{tk=TKbase};check(_G, _S, _N, X) -> ?DBG(" dbg: ~p~n", [element(1,X)]), X.handle_preproc(G, _N, line_nr, X) -> ic_genobj:set_idlfile(G, ic_forms:get_id2(X));handle_preproc(_G, _N, _C, _X) -> ok.%%--------------------------------------------------------------------%%%% TK calculation%%%%--------------------------------------------------------------------tk(G, S, N, X) when record(X, union) -> N2 = [ic_forms:get_id2(X) | N], DisrcTK = tk(G, S, N, ic_forms:get_type(X)), case check_switch_tk(G, S, N, X, DisrcTK) of true -> do_special_enum(G, S, N2, ic_forms:get_type(X)), BodyTK = lists:reverse( tk_caselist(G, S, N2, DisrcTK, ic_forms:get_body(X))), tktab_add(G, S, N, X, {tk_union, ictk:get_IR_ID(G, N, X), ic_forms:get_id2(X), DisrcTK, default_count(ic_forms:get_body(X)), BodyTK}); false -> tk_void end;tk(G, S, N, X) when record(X, enum) -> N2 = [ic_forms:get_id2(X) | N], tktab_add(G, S, N, X, {tk_enum, ictk:get_IR_ID(G, N, X), ic_forms:get_id2(X), enum_body(G, S, N2, ic_forms:get_body(X))});%% Note that the TK returned from this function is the base TK. It%% must be modified for each of the identifiers in the idlist (for%% array reasons).tk(G, S, N, X) when record(X, typedef) -> case X of %% Special case only for term and java backend ! {typedef,{any,_},[{'<identifier>',_,"term"}],undefined} -> case ic_options:get_opt(G, be) of java -> tktab_add(G, S, N, X, tk_term), tk_term; _ -> TK = tk(G, S, N, ic_forms:get_body(X)), lists:foreach(fun(Id) -> tktab_add(G, S, N, #id_of{id=Id, type=X}, maybe_array(G, S, N, Id, TK)) end, X#typedef.id), TK end; _ -> TK = tk(G, S, N, ic_forms:get_body(X)), lists:foreach(fun(Id) -> tktab_add(G, S, N, #id_of{id=Id, type=X}, maybe_array(G, S, N, Id, TK)) end, X#typedef.id), TK end;tk(G, S, N, X) when record(X, struct) -> N2 = [ic_forms:get_id2(X) | N], tktab_add(G, S, N, X, {tk_struct, ictk:get_IR_ID(G, N, X), ic_forms:get_id2(X), tk_memberlist(G, S, N2, ic_forms:get_body(X))});tk(G, S, N, X) when record(X, except) -> N2 = [ic_forms:get_id2(X) | N], tktab_add(G, S, N, X, {tk_except, ictk:get_IR_ID(G, N, X), ic_forms:get_id2(X), tk_memberlist(G, S, N2, ic_forms:get_body(X))});tk(G, S, N, X) -> tk_base(G, S, N, X).tk_base(G, S, N, X) when record(X, sequence) -> {tk_sequence, tk(G, S, N, X#sequence.type), len_eval(G, S, N, X#sequence.length)};tk_base(G, S, N, X) when record(X, string) -> {tk_string, len_eval(G, S, N, X#string.length)};tk_base(G, S, N, X) when record(X, wstring) -> %% WSTRING {tk_wstring, len_eval(G, S, N, X#wstring.length)};%% Fixed constants can be declared as:%% (1) const fixed pi = 3.14D; or%% (2) typedef fixed<3,2> f32;%% const f32 pi = 3.14D;tk_base(G, S, N, X) when record(X, fixed) -> %% Case 2 {tk_fixed, len_eval(G, S, N, X#fixed.digits), len_eval(G, S, N, X#fixed.scale)};tk_base(_G, _S, _N, {fixed, _}) -> %% Case 1 tk_fixed;%% Special case, here CORBA::TypeCode is built in %% ONLY when erl_corba is the backend of choice tk_base(G, S, N, {scoped_id,V1,V2,["TypeCode","CORBA"]}) -> case ic_options:get_opt(G, be) of false -> tk_TypeCode; erl_corba -> tk_TypeCode; erl_template -> tk_TypeCode; _ -> case scoped_lookup(G, S, N, {scoped_id,V1,V2,["TypeCode","CORBA"]}) of T when element(1, T) == error -> T; T when tuple(T) -> element(3, T) end end;tk_base(G, S, N, X) when element(1, X) == scoped_id -> case scoped_lookup(G, S, N, X) of T when element(1, T) == error -> T; T when tuple(T) -> element(3, T) end;tk_base(_G, _S, _N, {long, _}) -> tk_long;tk_base(_G, _S, _N, {'long long', _}) -> tk_longlong; %% LLONGtk_base(_G, _S, _N, {short, _}) -> tk_short;tk_base(_G, _S, _N, {'unsigned', {short, _}}) -> tk_ushort;tk_base(_G, _S, _N, {'unsigned', {long, _}}) -> tk_ulong;tk_base(_G, _S, _N, {'unsigned', {'long long', _}})-> tk_ulonglong; %% ULLONGtk_base(_G, _S, _N, {float, _}) -> tk_float;tk_base(_G, _S, _N, {double, _}) -> tk_double;tk_base(_G, _S, _N, {boolean, _}) -> tk_boolean;tk_base(_G, _S, _N, {char, _}) -> tk_char;tk_base(_G, _S, _N, {wchar, _}) -> tk_wchar; %% WCHARtk_base(_G, _S, _N, {octet, _}) -> tk_octet;tk_base(_G, _S, _N, {null, _}) -> tk_null;tk_base(_G, _S, _N, {void, _}) -> tk_void;tk_base(_G, _S, _N, {any, _}) -> tk_any;tk_base(_G, _S, _N, {'Object', _}) -> {tk_objref, "", "Object"}.%%--------------------------------------------------------------------%%%% Special handling of idlists. Note that the recursion case is given%% as accumulator to foldr. Idlists are those lists of identifiers%% that share the same definition, i.e. multiple cases, multiple type%% declarations, multiple member names.%%tk_memberlist(G, S, N, [X | Xs]) -> BaseTK = tk(G, S, N, ic_forms:get_type(X)), XX = #id_of{type=X}, lists:foldr(fun(Id, Acc) -> [tk_member(G, S, N, XX#id_of{id=Id}, BaseTK) | Acc] end, tk_memberlist(G, S, N, Xs), ic_forms:get_idlist(X));tk_memberlist(_G, _S, _N, []) -> [].%% same as above but for case dclstk_caselist(G, S, N, DiscrTK, Xs) -> lists:foldl(fun(Case, Acc) -> BaseTK = tk(G, S, N, ic_forms:get_type(Case)), %% tktab_add for the uniqueness check of the declarator tktab_add(G, S, N, Case), lists:foldl(fun(Id, Acc2) -> case tk_case(G, S, N, Case, BaseTK, DiscrTK, Id) of Err when element(1, Err)==error -> Acc2; TK -> unique_add_case_label(G, S, N, Id, TK, Acc2) end end, Acc, ic_forms:get_idlist(Case)) end, [], Xs).%% Handling of the things that can be in an idlist or caselisttk_member(G, S, N, X, BaseTK) -> tktab_add(G, S, N, X, {ic_forms:get_id2(X), maybe_array(G, S, N, X#id_of.id, BaseTK)}).get_case_id_and_check(G, _S, _N, _X, ScopedId) -> case ic_symtab:scoped_id_is_global(ScopedId) of true -> ic_error:error(G, {bad_scope_enum_case, ScopedId}); false -> ok end, case ic_symtab:scoped_id_strip(ScopedId) of [Id] -> Id; _List -> ic_error:error(G, {bad_scope_enum_case, ScopedId}), "" end.tk_case(G, S, N, X, BaseTK, DiscrTK, Id) -> case case_eval(G, S, N, DiscrTK, Id) of Err when element(1, Err) == error -> Err; Val -> case iceval:check_tk(G, DiscrTK, Val) of true -> {iceval:get_val(Val), ic_forms:get_id2(X), maybe_array(G, S, N, X#case_dcl.id, BaseTK)}; false -> ic_error:error(G, {bad_case_type, DiscrTK, X, iceval:get_val(Val)}) end end.tktab_add(G, S, N, X) -> tktab_add_id(G, S, N, X, ic_forms:get_id2(X), nil, nil).tktab_add(G, S, N, X, TK) -> tktab_add_id(G, S, N, X, ic_forms:get_id2(X), TK, nil).tktab_add(G, S, N, X, TK, Aux) -> tktab_add_id(G, S, N, X, ic_forms:get_id2(X), TK, Aux).tktab_add_id(G, S, N, X, Id, TK, Aux) when record(X,enumerator) -> %% Check if the "scl" flag is set to true %% if so, allow old semantics ( errornous ) %% Warning, this is for compatibility reasons only. Name = case ic_options:get_opt(G, scl) of true -> [Id | N]; false -> [Id | tl(N)] end, UName = mk_uppercase(Name), case ets:lookup(S, Name) of [_] -> ic_error:error(G, {multiply_defined, X}); [] -> case ets:lookup(S, UName) of [] -> ok; [_] -> ic_error:error(G, {illegal_spelling, X}) end end, ets:insert(S, {Name, element(1, get_beef(X)), TK, Aux}), if UName =/= Name -> ets:insert(S, {UName, spellcheck}); true -> true end, TK;%%%% Fixes the multiple file module definition check %% but ONLY for Corba backend%% tktab_add_id(G, S, N, X, Id, TK, Aux) when record(X,module) -> case ic_options:get_opt(G, be) of erl_template -> Name = [Id | N], UName = mk_uppercase(Name), ets:insert(S, {Name, element(1, get_beef(X)), TK, Aux}), if UName =/= Name -> ets:insert(S, {UName, spellcheck}); true -> true end, TK; erl_corba -> Name = [Id | N], UName = mk_uppercase(Name), ets:insert(S, {Name, element(1, get_beef(X)), TK, Aux}), if UName =/= Name -> ets:insert(S, {UName, spellcheck}); true -> true end, TK; false -> %% default == erl_corba Name = [Id | N], UName = mk_uppercase(Name), ets:insert(S, {Name, element(1, get_beef(X)), TK, Aux}), if UName =/= Name -> ets:insert(S, {UName, spellcheck}); true -> true end, TK; java -> Name = [Id | N], UName = mk_uppercase(Name), ets:insert(S, {Name, element(1, get_beef(X)), TK, Aux}), if UName =/= Name -> ets:insert(S, {UName, spellcheck}); true -> true end, TK; erl_genserv -> Name = [Id | N], UName = mk_uppercase(Name), ets:insert(S, {Name, element(1, get_beef(X)), TK, Aux}), if UName =/= Name -> ets:insert(S, {UName, spellcheck}); true -> true end, TK; erl_plain -> Name = [Id | N], UName = mk_uppercase(Name), ets:insert(S, {Name, element(1, get_beef(X)), TK, Aux}), if UName =/= Name -> ets:insert(S, {UName, spellcheck}); true -> true end, TK; _Be -> Name = [Id | N], UName = mk_uppercase(Name), case ets:lookup(S, Name) of [_] -> ic_error:error(G, {multiply_defined, X}); [] -> case ets:lookup(S, UName) of [] -> ok; [_] -> ic_error:error(G, {illegal_spelling, X}) end end, ets:insert(S, {Name, element(1, get_beef(X)), TK, Aux}), if UName =/= Name -> ets:insert(S, {UName, spellcheck}); true -> true end, TK end;tktab_add_id(G, S, N, X, Id, TK, Aux) -> Name = [Id | N], UName = mk_uppercase(Name), case ets:lookup(S, Name) of [{_, forward, _, _}] when record(X, interface) -> ok; [XX] when record(X, forward), element(2, XX)==interface -> ok; [_] -> ic_error:error(G, {multiply_defined, X}); [] -> case ets:lookup(S, UName) of [] -> ok; [_] -> ic_error:error(G, {illegal_spelling, X}) end end, ets:insert(S, {Name, element(1, get_beef(X)), TK, Aux}), if UName =/= Name -> ets:insert(S, {UName, spellcheck}); true -> true end, TK.%%--------------------------------------------------------------------%% enum_body%%%% Special because ids are treated different than usual.%%enum_body(G, S, N, [Enum | EnumList]) -> tktab_add(G, S, N, Enum), %%%, enum_val, Enum), %% tktab_add(G, S, N, X, TK, V), [ic_forms:get_id2(Enum) | enum_body(G, S, N, EnumList)];enum_body(_G, _S, _N, []) -> [].%%--------------------------------------------------------------------%% mk_array%%%% Multi dimensional arrays are written as nested tk_array%%mk_array(G, S, N, [Sz | Szs], TK) -> case iceval:eval_const(G, S, N, positive_int, Sz) of Err when element(1, Err) == error -> TK; Val -> {tk_array, mk_array(G, S, N, Szs, TK), iceval:get_val(Val)} end;mk_array(_G, _S, _N, [], TK) -> TK.%%--------------------------------------------------------------------%% len_eval%%%% Evaluates the length, which in case it has been left out is a%% plain 0 (zero)%%len_eval(_G, _S, _N, 0) -> 0;len_eval(G, S, N, X) -> %%iceval:eval_const(G, S, N, positive_int, X). case iceval:eval_const(G, S, N, positive_int, X) of Err when element(1, Err) == error -> 0; Val -> iceval:get_val(Val) end.%%--------------------------------------------------------------------%% case_eval%%%% Evaluates the case label.%%case_eval(G, S, N, DiscrTK, X) when element(1, DiscrTK) == tk_enum, element(1, X) == scoped_id -> {tk_enum, _, _, Cases} = DiscrTK, Id = get_case_id_and_check(G, S, N, X, X), %%io:format("Matching: ~p to ~p~n", [Id, Cases]), case lists:member(Id, Cases) of true -> {enum_id, Id}; false -> iceval:mk_val(scoped_lookup(G, S, N, X)) % Will generate error end;case_eval(G, S, N, DiscrTK, X) -> iceval:eval_e(G, S, N, DiscrTK, X).%% The enum declarator is in the union scope.do_special_enum(G, S, N, X) when record(X, enum) -> tktab_add(G, S, N, #id_of{id=X#enum.id, type=X});do_special_enum(_G, _S, _N, _X) -> ok.unique_add_case_label(G, _S, _N, Id, TK, TKList) ->%%%io:format("check_case_labels: TK:~p TKLIST:~p ~n", [TK, TKList]), if element(1, TK) == error -> TKList; true -> case lists:keysearch(element(1, TK), 1, TKList) of {value, _} -> ic_error:error(G, {multiple_cases, Id}), TKList; false -> [TK | TKList] end end.%%--------------------------------------------------------------------%% default_count%%%% Returns the position of the default case.%%%% Modified for OTP-2007%%default_count(Xs) -> default_count2(Xs, 0).default_count2([X | Xs], N) -> default_count3(X#case_dcl.label, Xs, N);default_count2([], _) -> -1.default_count3([{default, _} | _Ys], _Xs, N) -> N;default_count3([_ | Ys], Xs, N) -> default_count3(Ys, Xs, N+1);default_count3([], Xs, N) -> default_count2(Xs, N).%%%% Type checks.%%%% Check constant type references (only for the scoped id case, others%% are caught by the BNF)%%check_const_tk(_G, _S, _N, _X, tk_long) -> true;check_const_tk(_G, _S, _N, _X, tk_longlong) -> true; %% LLONGcheck_const_tk(_G, _S, _N, _X, tk_short) -> true;check_const_tk(_G, _S, _N, _X, tk_ushort) -> true;check_const_tk(_G, _S, _N, _X, tk_ulong) -> true; check_const_tk(_G, _S, _N, _X, tk_ulonglong) -> true; %% ULLONGcheck_const_tk(_G, _S, _N, _X, tk_float) -> true;check_const_tk(_G, _S, _N, _X, tk_double) -> true;check_const_tk(_G, _S, _N, _X, tk_boolean) -> true;check_const_tk(_G, _S, _N, _X, tk_char) -> true;check_const_tk(_G, _S, _N, _X, tk_wchar) -> true; %% WCHARcheck_const_tk(_G, _S, _N, _X, tk_octet) -> true;check_const_tk(_G, _S, _N, _X, {tk_string, _Len}) -> true;check_const_tk(_G, _S, _N, _X, {tk_wstring, _Len}) -> true; %% WSTRINGcheck_const_tk(_G, _S, _N, _X, tk_fixed) -> true;check_const_tk(_G, _S, _N, _X, {tk_fixed, _Digits, _Scale}) -> true;check_const_tk(G, _S, _N, X, TK) -> ic_error:error(G, {illegal_const_t, X, TK}).check_switch_tk(_G, _S, _N, _X, tk_long) -> true;
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?