Welcome Guest Search | Active Topics | Members | Log In

Templates - procedury szablonowe. Options · View
Kamil W.
Posted: Monday, March 23, 2009 3:29:13 PM
Rank: Newbie

Joined: 3/23/2009
Posts: 3
Points: 9
Location: Warszawa
Witam.
Celem mojej pracy jest zrobienie metod szablonowych znanych między innymi z C++.
Czyli na podstawie funkcji szablonowej:

template <typename T>
T max (T a, T b)
{
return a > b ? a : b;
}

możemy wywoływać funkcje max z najróżniejszymi parametrami:
max(1.2; 1.3);
max(1; 2)
max("ala"; "kot")


Zaimplementowałem już w Odrze mechanizm przeciążenia nazw funkcji, tzn. funkcje są rozróżnialne ze względu na nazwę funkcji, jej parametry i ich kolejność.
przykład:
wyswietl(a:integer)
wyswietl(a:real)
wyswietl(a:Osoba);

Następnie poszedłem w kierunku prekompilacji kodu tak jak w C++, czyli na początku przechodzę drzewo AST i paterze „O wywołanie max(1;2)!”. Więc na podstawie szablonu w magiczny sposób robie procedurę.

Z podejścia tego zrezygnowałem, gównie ze względu na to, że Odra to nie C++, użytkownik może użyć zapytania ad-hoc a w nim: max(1; 2);
A po drugie prekompilator musiałby się bawić na tekście, bo przecież jeszcze żaden moduł ani klasa nie istnieje. Nie wydaje mi się to za najlepszy pomysł.
Ale mimo wszystko cieszę się że tę drogę rozważyłem.


Kolejnym podejściem jest zahaczenie się w SBQLTypeChecker w visitProcedureCallExpression
Czyli w miejscu gdzie następuje związanie nazwy procedury możemy przechwycić wyjątek, ze taka procedura nie istnieje.
Sprawdzić czy istnieje szablon który odpowiada nazwie wywoływanej procedury, jeżeli tak to stworzyć procedurę z szablonu.
I właśnie nad tym stworzenie procedury zastanawiam się jak najlepiej napisać.

Rozwiązanie, które przychodzi mi do głowy:
Jeszcze wcześniej, podczas konstrukcji modułu, czyli w ModuleConstructor dostawiłem visitTemplateDeclaration, które utworzy procedurę o nazwie
np.
$TEMPLATE$_max(T; T)

A skoro jest typ T to muszę zadeklarować klasę T, więc robię:

class T
{
instance Te :
{
}
}

i teraz powracamy do naszego visitProcedureCallExpression
1. Sprawdzamy czy procedura max(int; int) istnieje,
2. Jeżeli nie to sprawdzamy czy $TEMPLATE$_max o dwóch parametrach typu T istnieje
3. Jeżeli tak to kopiujemy ją i podstawiamy za T nasz parametr aktualny czyli integer.
4. Wywołujemy procedurę.

Pytanie moje jest takie:
1 Czy takie myślenie jest dozwolone?
2. Jeżeli tak to, jak zaimplementować podstawienie takich typów?
stencel
Posted: Monday, March 23, 2009 4:11:48 PM

Rank: Advanced Member

Joined: 12/7/2004
Posts: 598
Points: 74
Location: Raszyn
Kamil W. wrote:
template <typename T>
T max (T a, T b)
{
return a > b ? a : b;
}

Zaimplementowałem już w Odrze mechanizm przeciążenia nazw funkcji, tzn. funkcje są rozróżnialne ze względu na nazwę funkcji, jej parametry i ich kolejność.
przykład:
wyswietl(a:integer)
wyswietl(a:real)
wyswietl(a:Osoba);


Czegos tu nie rozumiem. Przeciazanie to zupelnie cos innego niz template. To pewnie jest jakies nieporozumienie. Templatow nie da sie zalatwic przeciazaniem.

Kamil W. wrote:
1 Czy takie myślenie jest dozwolone?


Tak, choc nie wiem po co deklarowac klase kukielke T? T nie jest tu nazwa klasy, ale metazmienna typologiczna. To jest wazne rozroznienie.

Kamil W. wrote:
2. Jeżeli tak to, jak zaimplementować podstawienie takich typów?


