1 /*
2 This file is part of GNU APL, a free implementation of the
3 ISO/IEC Standard 13751, "Programming Language APL, Extended"
4
5 Copyright (C) 2008-2015 Dr. Jürgen Sauermann
6
7 This program is free software: you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation, either version 3 of the License, or
10 (at your option) any later version.
11
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with this program. If not, see <http://www.gnu.org/licenses/>.
19 */
20
21 #ifndef __SYMBOL_HH_DEFINED__
22 #define __SYMBOL_HH_DEFINED__
23
24 #include <stdint.h>
25
26 #include "ErrorCode.hh"
27 #include "NamedObject.hh"
28 #include "Parser.hh"
29 #include "SystemLimits.hh"
30 #include "Svar_DB.hh"
31
32 class IndexExpr;
33 class UserFunction;
34
35 //-----------------------------------------------------------------------------
36 /** One entry in the value stack of a symbol. The value stack
37 is pushed/poped when the symbol is localized on entry/return of
38 a user defined function.
39 */
40 /// One entry in the value stack of a Symbol
41 class ValueStackItem
42 {
43 public:
44 /// constructor: ValueStackItem for an unused symbol
ValueStackItem()45 ValueStackItem() : name_class(NC_UNUSED_USER_NAME)
46 { memset(&sym_val, 0, sizeof(sym_val)); }
47
48 /// constructor: ValueStackItem for a label (function line)
ValueStackItem(Function_Line lab)49 ValueStackItem(Function_Line lab) : name_class(NC_LABEL)
50 { sym_val.label = lab; }
51
52 /// constructor: ValueStackItem for a variable
ValueStackItem(Value_P val)53 ValueStackItem(Value_P val)
54 : apl_val(val),
55 name_class(NC_VARIABLE)
56 {}
57
58 /// constructor: ValueStackItem for a shared variable
ValueStackItem(SV_key key)59 ValueStackItem(SV_key key) : name_class(NC_SHARED_VAR)
60 { sym_val.sv_key = key; }
61
62 /// reset \b this ValueStackItem to being unused
clear()63 void clear()
64 {
65 // sym_val contains only POD variables, so it can be memset()
66 memset(&sym_val, 0, sizeof(sym_val));
67 if (!!apl_val) apl_val.reset();
68 name_class = NC_UNUSED_USER_NAME;
69 }
70
71 /// the possible values of a symbol
72 union _sym_val
73 {
74 Function * function; ///< if \b Symbol is a function
75 Function_Line label; ///< if \b Symbol is a label
76 SV_key sv_key; ///< if \b Symbol is a shared variable
77 };
78
79 /// the (current) value of this symbol (unless variable)
80 _sym_val sym_val;
81
82 /// the (current) value of this symbol (if variable)
83 Value_P apl_val;
84
85 /// the (current) name class (like ⎕NC, unless shared variable)
86 NameClass name_class;
87 };
88 //-----------------------------------------------------------------------------
89 /// Base class for variables, defined functions, snd distinguished names
90 class Symbol : public NamedObject
91 {
92 friend class SymbolTable;
93
94 public:
95 /// create a system symbol with Id \b id
96 Symbol(Id id);
97
98 /// create a symbol with name \b ucs
99 Symbol(const UCS_string & ucs, Id id);
100
101 /// destructor
~Symbol()102 virtual ~Symbol()
103 { clear_vs(); }
104
105 /// List \b this \b Symbol ( for )VARS, )FNS )
106 ostream & list(ostream & out);
107
108 /// write this symbol in )OUT format to file \b out
109 void write_OUT(FILE * out, uint64_t & seq) const;
110
111 /// set \b token according to the current NC/sym_val of \b this \b Symbol
112 virtual void resolve(Token & token, bool left);
113
114 /// set \b token according to the current NC/sym_val of \b this shared var
115 void resolve_shared_variable(Token & token);
116
117 /// resolve a variable name for an assignment
118 virtual Token resolve_lv(const char * loc);
119
120 /// return the token class of \b this \b Symbol WITHOUT calling resolve()
121 TokenClass resolve_class(bool left);
122
123 /// set current NameClass of this Symbol to NC_UNUSED_USER_NAME and remove
124 /// any values associated with this symbol
125 virtual int expunge();
126
127 /// Set current NameClass of this Symbol to \b nc
128 void set_nc(NameClass nc);
129
130 /// share variable with \b proc
131 void share_var(SV_key key);
132
133 /// unshare a shared variable
134 SV_Coupling unshare_var();
135
136 /// clear the value stack of \b this symbol
137 void clear_vs();
138
139 /// Set current NameClass of this Symbol to \b nc and function fun
140 void set_nc(NameClass nc, Function * fun);
141
142 /// Compare name of \b this value with \b other
compare(const Symbol & other) const143 int compare(const Symbol & other) const
144 { return name.compare(other.name); }
145
146 /// return true iff this variable is read-only
147 /// (overloaded by RO_SystemVariable)
is_readonly() const148 virtual bool is_readonly() const { return false; }
149
150 /// Assign \b value to \b this \b Symbol
151 virtual void assign(Value_P value, bool clone, const char * loc);
152
153 /// Assign \b value to \b this \b Symbol (which is a shared variable)
154 void assign_shared_variable(Value_P value, const char * loc);
155
156 /// Indexed (multi-dimensional) assign \b value to \b this \b Symbol
157 virtual void assign_indexed(IndexExpr & index, Value_P value);
158
159 /// Indexed (one-dimensional) assign \b value to \b this \b Symbol
160 virtual void assign_indexed(Value_P index, Value_P value);
161
162 /// assign lambda, eg. V←{ ... }
163 virtual bool assign_named_lambda(Function * lambda, const char * loc);
164
165 /// Print \b this \b Symbol to \b out
166 virtual ostream & print(ostream & out) const;
167
168 /// Print \b this \b Symbol and its stack to \b out
169 ostream & print_verbose(ostream & out) const;
170
171 /// Pop latest entry from the stack of \b this \b Symbol
172 virtual void pop();
173
174 /// Push an undefined entry onto the stack of \b this \b Symbol
175 virtual void push();
176
177 /// push a label onto the stack of \b this \b Symbol
178 virtual void push_label(Function_Line label);
179
180 /// push a function onto the stack of \b this \b Symbol
181 virtual void push_function(Function * function);
182
183 /// Push an APL value onto the stack of \b this \b Symbol
184 virtual void push_value(Value_P value);
185
186 /// return the depth (global == 0) of \b ufun on the stack. Use the largest
187 /// depth if ufun is pushed multiple times
188 int get_ufun_depth(const UserFunction * ufun);
189
190 /// return the current APL value (or throw a VALUE_ERROR)
191 virtual Value_P get_apl_value() const;
192
193 /// return the first Cell of this value without creating a value
194 const Cell * get_first_cell() const;
195
196 /// return true, iff this Symbol can be assigned
197 bool can_be_assigned() const;
198
199 /// return the current SV_key (or throw a VALUE_ERROR)
200 SV_key get_SV_key() const;
201
202 /// set the current SV_key
203 void set_SV_key(SV_key key);
204
205 /// return true, iff this Symbol is not used (i.e. erased)
is_erased() const206 bool is_erased() const
207 { return (value_stack_size() <= 1) && (value_stack_size() &&
208 (value_stack[0].name_class == NC_UNUSED_USER_NAME)); }
209
210 /// Return the current function (or throw a VALUE_ERROR)
211 virtual const Function * get_function() const;
212
213 /// The name of \b this \b Symbol
get_name() const214 virtual UCS_string get_name() const { return name; }
215
216 /// overloaded NamedObject::get_function()
217 virtual Function * get_function();
218
219 /// overloaded NamedObject::get_value()
220 virtual Value_P get_value();
221
222 /// return a reason why this symbol cant become a defined function
223 const char * cant_be_defined() const;
224
225 /// overloaded NamedObject::get_symbol()
get_symbol()226 virtual Symbol * get_symbol()
227 { return this; }
228
229 /// overloaded NamedObject::get_symbol()
get_symbol() const230 virtual const Symbol * get_symbol() const
231 { return this; }
232
233 /// store the attributes (as per ⎕AT) of symbol at dest...
234 virtual void get_attributes(int mode, Cell * dest) const;
235
236 /// return the size of the value stack
value_stack_size() const237 const int value_stack_size() const
238 { return value_stack.size(); }
239
240 /// return the top-most item on the value stack
top_of_stack() const241 const ValueStackItem * top_of_stack() const
242 { return value_stack.size() ? &value_stack.back() : 0; }
243
244 /// return the top-most item on the value stack
top_of_stack()245 ValueStackItem * top_of_stack()
246 { return value_stack.size() ? &value_stack.back() : 0; }
247
248 /// return the idx'th item on stack (higher index = newer item)
operator [](int idx) const249 const ValueStackItem & operator [](int idx) const
250 { return value_stack[idx]; }
251
252 /// return the idx'th item on stack (higher index = newer item)
operator [](int idx)253 ValueStackItem & operator [](int idx)
254 { return value_stack[idx]; }
255
256 /// set a callback function for symbol events
set_monitor_callback(void (* callback)(const Symbol &,Symbol_Event ev))257 void set_monitor_callback(void (* callback)(const Symbol &, Symbol_Event ev))
258 { monitor_callback = callback; }
259
260 /// clear the marked flag of all entries
261 void unmark_all_values() const;
262
263 /// print variables owning value
264 int show_owners(ostream & out, const Value & value) const;
265
266 /// perform a vector assignment (like (A B C)←1 2 3) for variables in
267 /// \b symbols with values \b values
268 static void vector_assignment(std::vector<Symbol *> & symbols,
269 Value_P values);
270
271 /// dump this symbol to out
272 void dump(ostream & out) const;
273
274 /// call the monitor callback function (if any) with event \b ev
call_monitor_callback(Symbol_Event ev)275 void call_monitor_callback(Symbol_Event ev)
276 { if (monitor_callback) monitor_callback(*this, ev); }
277
278 /// Compare the name of \b this \b Symbol with \b ucs
equal(const UCS_string & ucs) const279 bool equal(const UCS_string & ucs) const
280 { return (name.compare(ucs) == COMP_EQ); }
281
282 /// return the level of fun on the stack of \b this Symbol) on the SI stack
283 int get_SI_level(const Function * fun) const;
284
285 /// return the SI stack level of val on the stack of \b this Symbol)
286 int get_SI_level(const Value * val) const;
287
288 /// The next Symbol with the same hash value as \b this \b Symbol
289 Symbol * next;
290
291 protected:
292 /// the name of \b this \b Symbol
293 UCS_string name;
294
295 /// called on symbol events (if non-0)
296 void (*monitor_callback)(const Symbol &, Symbol_Event sev);
297
298 /// the value stack of \b this \b Symbol
299 std::vector<ValueStackItem> value_stack;
300 };
301
302 inline void
Hswap(const Symbol * & u1,const Symbol * & u2)303 Hswap(const Symbol * & u1, const Symbol * & u2)
304 { const Symbol * tmp = u1; u1 = u2; u2 = tmp; }
305
306 //-----------------------------------------------------------------------------
307 /// lambda result λ
308 class LAMBDA : public Symbol
309 {
310 public:
311 /// constructor
LAMBDA()312 LAMBDA()
313 : Symbol(ID_LAMBDA)
314 {}
315
316 /// destroy variable
destroy_var()317 void destroy_var() {}
318 };
319 //-----------------------------------------------------------------------------
320 /// lambda variable ⍺
321 class ALPHA : public Symbol
322 {
323 public:
324 /// constructor
ALPHA()325 ALPHA()
326 : Symbol(ID_ALPHA)
327 {}
328
329 /// destroy variable
destroy_var()330 void destroy_var() {}
331 };
332 //-----------------------------------------------------------------------------
333 /// lambda variable ⍶
334 class ALPHA_U : public Symbol
335 {
336 public:
337 /// constructor
ALPHA_U()338 ALPHA_U()
339 : Symbol(ID_ALPHA_U)
340 {}
341
342 /// destroy variable
destroy_var()343 void destroy_var() {}
344 };
345 //-----------------------------------------------------------------------------
346 /// lambda variable χ
347 class CHI : public Symbol
348 {
349 public:
350 /// constructor
CHI()351 CHI()
352 : Symbol(ID_CHI)
353 {}
354
355 /// destroy variable
destroy_var()356 void destroy_var() {}
357 };
358 //-----------------------------------------------------------------------------
359 /// lambda variable ⍵
360 class OMEGA : public Symbol
361 {
362 public:
363 /// constructor
OMEGA()364 OMEGA()
365 : Symbol(ID_OMEGA)
366 {}
367
368 /// destroy variable
destroy_var()369 void destroy_var() {}
370 };
371 //-----------------------------------------------------------------------------
372 /// lambda variable ⍹
373 class OMEGA_U : public Symbol
374 {
375 public:
376 /// constructor
OMEGA_U()377 OMEGA_U()
378 : Symbol(ID_OMEGA_U)
379 {}
380
381 /// destroy variable
destroy_var()382 void destroy_var() {}
383 };
384 //-----------------------------------------------------------------------------
385
386 #endif // __SYMBOL_HH_DEFINED__
387