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