semantic.pl
3.8 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
% == No, Emacs this is -*-Prolog-*- code, not what you thought... =============
% == NAMES ====================================================================
% -- sa_names(AST_IN, AST_OUT, ST) --------------------------------------------
%
% sa_names/3: do name analysis (replace identifiers by their dict. entry)
sa_names(fzn(preds(IP), vars(IV), constrs(IC), SOLVE),
fzn(preds(OP), vars(OV), constrs(OC), SOLVE), ST) :-
sa_n_traverse(IP, OP, ST), % predicates
sa_n_traverse(IV, OV, ST), % variables
sa_n_traverse(IC, OC, ST). % constraints
% -----------------------------------------------------------------------------
sa_n_traverse([], [], _ST) :- !.
sa_n_traverse([N|Ns], [NN|NNs], ST) :-
sa_n(N, NN, ST), !,
sa_n_traverse(Ns, NNs, ST).
sa_n_traverse([_|Ns], NNs, ST) :- !, % ignore failing nodes (beware!)
sa_n_traverse(Ns, NNs, ST).
sa_n_traverse(N, NN, ST) :- sa_n(N, NN, ST). % non-list case
% - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
%
% sa_n(AST_N_IN, AST_N_OUT, ST)
%
% arguments:
% AST_N_IN - input AST node
% AST_N_OUT - output AST node (same structure, rewritten)
% ST - symbol table (gets extended)
%
% handle all AST cases:
% var(N,T,I,A) - Name, Type, Initializer, Attrib -- variable declaration
% lit(V,T) - Value, Type -- literal with type
% id(N) - Name -- identifier
% constraint(C,A) - Constraint, Attrib -- constraint
%
% variables with an initializer are treated as SSA & will now stand for
% the literal in the initializer itself.
sa_n(var(N,T,[],A), V, ST) :- !,
sa_attribs(A, AX, ST),
V=var(N,T,[],AX), % new AST node becomes ST entry value
st_insert(ST, N, V).
sa_n(var(N,T,I,A), NI, ST) :- % non-empty initializer
sa_attribs(A, AX, ST), % should ignore this?
sa_n_traverse(I, NI, ST), % parse initializer
V=var(N,T,NI,AX), % new AST node becomes ST entry value
st_insert(ST, N, V).
sa_n(lit(E,array(T)), lit(NE, array(T)), ST) :-
sa_n_traverse(E, NE, ST).
sa_n(lit(E,int), lit(E,int), _ST).
sa_n(lit(E,float), lit(E,float), _ST).
sa_n(lit(E,string), lit(E,string), _ST).
sa_n(id(N), V, ST) :- st_lookup(ST, N, V), !.
sa_n(id(N), V, ST) :- V=var(N,_,_,_), % type as yet unknown
st_insert(ST, N, V).
sa_n(constraint(CE, AT), constraint(NCE, AT), ST) :-
CE=..[C|AS],
sa_n_traverse(AS, NAS, ST),
NCE=..[C|NAS].
% - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
% == TYPES ====================================================================
% -- sa_types(AST, ST) --------------------------------------------------------
%
% sa_types/2: do type analysis (traverse AST enforcing type correctness).
% as a side-effect, it will do type inference.
sa_types(fzn(_PS, vars(VS), constrs(CS), _S), ST) :-
sa_t_traverse(VS, ST),
sa_t_traverse(CS, ST).
% -----------------------------------------------------------------------------
sa_t_traverse([], _ST) :- !.
sa_t_traverse([N|Ns], ST) :-
sa_t(N, ST), !,
sa_t_traverse(Ns, ST).
sa_t_traverse([_|Ns], ST) :- !, % ignore failing nodes (beware!)
sa_t_traverse(Ns, ST).
sa_t_traverse(N, ST) :- sa_t(N, ST). % non-list case
% -- sa_t(NODE, ST) -----------------------------------------------------------
sa_t(var(_N,T,I,_A), _ST) :- type(I,T).
sa_t(lit(E,T), _ST) :- type(lit(E,T), T).
sa_t(constraint(CE, _AT), ST) :-
CE=..[_|AS],
sa_t_traverse(AS, ST).
% =============================================================================
sa_attribs([A|As], [NA|NAs], ST) :-
sa_attrib(A, NA, ST), !,
sa_attribs(As, NAs, ST).
sa_attribs([_|As], NAs, ST) :- % ignore unknown attributes
sa_attribs(As, NAs, ST).
sa_attribs([], [], _).
sa_attrib(id(output_var), output, _).
% -----------------------------------------------------------------------------