Moim zdaniem zachodzi tu standardowy przypadek unifikacji. Mamy konkretne typy wywolania i dokonujemy unifikacji z metazmiennymi z szablonu. W ten sposob dostajemy dynamicznie wywolywane templates. To oczywiscie nalezaloby tez dorzucic do kompilacji, bo dynamiczne wiazanie templates jest kosztowne. O unifikacji mozna poczytac tu:

Unifikacja w wikipedii
Kamil W.
Posted: Monday, March 23, 2009 4:42:03 PM
Rank: Newbie

Joined: 3/23/2009
Posts: 3
Points: 9
Location: Warszawa
Bez przeciążenie nie zrobiłbym:
max(1;2)
max(student1; student2)

gdy istnieje już procedura
max(str1: string; str2: string)
{
...
}


Klasa kukiełka T była, ponieważ podczas tworzenie procedury w parametrem T
dostawałem:
Unable to link name 'T'
Dlatego wstawiłem sztuczną klasę, jednocześnie domyślałem się, że tak nie może być.

Dziękuję, poczytam o unifikacji.
Kamil W.
Posted: Sunday, April 19, 2009 2:52:27 PM
Rank: Newbie

Joined: 3/23/2009
Posts: 3
Points: 9
Location: Warszawa
Od kilku dni męczę się z pewnym problemem technicznym, Mianowicie.
Załóżmy, że kod Odra jest bardzo prosty:


Code:
module test2
{
    proc1()
    {
    }
}



W klasie ModuleConstructor (wykorzystywanej podczas budowania modułu) w metodzie visitProcedureDeclarartion
umieszczam testowy kod, odpowiedzialny za utworzenie testowej procedury.

Code:
    NamedTypeDeclaration namdd = new NamedTypeDeclaration(new Name("integer"));
    VariableDeclarationStatement zm = new VariableDeclarationStatement("zmienna", namdd, 1, 1, 1, new IntegerExpression(new IntegerLiteral(88)));
    ProcedureDeclaration myProcedure = new ProcedureDeclaration(new Name("testowaProcedura"), new EmptyArgumentDeclaration(), new ProcedureResult(), zm );
   
    try
    {
        ModuleOrganizer modOrg = new ModuleOrganizer(Database.getModuleByName("admin.test2"), false);
        modOrg.createProcedure(this.createSchemaProcedureInfo(myProcedure));
    }


i to działa. Podczas budowania proc1() zostanie zbudowana ukryta w kodzie testowaProcedura(). Od tej pory mogę sobię ja wywoływać i ogólnie jest ok.



Chciałbym takie sam ekperyment wykonać w SBQLTypeChecker. Do tego celu wybieram visitProcedureCallExpression()

Code:
     IF(jezeli taka procedura jeszcze nie istenije...){

        NamedTypeDeclaration namdd = new NamedTypeDeclaration(new Name("integer"));
        VariableDeclarationStatement zm = new VariableDeclarationStatement("zmienna", namdd, 1, 1, 1, new IntegerExpression(new IntegerLiteral(88)));
        ProcedureDeclaration myProcedure = new ProcedureDeclaration(new Name("testowaProcedura"), new EmptyArgumentDeclaration(), new ProcedureResult(), zm );
       
        try
        {
            ModuleConstructor modOrg = new ModuleConstructor(Database.getModuleByName("admin.test2"));
            modOrg.setConstructedModule(module);
            modOrg.visitProcedureDeclaration(myProcedure, null);
        }
     }


Również moja procedura zostaje stworzona. I podczas wywołania w SBQLTypeChecker widzi ja. Jednakże podczas wywołania pojawia się wyjątek:


