1%% 2%% %CopyrightBegin% 3%% 4%% Copyright Ericsson AB 1997-2016. All Rights Reserved. 5%% 6%% Licensed under the Apache License, Version 2.0 (the "License"); 7%% you may not use this file except in compliance with the License. 8%% You may obtain a copy of the License at 9%% 10%% http://www.apache.org/licenses/LICENSE-2.0 11%% 12%% Unless required by applicable law or agreed to in writing, software 13%% distributed under the License is distributed on an "AS IS" BASIS, 14%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15%% See the License for the specific language governing permissions and 16%% limitations under the License. 17%% 18%% %CopyrightEnd% 19%% 20%% 21-module(ic). 22 23 24-export([sgen/1, gen/1, gen/2, help/0, compile/3]). 25 26 27%%------------------------------------------------------------ 28%% 29%% Internal stuff 30%% 31%%------------------------------------------------------------ 32 33-export([filter_params/2, handle_preproc/4, do_gen/4]). 34 35-import(lists, [foldr/3]). 36 37 38-include("icforms.hrl"). 39-include("ic.hrl"). 40 41-include_lib("stdlib/include/erl_compile.hrl"). 42 43-export([make_erl_options/1]). % For erlc 44 45-export([main/3, do_scan/1, do_parse/2, do_type/2]). 46 47 48%%------------------------------------------------------------ 49%% 50%% Entry point 51%% 52%%------------------------------------------------------------ 53 54%% compile(AbsFileName, Outfile, Options) 55%% Compile entry point for erl_compile. 56 57compile(File, _OutFile, Options) -> 58 case gen(File, make_erl_options(Options)) of 59 ok -> ok; 60 Other -> Other 61 end. 62 63 64%% Entry for the -s switch 65sgen(ArgList) -> 66%%% io:format("sgen called w ~p~n", [ArgList]), 67 apply(?MODULE, gen, ArgList). 68 69 70gen(File) -> 71 gen(File, []). 72 73gen(File, Opts) -> 74 G = ic_genobj:new(Opts), 75 IdlFile = ic_file:add_dot_idl(File), 76 case ic_options:get_opt(G, show_opts) of 77 true -> 78 io:format("Opts: ~p~n", [ic_options:which_opts(G)]); 79 _ -> ok 80 end, 81 ic_genobj:set_idlfile(G, IdlFile), 82 case catch gen2(G, File, Opts) of 83 {_, {'EXIT', R}} -> 84 ic_genobj:free_table_space(G), %% Free space for all ETS tables 85 io:format("Fatal error : ~p~n",[R]), 86 error; 87 {_, {'EXIT', _, R}} -> 88 ic_genobj:free_table_space(G), %% Free space for all ETS tables 89 io:format("Fatal error : ~p~n",[R]), 90 error; 91 {'EXIT', R} -> 92 ic_genobj:free_table_space(G), %% Free space for all ETS tables 93 io:format("Fatal error : ~p~n",[R]), 94 error; 95 {'EXIT', _, R} -> 96 ic_genobj:free_table_space(G), %% Free space for all ETS tables 97 io:format("Fatal error : ~p~n",[R]), 98 error; 99 %% In this case, the pragma registration 100 %% found errors so this should return error. 101 error -> 102 ic_genobj:free_table_space(G), %% Free space for all ETS tables 103 error; 104 _ -> 105 X = ic_error:return(G), 106 ic_genobj:free_table_space(G), %% Free space for all ETS tables 107 X 108 end. 109 110 111gen2(G, File, Opts) -> 112 case ic_options:get_opt(G, time) of 113 true -> 114 time("TOTAL ", ic, main, [G, File, Opts]); 115 _ -> 116 case main(G, File, Opts) of 117 error -> 118 error; 119 _ -> 120 ok 121 end 122 end. 123 124 125 126do_gen(erl_corba, G, File, T) -> 127 ic_erlbe:do_gen(G, File, T); 128do_gen(erl_template, G, File, T) -> 129 ic_erl_template:do_gen(G, File, T); 130do_gen(erl_genserv, G, File, T) -> 131 ic_erlbe:do_gen(G, File, T); 132do_gen(c_genserv, G, File, T) -> 133 ic_cclient:do_gen(G, File, T); 134do_gen(noc, G, File, T) -> 135 ic_noc:do_gen(G, File, T); 136do_gen(erl_plain, G, File, T) -> 137 ic_plainbe:do_gen(G, File, T); 138do_gen(c_server, G, File, T) -> 139 ic_cserver:do_gen(G, File, T); 140do_gen(c_client, G, File, T) -> 141 ic_cclient:do_gen(G, File, T); 142%% Java backend 143do_gen(java, G, File, T) -> 144 ic_jbe:do_gen(G, File, T); 145%% No language choice 146do_gen(_,_,_,_) -> 147 ok. 148 149do_scan(G) -> 150 icscan:scan(G, ic_genobj:idlfile(G)). 151 152 153do_parse(G, Tokens) -> 154 case icparse:parse(Tokens) of 155 {ok, L} -> L; 156 X when element(1, X) == error -> 157 Err = element(2, X), 158 ic_error:fatal_error(G, {parse_error, element(1, Err), 159 element(3, Err)}); 160 X -> exit(X) 161 end. 162 163 164do_type(G, Form) -> 165 ictype:type_check(G, Form). 166 167time(STR,M,F,A) -> 168 case timer:tc(M, F, A) of 169 {_, {'EXIT', R}} -> exit(R); 170 {_, {'EXIT', _, R}} -> exit(R); 171 {_, _X} when element(1, _X)==error -> throw(_X); 172 {_T, _R} -> 173 io:format("Time for ~s: ~10.2f~n", [STR, _T/1000000]), 174 _R 175 end. 176 177 178 179%% Filters parameters so that only those with certain attributes are 180%% seen. The filter parameter is a list of attributes that will be 181%% seen, ex. [in] or [inout, out] 182filter_params(Filter, Params) -> 183 lists:filter(fun(P) -> 184 lists:member(get_param_attr(P#param.inout), Filter) end, 185 Params). 186 187 188%% Access primitive to get the attribute name (and discard the line 189%% number). 190get_param_attr({A, _N}) -> A. 191 192 193%% 194%% Fixing the preproc directives 195%% 196handle_preproc(G, _N, line_nr, X) -> 197 Id = ic_forms:get_id2(X), 198 Flags = X#preproc.aux, 199 case Flags of 200 [] -> ic_genobj:push_file(G, Id); 201 _ -> 202 foldr(fun({_, _, "1"}, Gprim) -> ic_genobj:push_file(Gprim, Id); 203 ({_, _, "2"}, Gprim) -> ic_genobj:pop_file(Gprim, Id); 204 ({_, _, "3"}, Gprim) -> ic_genobj:sys_file(Gprim, Id) end, 205 G, Flags) 206 end; 207handle_preproc(G, _N, _Other, _X) -> 208 G. 209 210 211 212%%------------------------------------------------------------ 213%% 214%% The help department 215%% 216%% 217%% 218%%------------------------------------------------------------ 219 220help() -> 221 io:format("No help available at the moment~n", []), 222 ok. 223 224print_version_str(G) -> 225 case {ic_options:get_opt(G, silent), ic_options:get_opt(G, silent2)} of 226 {true, _} -> ok; 227 {_, true} -> ok; 228 _ -> 229 io:format("Erlang IDL compiler version ~s~n", [?COMPILERVSN]) 230 end. 231 232 233 234%% 235%% Converts generic compiler options to specific options. 236%% 237%% Used by erlc 238%% 239 240make_erl_options(Opts) -> 241 242 %% This way of extracting will work even if the record passed 243 %% has more fields than known during compilation. 244 245 Includes1 = Opts#options.includes, 246 Defines = Opts#options.defines, 247 Outdir = Opts#options.outdir, 248 Warning = Opts#options.warning, 249 Verbose = Opts#options.verbose, 250 Specific = Opts#options.specific, 251 Optimize = Opts#options.optimize, 252 PreProc = 253 lists:flatten( 254 lists:map(fun(D) -> io_lib:format("-I\"~ts\" ", [ic_util:to_list(D)]) end, 255 Includes1)++ 256 lists:map( 257 fun ({Name, Value}) -> 258 io_lib:format("-D~s=~s ", [ic_util:to_list(Name), ic_util:to_list(Value)]); 259 (Name) -> 260 io_lib:format("-D~s ", [ic_util:to_list(Name)]) 261 end, 262 Defines)), 263 Options = 264 case Verbose of 265 true -> []; 266 false -> [] 267 end ++ 268 case Warning of 269 0 -> [nowarn]; 270 _ -> ['Wall'] 271 end ++ 272 case Optimize of 273 0 -> []; 274 _ -> [] 275 end, 276 277 Options++[{outdir, Outdir}, {preproc_flags, PreProc}]++Specific. 278 279 280%%% 281%%% NEW main, avoids memory fragmentation 282%%% 283main(G, File, _Opts) -> 284 print_version_str(G), 285 ?ifopt(G, time, io:format("File ~p compilation started : ~p/~p/~p ~p:~2.2.0p~n", 286 [ic_genobj:idlfile(G), 287 element(1,date()), 288 element(2, date()), 289 element(3, date()), 290 element(1, time()), 291 element(2, time())])), 292 293 case ic_options:get_opt(G, help) of 294 true -> help(); 295 296 _ -> 297 scanning(G, File) 298 end. 299 300 301 302scanning(G, File) -> 303 S = ?ifopt2(G, time, 304 time("input file scanning ", ic, do_scan, [G]), 305 ic:do_scan(G)), 306 ?ifopt2(G, tokens, io:format("TOKENS: ~p~n", [S]), 307 parsing(G, File, S)). 308 309parsing(G, File, S) -> 310 T = ?ifopt2(G, 311 time, 312 time("input file parsing ", ic, do_parse, [G,S]), 313 ic:do_parse(G,S)), 314 ?ifopt2(G, form, io:format("PARSE FORM: ~p~n", [T]), 315 pragma(G, File, T)). 316 317 318 319pragma(G, File, T) -> 320 case ?ifopt2(G, 321 time, 322 time("pragma registration ", ic_pragma, pragma_reg, [G,T]), 323 ic_pragma:pragma_reg(G,T)) of 324 %% All pragmas were successfully applied 325 {ok,Clean} -> 326 typing(G, File, Clean); 327 328 error -> 329 error 330 end. 331 332 333typing(G, File, Clean) -> 334 case catch ?ifopt2(G, 335 time, 336 time("type code appliance ", ic, do_type, [G,Clean]), 337 ic:do_type(G,Clean)) of 338 {'EXIT',Reason} -> 339 io:format("Error under type appliance : ~p~n",[Reason]), 340 error; 341 342 T2 -> 343 ?ifopt2(G, tform, io:format("TYPE FORM: ~p~n", [T2]), 344 generation(G, File, T2)) 345 end. 346 347 348 349generation(G, File, T2) -> 350 case ic_options:get_opt(G, multiple_be) of 351 false -> 352 single_generation(G, File, T2); 353 List -> 354 OutDir = 355 case ic_options:get_opt(G, outdir) of 356 false -> 357 []; 358 Dir -> 359 Dir 360 end, 361 362 case ic_options:get_opt(G, be) of 363 false -> 364 ok; 365 Be -> 366 %% Generate this first 367 ic_options:add_opt(G,[{outdir,OutDir++atom_to_list(Be)}],true), 368 single_generation(G, File, T2) 369 end, 370 multiple_generation(G, File, T2, OutDir, List) 371 end. 372 373multiple_generation(_G, _File, _T2, _RootDir, []) -> 374 ok; 375multiple_generation(G, File, T2, RootDir, [Be|Bes]) -> 376 ic_options:add_opt(G,[{outdir,RootDir++atom_to_list(Be)}],true), 377 ic_options:add_opt(G,[{be,Be}],true), 378 single_generation(G, File, T2), 379 380 case ic_error:get_error_count(G) of 381 0 -> 382 multiple_generation(G,File,T2,RootDir,Bes); 383 _ -> 384 %% Errors reported, abort 385 ok 386 end. 387 388 389single_generation(G, File, T2) -> 390 case ic_error:get_error_count(G) of 391 0 -> 392 %% Check if user has sett backend option 393 case ic_options:get_opt(G, be) of 394 false -> 395 %% Use default backend option 396 DefaultBe = ic_options:defaultBe(), 397 ic_options:add_opt(G,[{be,DefaultBe}],true), 398 399 ?ifopt2(G, 400 time, 401 time("code generation ", ic, do_gen, [DefaultBe, G, File, T2]), 402 ic:do_gen(DefaultBe, G, File, T2)); 403 Be -> 404 %% Use user defined backend 405 ?ifopt2(G, 406 time, 407 time("code generation ", ic, do_gen, [Be, G, File, T2]), 408 ic:do_gen(Be, G, File, T2)) 409 end; 410 _ -> 411 ok %% Does not matter 412 end. 413 414 415 416