HOME | 7. Abstract Classes | Try Sather | 9. Operators | download | Post Messages |
Method | Explanation |
---|---|
elt! | It is an iterator defined in $ELT and $ELT{ETP}. It returns an element stored in a container one by one. |
copy | It returns a copy of self, which is defined in the $CONTAINER class. |
has(e: ETP) | It returns true if self contains e. |
size | It returns the number of elements. |
01: -- a simple typecase program 02: 03: class MAIN is 04: 05: main is 06: a:ARRAY{$STR}:=#(|1, 2.12, 3.14159d, "Hello", #INTI(1000000), 'c'|); -- defining an array that contains six objects which have $STR method 07: s:STR; -- Any object having .str method can be stored in the array. 08: loop 09: i:$STR:=a.elt!; -- picking up an object from the array 10: typecase i -- and change the procedure according to the data type 11: when INT then 12: s:="INT: "; 13: when FLT then 14: s:="FLT: "; 15: when FLTD then 16: s:="FLTD: "; 17: when INTI then 18: s:="INTI: "; 19: when STR then 20: s:="STR: "; 21: else 22: s:="Other: "; 23: end; 24: #OUT + "a[" + a.ind! +"] = " + s + i.str + "\n"; 25: end; 26: end; 27: end;
$ sacomp typecase.sa -o typecase $ ./typecase a[0] = INT: 1 a[1] = FLT: 2.12 a[2] = FLTD: 3.14159 a[3] = STR: Hello a[4] = INTI: 100000000 a[5] = Other: c
a0:ARRAY{INT}=#(|1,2,3|); -- a0[0]=1, a0[1]=2, a0[2]=3 a1:ARRAY{INT}=#(3); -- making an array for three INT's a2::=#ARRAY{INT}; -- making an array for zero INT'sThe create_from(e: $ELT{T}):SAME constructor is also defined to create an instance of ARRAY{T} from that of other $ELT{T} classes.
methods | explanation |
---|---|
append | It appends arrays. It takes one to three arguments. |
binary_search(e:T) | It returns the index of e from a sorted array. |
copy | It copies self. It takes variety of arguments. |
count(e:T) | It return the number of e. |
has(e:T) | It returns true if the array contains e. |
remove(e:T) | It removes e from the array and returns the resulting array. |
remove_duplicates | It removes duplicates and return the resulting array. |
reverse | It returns the reverse-order array. |
size | It returns the size of array. |
sort | It sorts the array. |
str | It converts the array to a string. |
elt! | It returns an array element one by one. |
ind! | It returns the index one by one. |
set!(e:T) | It assigns a value to the element one by one. |
Example: tup.sa, in which the attributes of people are stored by TUP{INT, STR, CHAR, INT}.
01: -- a simple TUP program 02: 03: class MAIN is 04: 05: shared id:INT:=0; 06: make_person(name:STR, sex:CHAR, age:INT):TUP{INT, STR, CHAR, INT} is 07: id:= id+1; 08: return #(id, name, sex, age); 09: end; 10: 11: person_id(p:TUP{INT,STR,CHAR,INT}):INT is 12: return p.t1; 13: end; 14: 15: person_name(p:TUP{INT,STR,CHAR,INT}):STR is 16: return p.t2; 17: end; 18: 19: person_sex(p:TUP{INT,STR,CHAR,INT}):STR is 20: if p.t3 = 'm' then return "male"; 21: else return "female"; 22: end; 23: end; 24: 25: person_age(p:TUP{INT,STR,CHAR,INT}):INT is 26: return p.t4; 27: end; 28: 29: show_person(p:TUP{INT,STR,CHAR,INT}):STR is 30: return "ID: " + person_id(p).str + 31: "\nNAME: " + person_name(p) + 32: "\nSEX: " + person_sex(p) + 33: "\nAGE: " + person_age(p).str + "\n\n"; 34: end; 35: 36: main is 37: #OUT + "TUP test using person properties.\n\n"; 38: a:ARRAY{TUP{INT,STR,CHAR,INT}}:=#(|make_person("John Smith", 'm', 50), make_person("Mary McCarthy", 'f', 25)|); 39: loop 40: #OUT + show_person(a.elt!); 41: end; 42: end; 43: end;
$ sacomp tup.sa -o tup $ ./tup TUP test using person properties. ID: 1 NAME: John Smith SEX: male AGE: 50 ID: 2 NAME: Mary McCarthy SEX: female AGE: 25In fact defining PERSON class is better, I use TUP just for example.
01: -- swc.sa: a simple words counts program written in sather 02: 03: class MAIN is 04: 05: const nonword_chars:STR:=" \t\n\r.,\"\\\`\':;?!()/-"; -- These characters are removed from the word if they are at the end (\W). 06: 07: -- check if the character is a word character. 08: is_wordchar(c:CHAR):BOOL is 09: return ~nonword_chars.contains(c); -- return true if not \W 10: end; 11: 12: -- truncating non_word characters from the head or tail of the word. 13: w_truncate(w:STR, headp:BOOL):STR is 14: idx,begin,num:INT; 15: num:=w.size-1; 16: if headp then 17: idx:=0; 18: begin:=1; 19: else 20: idx:=num; 21: begin:=0; 22: end; 23: if w.size=0 or is_wordchar(w.char(idx)) then 24: return w; 25: else 26: return w_truncate(w.substring(begin,num), headp); 27: end; 28: end; 29: 30: -- modifying the word to add to the hash table 31: w_modify(w:STR):STR is 32: return w_truncate(w_truncate(w, false), true).lower; 33: end; 34: 35: -- making a word count hash table 36: make_hash(f:FILE):MAP{STR, INT} is 37: hash::=#MAP{STR,INT}; 38: line,w:STR; 39: loop 40: until!(f.eof); 41: line:=f.get_str + " "; -- Adding Space to pick up the last word of the line using split! 42: loop 43: w:=w_modify(line.split!(' ')); 44: if w.size > 0 then 45: if hash.has_ind(w) then 46: hash[w]:=hash[w]+1; 47: else 48: hash[w]:=1; 49: end; 50: end; 51: end; 52: end; 53: return hash; 54: end; 55: 56: -- getting the sorted array of the keys of the hash table 57: get_sorted_key(wc:MAP{STR,INT}):ARRAY{STR} is 58: a:ARRAY{STR}:=#(wc.size); 59: loop 60: a.set!(wc.ind!); 61: end; 62: return a.sort; 63: end; 64: 65: -- showing the result of word count, sorted by word. 66: show_result(wc:MAP{STR,INT}) is 67: w:STR; 68: loop 69: w:=get_sorted_key(wc).elt!; 70: #OUT + w + "\t" + wc[w] + "\n"; 71: end; 72: end; 73: 74: -- practical main function, counting word in a file 75: count_words(filename:STR) is 76: f::=FILE::open_for_read(filename); 77: if f.error then 78: #ERR + "Cannot open " + filename + "\n"; 79: else 80: show_result(make_hash(f)); 81: f.close; 82: end; 83: end; 84: 85: main(av: ARRAY{STR}) is 86: if (av.size = 2) then 87: count_words(av[1]); 88: else 89: #ERR + "Usage: scw FILENAME\n"; 90: end; 91: end; 92: end; -- MAIN
Here is a breadth first search (BFS) program as an example of LIST{T}. BFS takes a path so far from the queue, then adds the adjacent nodes of the last node if not visited yet. Finally it adds the resulting paths at the end of the queue. The following code (bfs.sa) returns the shortest path from the start to the goal in Figure 1.
Figure 1: A graph used in bfs.sa
01: -- bfs.sa: a simple breadth fast search 02: 03: class MAIN is 04: 05: const gr:ARRAY{ARRAY{INT}}:=| |1,2,3|, |4|, |4,5|, |6|, |0|, |6,7|, |8|, |3|, |5| |; -- ARRAY{ARRAY{INT}} expression of the graph shown in Fig. 1 06: attr goal:INT; 07: attr queue:LIST{LIST{INT}}; -- list of searched paths so far 08: 09: bfs is 10: if queue.size=0 then 11: #OUT + "Can not find the path\n"; -- if no queue, warn 12: UNIX::exit(1); -- and exit 13: end; 14: path:LIST{INT}:=queue[0]; -- take the first item of the queue 15: queue.remove_index(0); -- delete the first item 16: next_nodes:ARRAY{INT}:=gr[path[path.size-1]]; -- get the array of adjacent node from the last node (path[path.size-1]) 17: node:INT; 18: loop 19: node:=next_nodes.elt!; -- search the next node one by one 20: if node=goal then -- if it is the goal, 21: #OUT + "found: " + path.append(goal) + "\n"; -- show the path from the start to the goal. 22: UNIX::exit(0); 23: elsif ~path.has(node) then -- if not visited yet, 24: queue.append(path.append(node)); -- add the node at the end of the path so far then add the path to the end of the queue 25: end; 26: end; 27: bfs; -- call bfs recursively 28: end; 29: 30: main(av:ARRAY{STR}) is 31: if av.size=3 then -- check the number of arguments 32: goal:=av[2].cursor.get_int; -- the 2nd argument is the goal 33: queue:=#; -- initialize the queue 34: queue.append(#(|av[1].cursor.get_int|)); -- add the start point to the queue 35: bfs; -- do bfs 36: else 37: #ERR + "Usage: bfs START GOAL\n"; 38: end; 39: end; 40: end;
$ sacomp bfs.sa -o bfs
$ ./bfs 1 7 -- search a path from node 1 to node 7
found: {1,4,0,2,5,7}
Here is a program of a reverse polish calculator as an example of a stack. Only four arithmetic operations are implemented for simplicity.
01: -- calc.sa: a simple reverse polish calculator 02: 03: class MAIN is 04: 05: const op:STR:="+-*/"; 06: const re:REGEXP:=REGEXP::regexp("^[+\\-]?[0-9]+\\.?[0-9]*$", false); -- regular expression of numbers 07: shared stack:FLIST{FLTD}:=FLIST{FLTD}::create; -- a stack of FLTD 08: 09: operatorp(word:STR):BOOL is 10: return (word.size = 1 and op.contains(word.char(0))); 11: end; 12: 13: numberp(word:STR):BOOL is 14: return re.match(word); 15: end; 16: 17: calculate(word:STR) is -- take two items from the stack 18: c:CHAR:=word.char(0); 19: f1,f2, fr:FLTD; 20: f2:=stack.pop; 21: f1:=stack.pop; 22: case c -- then operate 23: when '+' then fr := f1+f2; 24: when '-' then fr := f1-f2; 25: when '*' then fr := f1*f2; 26: when '/' then fr := f1/f2; 27: else #ERR + "The operator is not supported.\n"; 28: end; 29: stack:=stack.push(fr); -- then push the result to the stack 30: end; 31: 32: push_to_stack(word:STR) is 33: stack:=stack.push(word.cursor.get_fltd); 34: end; 35: 36: main(av: ARRAY{STR}) is 37: line, word:STR; 38: loop 39: #OUT + "> "; 40: if ~void(stack) then 41: #OUT + stack[0] + " "; 42: end; 43: line:=#IN.get_str; 44: if line.size = 0 then break!; end; -- terminate if no input 45: line := line + " "; 46: loop 47: word := line.split!(' '); 48: word := word.head(word.size-1); 49: if operatorp(word) then calculate(word); 50: elsif numberp(word) then push_to_stack(word); 51: end; 52: end; 53: end; 54: end; 55: end;
$ sacomp calc.sa -o calc $ ./calc > 1 8 + 3.7 0.7 - / -- (1 + 8) / (3.7 - 0.7) > 3 0.01 * -- you can continue calculation from the last result > 0.03
Class | Explanation |
---|---|
ARRAY2{} | 2 dimensional array |
ARRAY3{} | 3 dimensional array |
BAG{} | bag. store items with no order, allowing duplication |
QUEUE{} | queue. In fact, bfs.sa gets shorter using this class. |
STACK{} | stack. calc.sa gets shorter with this class. |
SET{} | set. methods like union and intersection are defined. |
HOME | 7. Abstract Classes | Try Sather | 9. Operators | download | Post Messages |