java.nio.BufferUnderflowException
at java.nio.Buffer.nextGetIndex(Buffer.java:480)
at java.nio.HeapByteBuffer.getInt(HeapByteBuffer.java:336)
at odra.sbql.debugger.runtime.SBQLInstructionTable.deserialize(SBQLInstructionTable.java:73)
at odra.sbql.debugger.runtime.SBQLInstructionTable.<init>(SBQLInstructionTable.java:37)
at odra.sbql.interpreter.RuntimeEnvironmentManager$ProcedureEnvironmentMetaData.getInstructionTable(RuntimeEnvironmentManager.java:584)
at odra.sbql.interpreter.RuntimeEnvironmentManager.getInstructionTable(RuntimeEnvironmentManager.java:486)
at odra.sbql.interpreter.SBQLInterpreter.getInstructionForCodePosition(SBQLInterpreter.java:2060)
at odra.sbql.interpreter.SBQLInterpreter.error(SBQLInterpreter.java:2045)
at odra.sbql.interpreter.SBQLInterpreter.runCode(SBQLInterpreter.java:1941)
at odra.sbql.interpreter.SBQLInterpreter.runCode(SBQLInterpreter.java:157)
at odra.sbql.interpreter.SBQLInterpreter.runCode(SBQLInterpreter.java:162)
at odra.dbinstance.processes.ServerProcess.doExecution(ServerProcess.java:1281)
at odra.dbinstance.processes.ServerProcess.execSBQL(ServerProcess.java:1499)
at odra.dbinstance.processes.ServerProcess.execSBQL(ServerProcess.java:1547)
at odra.dbinstance.processes.ServerProcess.processRequests(ServerProcess.java:438)
at odra.dbinstance.processes.ServerProcess.feed(ServerProcess.java:313)
at odra.dbinstance.processes.ServerProcess.run(ServerProcess.java:261)




Próbowałem jeszcze w tym samym miejscu (SBQLTypeChecker) utworzyć procedurę w ten sposób:

Code:
                OdraProcedureSchema procedura = new OdraProcedureSchema(procName, procArgs, ast, result);
                ModuleOrganizer org = new ModuleOrganizer(module, false);
                org.createProcedure(procedura);


i również procedura zostaję utworzona, tylko podczasu wywołania dostaję błąd:


odra.sbql.ast.ParserException: Accept unimplemented in 'odra.sbql.ast.terminals.Name'java.nio.BufferUnderflowException
at java.nio.Buffer.nextGetIndex(Buffer.java:480)
at java.nio.HeapByteBuffer.getInt(HeapByteBuffer.java:336)
at odra.sbql.debugger.runtime.SBQLInstructionTable.deserialize(SBQLInstructionTable.java:73)
at odra.sbql.debugger.runtime.SBQLInstructionTable.<init>(SBQLInstructionTable.java:37)
at odra.sbql.interpreter.RuntimeEnvironmentManager$ProcedureEnvironmentMetaData.getInstructionTable(RuntimeEnvironmentManager.java:584)
at odra.sbql.interpreter.RuntimeEnvironmentManager.getInstructionTable(RuntimeEnvironmentManager.java:486)
at odra.sbql.interpreter.SBQLInterpreter.getInstructionForCodePosition(SBQLInterpreter.java:2060)
at odra.sbql.interpreter.SBQLInterpreter.error(SBQLInterpreter.java:2045)
at odra.sbql.interpreter.SBQLInterpreter.runCode(SBQLInterpreter.java:1941)
at odra.sbql.interpreter.SBQLInterpreter.runCode(SBQLInterpreter.java:157)
at odra.sbql.interpreter.SBQLInterpreter.runCode(SBQLInterpreter.java:162)
at odra.dbinstance.processes.ServerProcess.doExecution(ServerProcess.java:1281)
at odra.dbinstance.processes.ServerProcess.execSBQL(ServerProcess.java:1499)
at odra.dbinstance.processes.ServerProcess.execSBQL(ServerProcess.java:1547)
at odra.dbinstance.processes.ServerProcess.processRequests(ServerProcess.java:438)
at odra.dbinstance.processes.ServerProcess.feed(ServerProcess.java:313)
at odra.dbinstance.processes.ServerProcess.run(ServerProcess.java:261)



Czy da się zatem w SBQLTypeChecker utworzyć procedurę i tak zeby można było ją wołac?

Pozdrawiam
Kamil Wysocki
stencel
Posted: Tuesday, April 21, 2009 8:39:39 AM

Rank: Advanced Member

Joined: 12/7/2004
Posts: 598
Points: 74
Location: Raszyn
Kamil W. wrote:
Czy da się zatem w SBQLTypeChecker utworzyć procedurę i tak zeby można było ją wołac?


Tak. Tu moze wiecej powiedziec Radek Adamus, bo to on zakurat procedury projektowal. W Odrze jest wielofazowa kompilacja i linkowanie. Po stworzeniu procedury musi ona byc skompilowana i podlinkowana pod swoje zaleznosci [ resolve dependancies ]. Przed jej uzyciem trzeba wiec najpierw zawolac odpowiednie metody compile. Prosze zobaczyc jak to wyglada w kodzie tworzacym procedury w

