Re[5]: Вопрос по макросам
От: VladD2 Российская Империя www.nemerle.org
Дата: 27.04.07 09:47
Оценка: 10 (1)
Здравствуйте, konsoletyper, Вы писали:

K>А тайпбилдера не предусмотрено. Это же макроатрибут уровня сборки.


Я тебе говорю о возможностях "вообще". Ты же не спросил "как сделать то-то, там-то?"?.

K>Это плохо. А если я хочу как-то поработать с классом из другого места?


Какого? В принципе проблем работы с классами нет. Проблемы есть с работой вообще из кода. По уму код макросов уровня выражения не должен вообще создавать побочных эффектов (если конечно ты не далешь их осознанно и понимаешь последствия). Создание или изменение типа (тайпбилдера) — это побочный эффект.

Вот из макро-атриб побочные эффекты можно делать смело.

K>Как мы уже выяснили, макрос имеет синтаксис, несколько отличный от Nemerle, так что без лексемных макросов не обойтись.


Наверно, так.

K> Но лексемные макросы предусмотрены только на уровне выражений.


Да, но выражения предусмотрены не только в телах методов .
Выражения передаются и макро-атрибуту. Незнаю гут ли там быть применены лексические макросы. Скорее всего — да. Если это так, то никаких проблем нет.

K> А я хочу юзать их на уровне макроатрибута, используя обходной путь, описанный ниже. Вот и спрашивается, прежде чем передать PExpr макроатрибуту, будет ли компилятор обрабатывать макросы внутри него?


Несомненно будет. Но думаю, что если код содержит ссылку на лексический макрос, то он будет тупо помещен в специальную конструкцию и доп. обработке не подвергнется. Лексические макросы вообще раскрываются только во время типизации. Так что дума, все будет ОК, но надо пробовать.

K>OK. Пусть имеется что-то вроде:


K>
K>[assembly:BNF(
K>    lexer
K>    {
K>        Identifier ::= Letter (Letter | Digit)*;
K>        subst Letter ::= "a".."z" | "A".."Z";
K>        ...
K>    }
K>)]
K>


K>Макрос lexer развернётся (я этого ожидаю) во что-то вроде:


K>
K>{
K>    ("id", "Identifier", "filename.n", 0, 0, 0, 0); //вместо нулей будет location лексемы
K>    ("assign", "::=", "filename.n", 0, 0, 0, 0);
K>    ("id", "Letter", ...);
K>    ("leftparen", "(", ...);
K>    ...
K>}
K>


K>А потом макрос BNF возьмёт это выражение, проанализирует его и сформирует поток лексем. Далее поток лексем направляется парсеру, формируется AST, по AST генерится спосок регэкспов и т.д.


Слушай, я вот смотрю на то как ты теоретизируешь и не пойму, а почему бы просто не попробовать? Темболее, что сейчас с интеграцией это стало так просто!

В общем, вместо того чтобы рассуждать вместе с тобой, я просто попробовал сам...
И вот что у меня получилось.


Я создал два проекта: MacroLibrary2 и тесовый TestConsoleApplication в котором примаеняются макросы из MacroLibrary2. Поместил их в один солюшен.

Создал два макроса:
1. Bnf — макроатрибут.
2. lexer — лексический макрос. Он нужен, чтобы получить от компилятора набор токенов.

Вот код макро-проекта:
using MacroLibrary2;

using Nemerle; 
using Nemerle.Compiler;
using Nemerle.Collections;
using Nemerle.Utility;
using System.Diagnostics.Trace;

namespace MacroLibrary2
{
  [MacroUsage (MacroPhase.WithTypedMembers, MacroTargets.Assembly, Inherited = true)]
  macro Bnf (expr)
  {
    WriteLine(expr); // это просто чтобы поставить точку останова в отладчике.
  }

  macro lexer (group : Token)
  syntax ("lexer", group)
  {
    def str = group.ToString(); // это тоже чистый fake.
    <[ $(str : string) ]>
  }
}


В тестовом проекте написал:
using System;
using System.Console;
using Nemerle.Utility;
using MacroLibrary2;

[assembly: Bnf(
  lexer
  {
    aaaa ::= bbb* | ccc+;
    bbb ::= xxx*;
  })]

module Program
{
  Main() : void
  {
    _ = ReadLine();
  }
}

Все отлично скомпилировалось.

Далее я сделал активным (в IDE) проект MacroLibrary2 и в его свойствах, на закладке Debug задал в качестве отлаживаемого модуля ncc.exe.
Более конкретно:
Command Arguments =>
Main.n -m:C:\MyProjects\Tests\MacroTest1\MacroLibrary2\bin\Debug\MacroLibrary2.dll > C:\1.TXT
Start Program     => C:\Program Files\Nemerle\NCC.exe
Working Directory => C:\MyProjects\Tests\MacroTest1\MacroLibrary2\..\TestConsoleApplication

Далее я поставил точку останова в макросе Bnf, на строке:
    WriteLine(expr);

и нажал F5.
Далее оставалось поглядеть в окне Locals отладчике чему равно значение параметра expr.
В нем находился вызов PExpr.MacroCall в последнем параметре которого было значение SyntaxElement.RawToken, которое в свою очередь, содержало список токенов конструкции "lexer". Вот что я увидел в отладчике:
- expr  {lexer { aaaa ::= bbb * | ccc + ; bbb ::= xxx * ;  } }                                              => Nemerle.Compiler.Parsetree.PExpr {Nemerle.Compiler.Parsetree.PExpr.MacroCall}
+ name  {lexer}  Nemerle.Compiler.Parsetree.Name
+ ns NamespaceTree.Node: '"MacroLibrary2.lexer"'    Nemerle.Compiler.NamespaceTree.Node
- parms Length = 1: "[{\n  aaaa ::= bbb * | ccc + ;\n  bbb ::= xxx * ;\n  } ]"                              => Nemerle.Core.list<Nemerle.Compiler.Parsetree.SyntaxElement>
    - [0] {{ aaaa ::= bbb * | ccc + ; bbb ::= xxx * ; } }                                                   => Nemerle.Compiler.Parsetree.SyntaxElement {Nemerle.Compiler.Parsetree.SyntaxElement.RawToken}
      + [Nemerle.Compiler.Parsetree.SyntaxElement.RawToken] {{ aaaa ::= bbb * | ccc + ; bbb ::= xxx * ; } } => Nemerle.Compiler.Parsetree.SyntaxElement.RawToken


Так что все что тебе нужно легко достижимо.

Тебе только остается разобрать содержимое переданных в макрос Dnf выражений, распарсить грамматику и создать нуный код.
... << RSDN@Home 1.2.0 alpha rev. 637>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.