source: to-imperative/trunk/compiler/src/rfp_const.rf @ 3539

Last change on this file since 3539 was 3539, checked in by yura, 13 years ago
  • Files are moved in src dir.
  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 20.4 KB
Line 
1// $Source$
2// $Revision: 3539 $
3// $Date: 2008-03-15 20:05:22 +0000 (Sat, 15 Mar 2008) $
4
5$use Access Arithm Box List StdIO Table;
6
7
8/*
9 * Во время компиляции каждого модуля все статические константые выражения
10 * складываются в ящик
11 */
12$box Static;
13/*
14 * Каждое выражение представлено термом вида (t.name expr).
15 */
16
17
18
19Init_Consts = <Store &Static /*empty*/>;
20
21
22
23Create_Static {
24  /*empty*/ = /*empty*/;
25  (REF t.name) = (REF t.name);
26  expr = {
27    <Get &Static> : e (t.name expr) e =
28      (STATIC t.name);  // FIXME: Add comment?
29    (<Length <Get &Static>>) :: t.name,
30      <Put &Static (t.name expr)>,
31      (STATIC t.name);
32  };
33};
34
35
36
37Get_Static (STATIC t.name), <Get &Static> : e (t.name expr) e = expr;
38
39
40
41/*
42 * Накопленные в процессе компиляции модуля константные выражения лежат в
43 * &Static.  Теперь необходимо отобразить их в CONSTEXPR из ASAIL.
44 * Эта форма имеет следующий синтаксис:
45 *
46 * t.const         ::= (CONSTEXPR s.linkage t.name (e.comment) e.const-expr)
47 * s.linkage       ::= EXPORT | LOCAL
48 * t.name          ::= t.QualifiedName | (STATIC t.QualifiedName)
49 * e.const-expr    ::= e.compound-expr | e.subexpr
50 * e.compound-expr ::= [empty] | t.const-term e.const-expr
51 * t.const-term    ::= s.symbol | (PAREN e.const-expr)
52 *                              | (REF t.QualifiedName)
53 *                              | (STATIC t.QualifiedName)
54 * e.subexpr       ::= (SUBEXPR t.name s.pos s.len)
55 * s.pos, s.len    ::= [int]
56 *
57 * e.comment содержит выражение в том виде, в котором оно встретилось в
58 * Рефал-программе.  Может быть полезным для получения более читабельной
59 * программы на императивном языке.
60 *
61 * REF -- ссылка на $const'анту или объект.
62 *
63 * STATIC -- обозначение константного статического выражения.
64 *
65 *
66 * Выражения из &Static должны создаваться после того, как объявлены все
67 * функции, объекты и константы, потому что могут ссылаться на них.
68 * Они также ссылаются друг на друга, с целью минимизации ресурсов, требуемых
69 * на их хранение.  Если выражение встречается как подвыражение в другом, то
70 * оно должно являться просто ссылкой.  Несколько примеров того, как надо
71 * заводить константы с учётом этого правила:
72 *
73 * 1. ABCD, ABC            --> ABC должно заводиться после ABCD, как подвыражение.
74 *
75 * 2. A(BCD)E, BC          --> BCD, затем A(BCD)E, затем BC, как подвыражение BCD.
76 *
77 * 3. A(BC(DE)FG)H, E      --> DE, затем A(BC(DE)FG)H, затем E.
78 *
79 * 4. A(BC(DE)FG)H, C(DE)F --> BC(DE)FG, затем A(BC(DE)FG)H, затем C(DE)F.
80 *
81 * 5. (AB)(ABC)(BC)        --> ABC, затем (AB)(ABC)(BC), причём AB и BC -- ссылки на ABC.
82 *
83 *
84 * Итак, если из двух имеющихся выражений одно является подвыражением другого,
85 * то первым делом заводится минимальное выражение в скобках, содержащее
86 * подвыражение, а искомые выражения получаются из него либо операцией SUBEXPR,
87 * либо одеванием скобок и конкатенацией.
88 *
89 * Для каждого подвыражения в скобках: если оно является подвыражением верхнего
90 * уровня какого-нибудь другого выражения или подвыражения в скобках, то
91 * сначала заводится выражение, содержащее его на верхнем уровне.
92 *
93 *
94 * Обеспечивать такую схему будем в два приёма.  Сначала выпишем все выражения,
95 * которые необходимо завести, а затем определим порядок их заведения,
96 * удовлетворяющий зависимостям между ними.
97 *
98 * На первом шаге все статические выражения, и все их подвыражения в скобках
99 * выписываются в табличку
100 */
101$table St_Table;
102/*
103 * Ключами являются сами выражения.  Значения имеют следующий вид:
104 *
105 * e.value ::= t.expr-name (e.context) (e.position)
106 * t.expr-name ::= () | ([int])
107 * e.context ::= expr
108 * e.position ::= [empty] | s.pos s.len expr
109 *
110 * Пустое имя означает, что это выражение вспомогательное, нужное для
111 * обеспечения выше приведённых правил, и нормальное имя для него будет
112 * необходимо сгенерировать в случае, если его действительно потребуется
113 * завести.
114 *
115 * e.context -- это уровень в объемлющем выражении, содержащий наше.  Например,
116 * если наше выражение -- это A B, входящее в X (Y (A B) (Z (Z))) X, то
117 * контекстом будет Y (A B) (Z (Z)).  Это поле нужно для определения выражений,
118 * которые всегда используются в одном и том же контексте и, следовательно, не
119 * требуют заведения.  Пустой контекст означает, что выражение используется в
120 * разных ситуациях.  Выражение необходимо завести тогда и только тогда, когда
121 * контекст пуст.
122 *
123 * e.position -- это координаты для тех выражений, которые являются
124 * подвыражениями каких-либо других.  Такие выражения необходимо заводить после
125 * тех, на которые они ссылаются.
126 *
127 *
128 * Опишем рекурсивный алгоритм раскладывания очередного выражения по табличке.
129 */
130$func Bind_Subexprs s.Isnew t.expr_name (e.context) (e.current) expr = s.Isnew;
131/*
132 * Будем искать подвыражения среди уже имеющихся в табличке, начиная с самых
133 * глубоких.  Если на каком-то уровне окажется, что такого подвыражения в
134 * табличке ещё не было (оно новое), значит там нет и никакого подвыражения
135 * более высокого уровня.  Эту информацию будем хранить в s.new?, и она поможет
136 * нам сэкономить на просмотрах имеющейся таблицы.
137 *
138 * Если s.new? есть Old, значит есть вероятность, что текущее выражение в
139 * табличке уже имеется.  Если New, значит текущее выражение новое, в табличке
140 * его точно нет.
141 *
142 * Возвращает функция также флаг s.new?, показывающий удалось ли найти текущий
143 * уровень в табличке, и надо ли, соответственно, искать там следующий уровень.
144 *
145 * e.context -- контекст текущего уровня.
146 *
147 * e.current -- текущий уровень.
148 *
149 * expr -- остаток текущего уровня, который надо просмотреть на предмет
150 * подвыражений.
151 *
152 * Для проверки того, что выражение e1 является подвыражением в скобках для
153 * выражения e2 (откуда следует, что e1 не может быть заведено после e2), далее
154 * используется функция
155 */
156$func? IsSubexpr (e1) e2 = ;
157
158IsSubexpr (e1) e2, \{
159  e1 : e2;
160  e2 : e3 (PAREN e4) e5, <IsSubexpr (e1) e4>;
161};
162
163Bind_Subexprs s.Isnew (e.name) (e.context) (e.current) expr, {
164  /*
165   * Прежде всего, заносим в таблицу все подвыражения.  Если какого-то из них
166   * в таблице не оказалось, значит там нет и текущего выражения.
167   */
168  expr : e1 (PAREN e2) e3 =
169    <Bind_Subexprs
170      <Bind_Subexprs Old () (e.current) (e2) e2> (e.name) (e.context) (e.current) e3>;
171  /*
172   * Если все подвыражения оказались в таблице, значит там может оказаться и
173   * весь текущий уровень.
174   * Если его контекст уже пуст, значит он таким и остаётся.
175   * Если он совпадает с текущим контекстом, опять всё остаётся как было.
176   * Если же контекст раньше был иным, значит текущее подвыражение необходимо
177   * заводить.  Его контекст обнуляется.  И мы можем не искать в таблице
178   * следующий уровень (ведь единственный возможный оказался не совпадающим с
179   * контекстом), поэтому возвращаем New.
180   */
181  s.Isnew : Old, <Lookup &St_Table e.current> : (e.tbl_name) (e.tbl_context) t.tbl_pos =
182    {
183      e.tbl_name : /*empty*/ = e.name;
184      e.tbl_name;
185    } :: e.tbl_name,
186    {
187      e.tbl_context : /*empty*/ = e.tbl_context Old;
188      e.tbl_context : e.context = e.tbl_context Old;
189      /*empty*/ New;
190    } :: e.tbl_context s.Isnew,
191    <Bind &St_Table (e.current) ((e.tbl_name) (e.tbl_context) t.tbl_pos)>,
192    s.Isnew;
193  /*
194   * Если известно, что текущего уровня в таблице ещё нет, надо искать в ней
195   * его подвыражения.  Если хотя бы одно такое подвыражение нашлось, значит
196   * текущий уровень необходимо заводить.  Это контролирует флаг s.needed?.
197   *
198   * Однако возможна ситуация, когда найденое подвыражение необходимо для
199   * заведения текущего.  Это проверяется функцией Subexpr?.  Если она не
200   * $fail'ится, значит подвыражение необходимо для построения текущего
201   * уровня и, следовательно, его нельзя заводить вырезанием из него.
202   *
203   * Также, текущий уровень может оказаться подвыражением какого-либо
204   * имеющегося выражения.   Тогда это выражение должно быть заведено,
205   * поэтому его контекст обнуляется.  Позиция текущего уровня в этом
206   * выражении запоминается в t.pos.
207   * Если про текущее выражение известно, чо оно новое, то такой ситуации
208   * быть не может.
209   */
210  <Domain &St_Table> "Not-Needed" () $iter {
211    e.domain : (e.key) e.rest, {
212      <Lookup &St_Table e.key> : e.tbl_params (),
213        e.current : e1 e.key e2,
214        # <IsSubexpr (e.key) e.current> =
215        <Bind &St_Table (e.key)
216          (e.tbl_params (<Length e1> <Length e.key> e.current))>,
217        e.rest Needed t.pos;
218      s.Isnew : Old, t.pos : (), e.key : e1 e.current e2 =
219        <Lookup &St_Table e.key> : t.tbl_name t.tbl_context t.tbl_pos,
220        <Bind &St_Table (e.key) (t.tbl_name () t.tbl_pos)>,
221        e.rest s.Isneeded (<Length e1> <Length e.current> e.key);
222      e.rest s.Isneeded t.pos;
223    };
224  } :: e.domain s.Isneeded t.pos,
225    e.domain : /*empty*/ =
226    {
227      s.Isneeded : Needed = /*empty*/;
228      e.context;
229    } :: e.context,
230    <Bind &St_Table (e.current) ((e.name) (e.context) t.pos)>,
231    New;
232};
233
234/*
235 * Выражение из &Static кладётся в таблицу с помощью функции:
236 */
237$func Bind_Static e = e;
238
239Bind_Static (t.name expr) = <Bind_Subexprs Old t.name () (expr) expr> : e;
240
241/*
242 * Теперь перейдём ко второму этапу -- составлению списка нужных выражений в
243 * виде форм CONSTEXPR.
244 *
245 * Для заведения новых имён нам понадобиться свободный индекс.
246 */
247$box FreeIdx;
248/*
249 * Функция
250 */
251$func Name e.idx = t.name;
252/*
253 * Получает индекс -- тогда она делает имя из него, либо пустое выражение --
254 * тогда она генерирует незанятый индекс, после чего делает из него имя.
255 */
256Name {
257  /*empty*/ =
258    <Get &FreeIdx> : s.free,
259    <Store &FreeIdx <Arithm.Add s.free 1>>,
260    (STATIC (s.free));
261  s.idx =
262    (STATIC (s.idx));
263};
264
265/*
266 * Функция
267 */
268$func Subexprs_To_Constexprs expr = (e.constexprs) e.const_expr_or_its_name;
269/*
270 * Возвращает список всех форм CONSTEXPR, которые нужны для заведения выражения
271 * expr (т.е. форму, соответствующую expr, а также все, на которые она
272 * ссылается, и которые не были заведены раньше).  Если expr необходимо
273 * заводить как именованное выражение, то его форма включается в e.constexprs и
274 * вторым параметром возвращается сгенерированное имя.  Иначе, второй
275 * параметр -- это форма, соответствующая expr.
276 *
277 * Заведённые выражения помечаются как Constructed в таблице &St-Table.
278 *
279 * На случай, если пустое выражение попало в табличку, обрабатываем его
280 * отдельно.
281 */
282Subexprs_To_Constexprs {
283  /*empty*/ = () /*empty*/;
284  expr, <Lookup &St_Table expr> : {
285    Constructed e.const = () e.const;
286    (e.name) (e.context) (e.pos) =
287      {
288        e.pos : s.left s.len e.source =
289          <Subexprs_To_Constexprs e.source> :: (e.constexprs) e.source,
290          (e.constexprs) (SUBEXPR e.source s.left s.len);
291        expr () () $iter {
292          expr : e1 (PAREN e2) e3 =
293            <Subexprs_To_Constexprs e2> :: (e2_consts) e2,
294            e3 (e.constexprs e2_consts) (e.const e1 (PAREN e2));
295          /*empty*/ (e.constexprs) (e.const expr);
296        } :: expr (e.constexprs) (e.const),
297          expr : /*empty*/ =
298          (e.constexprs) e.const;
299      } :: (e.constexprs) e.const,
300      {
301        e.context : /*empty*/ =
302          <Name e.name> :: t.name,
303          (e.constexprs (CONSTEXPR LOCAL t.name (expr) e.const)) t.name;
304        (e.constexprs) e.const;
305      } :: (e.constexprs) e.const,
306      <Bind &St_Table (expr) (Constructed e.const)>,
307      (e.constexprs) e.const;
308  };
309};
310
311/*
312 * Выражение из &Static преобразуется в список CONSTEXPR-форм (для него, и всех
313 * необходимых ему) с помощью функции:
314 */
315$func Static_To_Constexprs e.static_expr = e.constexprs;
316
317Static_To_Constexprs (t.name expr) =
318  <Subexprs_To_Constexprs expr> :: (e.constexprs) e = e.constexprs;
319
320/*
321 * Теперь, проинициализировав таблицу и свободный индекс, мы можем
322 * сгенерировать список всех CONSTEXPR-форм.
323 */
324Comp_Consts =
325  <ClearTable &St_Table>,
326  <Store &FreeIdx <Length <Get &Static>>>,
327  <Map &Bind_Static (<Get &Static>)> : e,
328  <Map &Static_To_Constexprs (<Get &Static>)>;// : e,
329//  {
330//    <Domain &St-Table> : e (e.key) e,
331//      <WriteLN e.key '--->' <Lookup &St-Table e.key>>,
332//      $fail;;
333//  };
334
335
336
337// /*
338//  * После того, как все нужные объекты скомпилированы, в &Static находится
339//  * список всех используемых в них статических выражений и констант.  Необходимо
340//  * для каждого выражения завести переменную (все переменные, кроме
341//  * экспортируемых констант должны быть статическими).
342//  *
343//  * В ASAIL эти переменные представляются так:
344//  *
345//  * t.const      ::= (CONSTEXPR s.linkage t.name (e.comment) e.const-expr)
346//  * s.linkage    ::= STATIC | EXTERN
347//  * e.const-expr ::= [empty] | t.path | t.const-term e.const-expr
348//  * t.const-term ::= s.symbol | (PAREN e.const-expr)
349//  * t.path       ::= (PATH t.ref-name e.path-expr)
350//  * e.path-expr  ::= (L s.pos) e.path-expr | (E s.pos s.len)
351//  * s.pos, s.len ::= [int]
352//  *
353//  * e.comment содержит выражение в том виде, в котором оно встретилось в
354//  * Рефал-программе.  Может быть полезным для получения более читабельной
355//  * программы на императивном языке.
356//  *
357//  * t.path необходим для минимизации ресурсов, расходуемых на заведение
358//  * констант.  Эта часть ASAIL (и соответствующая часть компилятора) является
359//  * сугубо специфичной для векторного представления выражений с подвешенными
360//  * скобками.  Для спискового ран-тайма такое представление констант будет
361//  * вопиюще неэффективным.
362//  * FIXME: возможно, стоит вынести представление констант за ASAIL.  Оставить в
363//  * нём просто список всех употреблённых в программе константных выражений с
364//  * именами, и предоставить бек-энду разбираться с их представлением.
365//  * Тогда все нижеследующие функции, начиная с Compile-Static переедут в rfp_asail.
366//  *
367//  * t.path представляет из себя ссылку на подвыражение ранее определённого
368//  * выражения t.ref-name.  Эта ссылка формирует либо новое выражение целиком,
369//  * либо его часть, подвешенную в скобках.
370//  *
371//  * Ссылка строится по следующим правилам: сначала идёт несколько (м.б. ни
372//  * одного) термов вида (L s.pos) (от слов Left, Length), означающих, что надо
373//  * залезть в скобки, находящиеся на расстоянии s.pos от начала текущего уровня
374//  * (считая слева); затем идёт ровно один терм (E s.pos s.len) (от слов Expr,
375//  * End), означающий, что искомое подвыражение начинается в позиции s.pos
376//  * текущего уровня, и имеет длину s.len.
377//  *
378//  * Основная функция, обрабатывающая &Static, и выдающая список констант в
379//  * описанном выше виде:
380//  */
381// $func Compile-Static = e.asail-const-expressions;
382// /*
383//  * Она берёт выражения из &Static и по одному добавляет их к списку уже
384//  * обработанных, нужным образом модифицируя этот список.
385//  *
386//  * Функция, добавляющая одно выражение к списку, называется
387//  * $func Add-Static-Expr (t.name e.expr) e.static-exprs = e.new-static-exprs
388//  */
389// $func Add-Static-Expr e = e;
390// /*
391//  * В списке обработанных выражений (e.static-exprs) каждое выражение "помнит" о
392//  * всех своих подвыражениях, которые надо завести.  К списку констант его
393//  * преобразует функция
394//  */
395// $func Static-To-Const-Exprs e.static-exprs = e.asail-const-expressions;
396// /*
397//  * Для каждого выражения, она обрабатывает все его подвыражения непосредственно
398//  * за ним.  Так как одно и то же выражение может быть подвыражением нескольких
399//  * других выражений, необходимо помнить имена уже полученных констант, чтобы не
400//  * завести какую-нибудь константу несколько раз.  Для этого имена обработанных
401//  * выражений складываются в ящик
402//  */
403// $box Const-Exprs;
404//
405// Compile-Static =
406//      <Foldr &Add-Static-Expr () (<? &Static>)> :: e.static-exprs,
407//      <WriteLN e.static-exprs>,
408//      <Store &Const-Exprs /*empty*/>,
409//      <WriteLN <Static-To-Const-Exprs e.static-exprs>>;
410// /*
411//  * Список e.static-exprs состоит из термов вида
412//  * (t.expr-name (e.subexprs) e.expr), где e.expr -- обычное выражение,
413//  * состоящее из символов, ссылок и скобок, в начале каждого уровня которого
414//  * может идти терм (S e.labels), где
415//  * e.labels ::= [empty] | t.label
416//  * t.label  ::= (t.name s.pos s.len)
417//  *
418//  * e.subexprs -- список _обычных_ (без S-термов) выражений, имена которых
419//  * встречаются в e.labels в e.expr.
420//  *
421//  * Для того, чтобы определить, является ли данное _обычное_ выржение ey
422//  * подвыражением _статического_ (с S-термами) выражения ex есть функция:
423//  */
424// $func? Subexpr? (ex) (ey) t.y-name = e.x-with-ey-label;
425// /*
426//  * Она ищет в ex уровень, подвыражением которого является ey, и вставляет в
427//  * начало этого уровня соответствующую метку.  Если ey не является
428//  * подвыражением ex, то функция выдаёт $fail.
429//  */
430// Subexpr? (ex) (ey) t.name =
431//      {
432//              ex : (S e.labels) e.xe = (e.labels) e.xe;
433//              () ex;
434//      } :: (e.labels) ex,
435//      {
436//              ex : e1 ey e2 = (S e.labels (t.name <Length e1> <Length e.y>)) e.x;
437//              ex : e1 (PAREN ez) e2 = (S e.labels) e1 (PAREN <Subexpr? (ez) (ey) t.name>) e2;
438//              = $fail;
439//      };
440// /*
441//  * Функция
442//  */
443// $func Find-Subexprs (ey) exprs = (e.y-with-labels) (e.subexprs) e.not-subexprs;
444// /*
445//  * берёт выражение ey (в общем случае _статическое_) и список _обычных_
446//  * выражений exprs.
447//  * Она находит в ey все подвыражения из exprs, вставляет в него соответствующие
448//  * e.labels, и возвращает полученное ey, список выражений из exprs, являющихся
449//  * подвыражениями ey, и список остальных выражений из exprs.
450//  */
451// Find-Subexprs {
452//      (ey) (t.xn ex) e.rest, {
453//              <Find-Subexprs (<Subexpr? (ey) (ex) t.xn>) e.rest> :: (ey) (e.subexprs) e.not-sub =
454//                      (ey) ((t.xn ex) e.subexprs) e.not-sub;
455//              <Find-Subexprs (ey) e.rest> :: (ey) (e.subexprs) e.not-sub =
456//                      (ey) (e.subexprs) (t.xn ex) e.not-sub;
457//      };
458//      (ey) /*empty*/ = (ey) () /*empty*/;
459// };
460// /*
461//  * Для того, чтобы добавить выражение из &Static к списку e.static-exprs,
462//  * необходимо произвести следующие действия:
463//  *
464//  * 1) Проверить, не является ли данное выражение подвыражением какого-либо из
465//  *    уже имеющихся в списке.  Подвыражения хранятся в списке правее, чем их
466//  *    хозяева, поэтому проверять надо справа на лево.
467//  * 2) Пусть нашлось выражение ex, содержащее наше.  Никакое из уже имеющихся
468//  *    его подвыражений наше не содержит.  Остаётся проверить, не содержит ли
469//  *    наше выражение какие-нибудь из них.  После этого подвыражениями ex
470//  *    являются только выражения, не являющиеся подвыражениями нашего, и само
471//  *    наше выражение.  Добавляем в список наше выражение сразу после ex.
472//  * 3) Если наше выражение не является подвыражением никакого из имеющихся, надо
473//  *    проверить, какие выражения являются подвыражениями нашего.  Для этого
474//  *    нужна их "чистая" форма (без S-термов).  Она берётся заново из &Static.
475//  *    Т.к. Add-Static-Expr применяется в Compile-Static посредством Foldr, и на
476//  *    каждое обрабатываемое выражение в e.static-exprs заводится ровно один
477//  *    терм, нужные нам выражения лежат в правом конце &Static, и их кол-во
478//  *    равняется длине имеющегося на данный момент списка.
479//  */
480// Add-Static-Expr (t.yn ey) exprs, {
481//      exprs : $r e1 (t.xn (e.subexprs) ex) e2,
482//              <Subexpr? (ex) (ey) t.yn> :: ex =
483//              <Find-Subexprs (ey) e.subexprs> :: (e.y-expr) (e.y-subexprs) e.subexprs,
484//              e1 (t.xn (e.subexprs (t.yn ey)) ex) (t.yn (e.y-subexprs) e.y-expr) e2;
485//      <Find-Subexprs (ey) <Right 0 <Length exprs> <? &Static>>> :: (ey) (e.subexprs) e =
486//              (t.yn (e.subexprs) ey) exprs;
487// };
488// /*
489//  *
490//  *
491//  */
492// Static-To-Const-Exprs {
493//      (t.name t expr) e.rest =
494//              {
495//                      t.name : (Extern t.n) = Extern t.n;
496//                      Static t.name;
497//              } :: s.linkage t.name,
498//              <Subexprs-To-Const () (t.name) expr> :: expr (e.subexprs),
499//              {
500//                      <? &Const-Exprs> : e t.name e = e.subexprs;
501//                      <Put &Const-Exprs t.name>, (CONSTEXPR s.linkage t.name expr) e.subexprs;
502//      } :: e.const-exprs =
503//              e.const-exprs <Static-To-Const-Exprs e.rest>;
504//      /*empty*/ = /*empty*/;
505// };
506//
507//
508//
509// $func Labels-To-Const (e.path) e.labels = e.const-exprs;
510//
511// Labels-To-Const (e.path) e.labels, e.labels : {
512//      (t.name s.pos s.len) e.rest =
513//              {
514//                      t.name : (Extern t.n) = Extern t.n;
515//                      Static t.name;
516//              } :: s.linkage t.name,
517//              {
518//                      <? &Const-Exprs> : e t.name e;
519//                      <Put &Const-Exprs t.name>,
520//                              (CONSTEXPR s.linkage t.name (PATH e.path (E s.pos s.len)));
521//              } :: e.const-expr,
522//              e.const-expr <Labels-To-Const (e.path) e.rest>;
523//      /*empty*/ = /*empty*/;
524// };
525//
526// $func Subexprs-To-Const (e.subexprs) (e.path) expr = e.const-expr (e.const-subexprs);
527//
528// Subexprs-To-Const (e.subexprs) (e.path) expr =
529//      {
530//              expr : (S e.labels) ex = (<Labels-To-Const (e.path) e.labels>) ex;
531//              () expr;
532//      } :: (e.sub) ex,
533//      ex (/*e.const*/) (e.subexprs e.sub) $iter {
534//              ex : e1 (PAREN e2) e3 =
535//                      <Subexprs-To-Const (e.subexprs) (e.path (L <Length e1>)) e2> :: e2 (e.subexprs),
536//                      e3 (e.const e1 (PAREN e2)) (e.subexprs);
537//              /*empty*/ (e.const ex) (e.subexprs);
538//      } :: ex (e.const) (e.subexprs),
539//      ex : /*empty*/ =
540//      e.const (e.subexprs);
541
Note: See TracBrowser for help on using the repository browser.