Code:
odra.sbql.parser.OCLSBQLGenerator


To sa metody:

Code:
installMethodBody

Code:
installProcedureBody

radamus
Posted: Tuesday, April 21, 2009 11:54:37 AM

Rank: Advanced Member

Joined: 1/25/2005
Posts: 325
Points: 108
Location: Łódź
Co do błędu, który się pojawia to jest on zapewne wynikiem wstawiania w Typecheckerze węzłów potomnych Declaration.
Ustaw w 'conf/odra-server.properties'
debug.enable = false
To powinno ten problem wyeliminować i będziesz w stanie analizować dalej.

Co do mozności utworzenia nowej procedury podczas typecheckingu, to teoretycznie taka możliwość istnieje, ale wymaga zachowania wszystkich kroków, które normalnie kod wprowadzany do ODRY przechodzi, czyli: dodaj -> linkuj metabazę -> kompiluj. Nie wiem jak na taki proces wpłynie fakt, że wykonujemy go w trakcie fazy "kompiluj".
Tak na prawdę problem rozbija się o linkowanie metabazy, które jest obecnie wykonywane na poziomie obiektu posiadacza (czyli głównie modułu) i polega na inwalidacji wszystkich powiązań a następnie ich regeneracji. Przez powiązanie rozumiem referencję do obiektu reprezentujacego drugi koniec metareferencji wyliczoną na podstawie nazwy tego obiektu.
np. deklaracja

proc():integer {//kod}

jest wprowadzana do ODRY w nastepujących krokach

1. dodaj
AST deklaracji procedury jest analizowane przez Konstruktor i przeksztalcane do formatu pośredniego (...Schema) - schematu Odry w postaci obiektów Java
Schemat ten jest następnie analizowany przez Organizer (metabazy), który tworzy na podstawie tego pośredniego formatu obiekty metabazy. Nie jest to mechanizm dopracowany więc modyfikacja istniejącego schematu jest niebezpieczna (co oznacza w praktyce - poza prostymi przypadkami najlepiej dodawać cały moduł usuwając uprzednio istniejący o tej samej nazwie)! Wprowadzenie oznacza dodanie meta procedury proc, która zawiera m.in. AST kodu. Dodatkowo do tablicy metareferencji zostaje dodana informacja(jeżeli nie istnieje), że istnieje metareferencja prowadząca do obiektu o nazwie 'integer' Metabaza modułu właściciela, jest inwalidowana.

2. linkuj metabazę
Po dokonaniu zmian można zażądać linkowania metabazy. Likowanie w najprostszym wypadku (nie uwzględniając importów) oznacza dowiązanie do nazw w tabeli metareferencji fizycznych obiektów o danych nazwach (np. obiektu reprezentującego typ integer). Linkowanie metabazy jest globalne dla całego modułu.

3. kompiluj
Jeżeli metabaza została poprawnie zlinkowana można rozpocząć procedurę kompilacji, której częścia jest typechecking wewnątrz, którego chcesz dodać nową procedurę.

Rozwiązania, które mi się nasuwają:
1. Zmodyfikować linkowanie tak, żeby można było linkować pojedyncze metareferencje (ale nie wiem na ile jest to możliwe przy obecnych założeniach). Średnio czasochłonne, ale nie wiem czy realizowalne.

2. Zrezygnować z fizycznego linkowania zapisywanego w metabazie i oprzeć się o dynamiczne linkowanie w fazie kompilacji. Oznacza to zrezygnowanie z fazy linkowania i pozostawienie tylko fazy kompilacji. Czasochłonne, realne, potencjalnie uelastyczniające całą ODRĘ.
Users browsing this topic
Guest


Forum Jump
You cannot post new topics in this forum.
You cannot reply to topics in this forum.
You cannot delete your posts in this forum.
You cannot edit your posts in this forum.
You cannot create polls in this forum.
You cannot vote in polls in this forum.

Main Forum RSS : RSS

Powered by Yet Another Forum.net version 1.9.1.6 (NET v2.0) - 11/14/2007
Copyright © 2003-2006 Yet Another Forum.net. All rights reserved.
This page was generated in 0.103 seconds.