home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
OS/2 Shareware BBS: 10 Tools
/
10-Tools.zip
/
sa104os2.zip
/
SATHR104.ZIP
/
SATHER
/
COMPILER
/
OPTIONS.SA
< prev
next >
Wrap
Text File
|
1995-02-13
|
23KB
|
718 lines
-- Copyright (C) International Computer Science Institute, 1994. COPYRIGHT --
-- NOTICE: This code is provided "AS IS" WITHOUT ANY WARRANTY and is subject --
-- to the terms of the SATHER LIBRARY GENERAL PUBLIC LICENSE contained in --
-- the file "Doc/License" of the Sather distribution. The license is also --
-- available from ICSI, 1947 Center St., Suite 600, Berkeley CA 94704, USA. --
--------> Please email comments to "sather-bugs@icsi.berkeley.edu". <----------
class OPTIONS is
attr sather_files:FSET{STR}; -- Sather source files
private attr paths:FSET{STR};
-- Resolved Sather source paths (to allow redundancy in on command line)
attr c_files:FSET{STR}; -- C source files
attr object_files:FSET{STR}; -- object files
attr archive_files:FLIST{STR}; -- `library' archive files
attr main_class:STR; -- The class with main
attr executable:STR; -- The executable to output, or void
attr home:STR; -- home
attr gen_c:BOOL; -- If true, generate C files
attr pretty:BOOL; -- Make generated C look nice
attr verbose:BOOL; -- Be noisy
attr psather:BOOL; -- Accept pSather code
attr only_parse:BOOL; -- Stop after parsing
attr only_check:BOOL; -- Don't do code generation
attr only_C:BOOL; -- Stop after making C
attr only_reachable:BOOL; -- Don't check unreachable code
attr optimize:BOOL; -- Attempt optimizations
attr debug:BOOL; -- Generate debugging information
attr deterministic:BOOL; -- generate id determinism
-- because we don't know the class names at the time
-- that the command line is parsed, there is a special
-- representation for sets of classes with given checking
-- on or off. *.union(chk_in).difference(chk_out), where
-- chk is the check name and * is all classes if chk_all
-- is true or the empty set if chk_all is false.
attr pre_all, post_all, invariant_all, assert_all, arith_all,
bounds_all, void_all, when_all, destroy_all, return_all:BOOL;
attr pre_in, post_in, invariant_in, assert_in,
arith_in, bounds_in, void_in, when_in,
destroy_in, return_in:FSET{STR};
attr pre_out, post_out, invariant_out, assert_out,
arith_out, bounds_out, void_out, when_out,
destroy_out, return_out:FSET{STR};
attr force_routines:FSET{STR}; -- Routines to be generated no matter what
attr force_all:BOOL; -- Force all generation
attr c_flags:FLIST{STR}; -- Flags to pass to C compiler
attr externals:FMAP{STR,FSET{STR}}; -- Files linked if class reachable
attr has:FMAP{STR,STR}; -- Files containing classes given by -has
attr known_files:FSET{STR}; -- Files that we know all classes by -has
attr c_compile1, c_compile2, c_opt, c_debug, c_verbose, c_exec:STR;
attr make_command, make_silent:STR;
attr null_segfaults:BOOL;
-- Options garnered from CONFIG file
create:SAME is
r::=new;
r.bounds_all:=true;
r.void_all:=true;
r.when_all:=true;
r.return_all:=true;
r.main_class:="MAIN";
-- r.executable:="a.out"; -- NLP
return r;
end;
pre_chk(n:STR):BOOL is
return (pre_all or pre_in.test(n)) and ~pre_out.test(n);
end;
post_chk(n:STR):BOOL is
return (post_all or post_in.test(n)) and ~post_out.test(n);
end;
invariant_chk(n:STR):BOOL is
return (invariant_all or invariant_in.test(n)) and ~invariant_out.test(n);
end;
assert_chk(n:STR):BOOL is
return (assert_all or assert_in.test(n)) and ~assert_out.test(n);
end;
arith_chk(n:STR):BOOL is
return (arith_all or arith_in.test(n)) and ~arith_out.test(n);
end;
bounds_chk(n:STR):BOOL is
return (bounds_all or bounds_in.test(n)) and ~bounds_out.test(n);
end;
void_chk(n:STR):BOOL is
return (void_all or void_in.test(n)) and ~void_out.test(n);
end;
when_chk(n:STR):BOOL is
return (when_all or when_in.test(n)) and ~when_out.test(n);
end;
destroy_chk(n:STR):BOOL is
return (destroy_all or destroy_in.test(n)) and ~destroy_out.test(n);
end;
return_chk(n:STR):BOOL is
return (return_all or return_in.test(n)) and ~return_out.test(n);
end;
private mention(name,s1,s2:STR):STR is
if s2/="" then return s1+'\n'+name+": "+s2;
-- else return s1; -- NLP
end; return s1; -- NLP
-- end; -- NLP
end;
str:STR is
-- diagnostic for printing the state of a command line parse
r,s:STR;
r:=""; loop r:=r+' '+sather_files.elt!; end;
s:=mention("Sather files","",r);
r:=""; loop r:=r+' '+c_files.elt!; end;
s:=mention("C files",s,r);
r:=""; loop r:=r+' '+object_files.elt!; end;
s:=mention("object files",s,r);
r:=""; loop r:=r+' '+archive_files.elt!; end;
s:=mention("archive files",s,r);
s:=mention("Main class",s,main_class);
s:=mention("Executable",s,executable);
s:=s+"\nHome directory: "+home;
if gen_c then s:=s+"\nGenerate C."; end;
if pretty then s:=s+"\nPretty C."; end;
if verbose then s:=s+"\nVerbose."; end;
if optimize then s:=s+"\nOptimize."; end;
if debug then s:=s+"\nGenerate debugging info."; end;
if psather then s:=s+"\nAccept pSather code."; end;
if deterministic then s:=s+"\nGenerate deterministic ob ids."; end;
if only_parse then s:=s+"\nStop after parsing."; end;
if only_check then s:=s+"\nDon't generate code."; end;
if only_C then s:=s+"\nDon't compile C."; end;
if only_reachable then s:=s+"\nDon't check unreachable code."; end;
r:="";
if pre_all then r:=r+"All";
else loop r:=r+'+'+pre_in.elt!; end;
end;
loop r:=r+'-'+pre_out.elt!; end;
s:=mention("Preconditions",s,r);
r:="";
if post_all then r:=r+"All";
else loop r:=r+'+'+post_in.elt!; end;
end;
loop r:=r+'-'+post_out.elt!; end;
s:=mention("Postconditions",s,r);
r:="";
if invariant_all then r:=r+"All";
else loop r:=r+'+'+invariant_in.elt!; end;
end;
loop r:=r+'-'+invariant_out.elt!; end;
s:=mention("Invariants",s,r);
r:="";
if assert_all then r:=r+"All";
else loop r:=r+'+'+assert_in.elt!; end;
end;
loop r:=r+'-'+assert_out.elt!; end;
s:=mention("Asserts",s,r);
r:="";
if void_all then r:=r+"All";
else loop r:=r+'+'+void_in.elt!; end;
end;
loop r:=r+'-'+void_out.elt!; end;
s:=mention("Void checks",s,r);
r:="";
if when_all then r:=r+"All";
else loop r:=r+'+'+when_in.elt!; end;
end;
loop r:=r+'-'+when_out.elt!; end;
s:=mention("When clause",s,r);
r:="";
if bounds_all then r:=r+"All";
else loop r:=r+'+'+bounds_in.elt!; end;
end;
loop r:=r+'-'+bounds_out.elt!; end;
s:=mention("Bounds",s,r);
r:="";
if destroy_all then r:=r+"All";
else loop r:=r+'+'+destroy_in.elt!; end;
end;
loop r:=r+'-'+destroy_out.elt!; end;
s:=mention("Destroy",s,r);
r:="";
if arith_all then r:=r+"All";
else loop r:=r+'+'+arith_in.elt!; end;
end;
loop r:=r+'-'+arith_out.elt!; end;
s:=mention("Arith",s,r);
r:="";
if return_all then r:=r+"All";
else loop r:=r+'+'+return_in.elt!; end;
end;
loop r:=r+'-'+return_out.elt!; end;
s:=mention("Return",s,r);
r:="";
if force_all then r:=r+"All";
elsif ~force_routines.is_empty then
loop r:=r+' '+force_routines.elt!; end;
end;
s:=mention("Forced routines",s,r);
r:="";
if ~c_flags.is_empty then loop r:=r+' '+c_flags.elt!; end; end;
s:=mention("C flags",s,r);
if ~externals.is_empty then
s:=s+"\nExternals:";
loop p::=externals.pairs!;
s:=s+"\n "+p.t1+" -> {";
loop r:=r+",".separate!(p.t2.elt!); end;
s:=s+"}\n";
end;
end;
if ~has.is_empty then
s:=s+"\nHas:";
loop p::=has.pairs!; s:=s+"\n "+p.t1+" in "+p.t2; end;
s:=s+"\n";
end;
return s;
end;
private attr args:ARRAY{STR};
private attr next:INT;
private attr classes:FSET{STR};
private attr all:BOOL;
interpret(a:ARRAY{STR}) is
-- interpret command lines.
args:=a;
next:=1;
get_files;
insert_here(args_from_env);
loop while!(more_args);
s::=next_arg;
case s
when "-main" then main_class:=next_arg;
when "-o" then executable:=next_arg;
when "-home" then home:=next_arg;
when "-output_C" then gen_c:=true;
when "-pretty" then pretty:=true;
when "-verbose" then verbose:=true;
when "-psather" then psather:=true;
when "-only_parse" then only_parse:=true;
when "-only_check" then only_check:=true;
when "-only_C" then only_C:=true; gen_c:=true;
when "-only_reachable" then only_reachable:=true;
when "-check" then
get_classes;
if all then
arith_all:=true; arith_out:=#;
bounds_all:=true; bounds_out:=#;
void_all:=true; void_out:=#;
pre_all:=true; pre_out:=#;
post_all:=true; post_out:=#;
assert_all:=true; assert_out:=#;
invariant_all:=true; invariant_out:=#;
when_all:=true; when_out:=#;
destroy_all:=true; destroy_out:=#;
return_all:=true; return_out:=#;
else
arith_in:=arith_in.union(classes);
bounds_in:=bounds_in.union(classes);
void_in:=void_in.union(classes);
pre_in:=pre_in.union(classes);
post_in:=post_in.union(classes);
assert_in:=assert_in.union(classes);
invariant_in:=invariant_in.union(classes);
when_in:=when_in.union(classes);
destroy_in:=destroy_in.union(classes);
return_in:=return_in.union(classes);
arith_out:=arith_out.difference(classes);
bounds_out:=bounds_out.difference(classes);
void_out:=void_out.difference(classes);
pre_out:=pre_out.difference(classes);
post_out:=post_out.difference(classes);
assert_out:=assert_out.difference(classes);
invariant_out:=invariant_out.difference(classes);
when_out:=when_out.difference(classes);
destroy_out:=destroy_out.difference(classes);
return_out:=return_out.difference(classes);
end;
when "-arith" then
get_classes;
if all then arith_all:=true; arith_out:=#;
else
arith_in:=arith_in.union(classes);
arith_out:=arith_out.difference(classes);
end;
when "-bounds" then
get_classes;
if all then bounds_all:=true; bounds_out:=#;
else
bounds_in:=bounds_in.union(classes);
bounds_out:=bounds_out.difference(classes);
end;
when "-void" then
get_classes;
if all then void_all:=true; void_out:=#;
else
void_in:=void_in.union(classes);
void_out:=void_out.difference(classes);
end;
when "-pre" then
get_classes;
if all then pre_all:=true; pre_out:=#;
else
pre_in:=pre_in.union(classes);
pre_out:=pre_out.difference(classes);
end;
when "-post" then
get_classes;
if all then post_all:=true; post_out:=#;
else
post_in:=post_in.union(classes);
post_out:=post_out.difference(classes);
end;
when "-assert" then
get_classes;
if all then assert_all:=true; assert_out:=#;
else
assert_in:=assert_in.union(classes);
assert_out:=assert_out.difference(classes);
end;
when "-invariant" then
get_classes;
if all then invariant_all:=true; invariant_out:=#;
else
invariant_in:=invariant_in.union(classes);
invariant_out:=invariant_out.difference(classes);
end;
when "-when" then
get_classes;
if all then when_all:=true; when_out:=#;
else
when_in:=when_in.union(classes);
when_out:=when_out.difference(classes);
end;
when "-destroy" then
get_classes;
if all then destroy_all:=true; destroy_out:=#;
else
destroy_in:=destroy_in.union(classes);
destroy_out:=destroy_out.difference(classes);
end;
when "-return" then
get_classes;
if all then return_all:=true; return_out:=#;
else
return_in:=return_in.union(classes);
return_out:=return_out.difference(classes);
end;
when "-when" then
get_classes;
if all then when_all:=true; when_out:=#;
else
when_in:=when_in.union(classes);
when_out:=when_out.difference(classes);
end;
when "-no_check" then
get_classes;
if all then
arith_in:=#; arith_all:=false;
bounds_in:=#; bounds_all:=false;
void_in:=#; void_all:=false;
pre_in:=#; pre_all:=false;
post_in:=#; post_all:=false;
assert_in:=#; assert_all:=false;
invariant_in:=#; invariant_all:=false;
when_in:=#; when_all:=false;
destroy_in:=#; destroy_all:=false;
return_in:=#; return_all:=false;
else
arith_out:=arith_out.union(classes);
bounds_out:=bounds_out.union(classes);
void_out:=void_out.union(classes);
pre_out:=pre_out.union(classes);
post_out:=post_out.union(classes);
assert_out:=assert_out.union(classes);
invariant_out:=invariant_out.union(classes);
when_out:=when_out.union(classes);
destroy_out:=destroy_out.union(classes);
return_out:=return_out.union(classes);
end;
when "-no_arith" then
get_classes;
if all then arith_in:=#; arith_all:=false;
else arith_out:=arith_out.union(classes);
end;
when "-no_bounds" then
get_classes;
if all then bounds_in:=#; bounds_all:=false;
else bounds_out:=bounds_out.union(classes);
end;
when "-no_void" then
get_classes;
if all then void_in:=#; void_all:=false;
else void_out:=void_out.union(classes);
end;
when "-no_pre" then
get_classes;
if all then pre_in:=#; pre_all:=false;
else pre_out:=pre_out.union(classes);
end;
when "-no_post" then
get_classes;
if all then post_in:=#; post_all:=false;
else post_out:=post_out.union(classes);
end;
when "-no_assert" then
get_classes;
if all then assert_in:=#; assert_all:=false;
else assert_out:=assert_out.union(classes);
end;
when "-no_invariant" then
get_classes;
if all then invariant_in:=#; invariant_all:=false;
else invariant_out:=invariant_out.union(classes);
end;
when "-no_destroy" then
get_classes;
if all then destroy_in:=#; destroy_all:=false;
else destroy_out:=destroy_out.union(classes);
end;
when "-no_return" then
get_classes;
if all then return_in:=#; return_all:=false;
else return_out:=return_out.union(classes);
end;
when "-no_when" then
get_classes;
if all then when_in:=#; when_all:=false;
else when_out:=when_out.union(classes);
end;
when "-optimize", "-O" then optimize:=true;
when "-fast" then
optimize:=true;
arith_in:=#; arith_all:=false;
bounds_in:=#; bounds_all:=false;
void_in:=#; void_all:=false;
pre_in:=#; pre_all:=false;
post_in:=#; post_all:=false;
assert_in:=#; assert_all:=false;
invariant_in:=#; invariant_all:=false;
when_in:=#; when_all:=false;
destroy_in:=#; destroy_all:=false;
return_in:=#; return_all:=false;
when "-debug", "-g" then debug:=true; gen_c:=true;
when "-deterministic" then deterministic:=true;
when "-force" then force_routines:=force_routines.insert(next_arg);
when "-force_all" then force_all:=true;
when "-C_flag" then c_flags:=c_flags.push(next_arg);
when "-external" then externals:=externals.insert(next_arg,files);
when "-has" then
fn::=next_arg;
known_files:=known_files.insert(fn);
get_classes;
loop has:=has.insert(classes.elt!,fn); end;
when "-com" then insert_here(args_from_file(next_arg));
else if is_filename(s) then rewind; get_files;
else rewind; usage; return;
end;
end;
end;
if void(home) then
barf("No home directory specified. Use -home <dir> or make sure SATHER_COMMANDS is set correctly.");
end;
if void(executable) then -- NLP
barf("No executable specified. Use -o <name> -- the compiler will append '.exe'."); -- NLP
end; -- NLP
l::=#BE_LEX(home+"/System/CONFIG");
if void(l) then barf("Could not open CONFIG file.\n"); end;
c_compile1:=l.get_str;
if void(c_compile1) then barf("Could not read CONFIG:c1."); end;
t::=l.get_str;
if void(t) then barf("Could not read CONFIG:c2."); end;
c_compile2:="";
loop c::=t.elt!;
if c='\\' then c:='/'; end; -- NLP
if c/='#' then c_compile2:=c_compile2+c;
elsif home=".." then -- for the bootstrap
c_compile2:=c_compile2+"../..";
else
c_compile2:=c_compile2+home;
end;
end;
c_opt:=l.get_str;
if void(c_opt) then barf("Could not read CONFIG:c_opt."); end;
c_debug:=l.get_str;
if void(c_debug) then barf("Could not read CONFIG:c_dbg."); end;
c_verbose:=l.get_str;
if void(c_verbose) then barf("Could not read CONFIG:vbs."); end;
make_command:=l.get_str;
if void(make_command) then barf("Could not read CONFIG:make_com."); end;
make_silent:=l.get_str;
if void(make_silent) then barf("Could not read CONFIG:mk_silent."); end;
c_exec:=l.get_str;
if void(c_exec) then barf("Could not read CONFIG:exec."); end;
t:=l.get_str;
if void(t) then barf("Could not read CONFIG:null_segf."); end;
null_segfaults:=BOOL::from_str(t);
end;
private barf(msg:STR) is
#ERR + msg + '\n';
UNIX::exit(1);
end;
private more_args:BOOL is return next<args.size end;
private next_arg:STR is
if more_args then res::=args[next]; next:=next+1; return res;
-- else usage; return ""; -- NLP
end; usage; return ""; -- NLP
-- end; -- NLP
end;
rewind is next:=next-1; end;
private get_classes is
-- get a list of classes from the argument list
classes:=#;
loop while!(more_args);
arg::=next_arg;
all:=arg="all";
if all then return;
elsif is_class_name(arg) then classes:=classes.insert(arg);
else rewind; return;
end;
end;
end;
private is_class_name(nm:STR):BOOL is
-- is this string a viable class name?
if nm[0]/='$' and ~nm[0].is_upper then return false; end;
loop c::=nm.elt!(1);
case c
when 'A','B','C','D','E','F','G','H','I','J',
'K','L','M','N','O','P','Q','R','S','T',
'U','V','W','X','Y','Z','0','1','2','3',
'4','5','6','7','8','9','_' then
else return false;
end;
end;
return true;
end;
private files:FSET{STR} is
-- get a list of files from the command line
r::=#FSET{STR};
loop while!(more_args);
arg::=next_arg;
if is_filename(arg) then r:=r.insert(arg);
else rewind; return r;
end;
end;
return r;
end;
private get_files is
-- get list of files from the command line and put in appropriate set
loop while!(more_args);
arg::=next_arg;
suf::=suffix(arg);
if suf=".c" then c_files:=c_files.insert(arg);
-- elsif suf=".o" then object_files:=object_files.insert(arg); -- NLP
elsif suf=".obj" then object_files:=object_files.insert(arg); -- NLP
elsif suf=".sa" then
-- make sure isn't found by a different name already
path::=FILE::resolve_path(arg);
if ~paths.test(path) then
sather_files:=sather_files.insert(arg);
paths:=paths.insert(path);
end;
-- elsif suf=".a" then archive_files:=archive_files.push(arg); -- NLP
elsif suf=".lib" then archive_files:=archive_files.push(arg); -- NLP
else rewind; return;
end;
end;
end;
private usage is
#ERR + "Command line error near: " + args[next.min(args.size-1)] + '\n';
#ERR + "(See man page.)\n";
UNIX::exit(1);
end;
private suffix(a:STR):STR is
pos:INT;
loop pos:=(a.length-1).downto!(0); until!(a[pos]='.'); end;
return a.tail(a.length-pos);
end;
private is_filename(fn:STR):BOOL is
if fn[0]='-' then return false; end;
case suffix(fn)
-- when ".c", ".sa", ".o", ".a" then return true; -- NLP
when ".c", ".sa", ".obj", ".lib" then return true; -- NLP
-- else return false; -- NLP
else; end; return false; -- NLP
-- end; -- NLP
end;
private insert_here(cl:FLIST{STR}) is
-- insert a list of args so it will be read next
tail:ARRAY{STR};
if more_args then tail:=args.subarr(next,args.size-next);
else tail:=#(0);
end;
args:=cl.array.append(tail);
next:=0;
end;
-- private args_from_file(name:STR):FLIST{STR} is -- NLP
private args_from_file(fname:STR):FLIST{STR} is -- NLP
name::=fname.replace('\\','/'); -- NLP
wd::=directory(name);
cl::=#FLIST{STR};
f::=FILE::open_for_read(name);
if f.error then #ERR + "Couldn't open file: " + name + '\n'; usage; end;
fs::=f.fstr+' ';
f.close;
tok::="";
pos::=0;
loop
until!(pos>=fs.size);
c::=fs[pos];
if c='\\' then c:='/'; end; -- NLP
if c='-' then
if fs[pos+1]='-' then
loop
pos:=pos+1;
until!(pos>=fs.size or fs[pos]='\n' or fs[pos]='\r');
end;
else tok:=tok+'-';
end;
elsif ~c.is_space then tok:=tok+c;
elsif tok/="" then
if is_filename(tok) and tok[0]/='/' then tok:=wd+'/'+tok; end;
cl:=cl.push(tok);
tok:="";
end;
pos:=pos+1;
end;
return cl;
end;
private directory(nm:STR):STR is
-- The directory in which nm resides
pos:INT;
loop pos:=(nm.size-1).downto!(0); if nm[pos]='/' then break!; end; end;
r::=nm.head(pos);
if r="" then r:="."; end;
return r;
end;
private args_from_env:FLIST{STR} is
cl::=#FLIST{STR};
sc::=UNIX::get_env("SATHER_COMMANDS");
if void(sc) then sc:=""; end;
tok::="";
loop c::=sc.elt!;
if c = '\\' then c := '/'; end; -- NLP
if ~c.is_space then tok:=tok+c;
elsif tok/="" then cl:=cl.push(tok); tok:="";
end;
end;
if tok/="" then cl:=cl.push(tok); end;
return cl;
end;
end;
-----------------------------------------------------------------
class OPTIONS_TEST is
main(a:ARRAY{STR}) is
op::=#OPTIONS;
op.interpret(a);
#OUT + op.str + '\n';
end;
end;