mój nowy język Appes

0

Chcę zrobić nowy, ściśle typowany, obiektowy język funkcji-makr - obiektową nakładkę na dowolny język, używany do tej pory. Zastosowania komercyjne i w szkołach - jak najbardziej ;-). Wymyśliłem nawet nazwę - Appes, zbitka słów apes (małpy) i application. A czemu te małpy? Bo zmienne będą zaczynały się od małpy: @zmienna1. Pomysł jest taki, że pisze się makra-funkcje, z użyciem zmiennych, w języku w miarę naturalnym, a kompilator rozwija je rekurencujnie aż dojdzie do instrukcji #napis, która generuje napis na wyjściu programu. Można generować napisy w dowolnym języku, bo to zwykłe są zwykłe teksty. Tak więc program może sam się skompilować, jeśłi rekurencyjnie wywołując funkcje-makra zejdzie do poziomu asemblera i jeśli jako #napisy będziemy generować kod maszynowy. Ja w przykładach generował będę kod w C. Można nawet w Fortranie, czy przysłowiowym Cobolu ;-).

Wypadałoby napisać kompletny program Hello World w Appesie. Nieliczne słowa kluczowe zaczynają się od podkreślenia:

_code definiuje funkcję-makro, która może zawierać wywołania innych funkcji-makr albo polecenia generowania kodu #.

_use CPrintf;  // wywołaj funkcję-makro _code _use CPrintf{}, wygeneruje tu @includa

start;                 // wywołaj funkcję-makro _code start{}, wygeneruje tu nagłowek funkcji języka C main() i nawias klamrowy {.
przywitaj sie;
stop z sukcesem

_code _use CPrintf
{
#include <stdio.h> // ciało makra. Tu generujemy kod w C, ale możemy też wywoływać inne funkcje-makra ze @zmiennymi
}                         
_code start
{
#int main();
#{
}

_code przywitaj sie
{
#printf("Hello World!\n");
}

_code stop z sukcesem
{
# return 0;
#}
}

w ogólności wywołanie funkcji-makr:

_use Int cena1;
_use StosInt stos1;

wrzuć @cena1 na stos liczb @stos1

sprowadza się do rozwinięcia (albo wywołania jako funkcja, żeby kod się nie rozdął) funkcji-makra:

_code wrzuć Int @liczba na StosInt @stos
{
//... wywołania innych funkcji-makr ze zmiennymi i/lub generowanie kodu wynikowego
}

Typy rozróżniamy od zmiennych i innych fragmentów kodu programu po dużej literze na początku wyrazu.
Zgodnie z przyjętą przeze mnie konwencją definiujemy typy i zmienne za pomocą słowa kluczowego _use. Np:

_use Osoba    // wygeneruje się definicja struct Osoba w języku C, wg ciała funkcji-makra poniżej.

_code _use Osoba
{
#struct Osoba
#{
#char *imie;
#int osoba;
#};
}

analogicznie:

_use Osoba @osoba1

_code _use Osoba @var
{
#struct Osoba @@@var;     // tutaj @@@var oznacza nazwe bez małpy parametru aktualnego w wywołaniu funkcji-makra, czyli osoba1.
                                             // @@var oznaczałoby @osoba1, ale tutaj musimy pozbyć się @ z przodu, dlatego jest @@@var.
}

To na razie tyle, będę pisał więcej wkrótce.

0

Znowu odstawiłeś leki? o_O
Możesz wyjaśnić jaki miałby cel ten twój "rewolucyjny" pomysł? Bo chciałbym przenieść do perełek, ale liczę że jeszcze coś ciekawego napiszesz :)

1

nie widze praktycznego sensu uzywania czegos takiego. A jak bardzo chcesz to mozesz po prostu napisac odpowiednie makra

http://4programmers.net/Forum/C_i_C++/264482-potega_w_kalkulatorze_c++?p=1214208#id1214208

0

Polimorfizm.

ogólnie, dla:

_use Kula
_use Powierzchnia

_code rzuc kulą Kula @K o powierzchnię Powierzchnia @p
{
}

_use Pilka
_use Ściana

_code o sciane Sciana @s rzuc pilka Pilka @p
{
}

definiujemy polimorfizm:

_code o sciane Sciana @s rzuc pilka Pilka @p
_is _code rzuc kulą Kula @p o powierzchnię Powierzchnia @s

teraz mozemy napisac:

_use Pilka @pilka1
_use Sciana @sciana1

rzuc kula @pilka1 o powierzchnie @sciana1

i wykona się:

o sciane @sciana1 rzuc pilka @pilka1

Taki mam pomysł, co do polimorfizmu.

Opiszę później jeszcze 2 rodzaje zmiennych:

@funkcja (kod + lista parametrów formalnych)
@funktor (wskaźnik na kod funkcji i lista parametrów aktualnych, do mapowania z parametrami formalnymi funkcji)
_sync @funkcja @funktor // przypisanie wskaźnika na kod i mapowanie parametrów funktora i funkcji

A le to potem.

0
Shalom napisał(a):

Znowu odstawiłeś leki? o_O
Możesz wyjaśnić jaki miałby cel ten twój "rewolucyjny" pomysł? Bo chciałbym przenieść do perełek, ale liczę że jeszcze coś ciekawego napiszesz :)

Celem jest wypróbowanie koncepcji pisania programów obiektowych w języku naturalnym. A co z tego wyjdzie, to tylko w teleturnieju "Wiem Wszysko" wiedzą. :-)

0

Zagnieżdżone wywołania funkcji-makr:

jesli mamy odpowiednie funkcje-makra aby móc napisac

czytaj @osoba1 z @plik1
zwieksz wiek @osoba1 o 1
zamknij @plik1

to możemy napisać

zwieksz wiek {czytaj ?@osoba1 z @plik1} o 1

albo

zamknij plik {czytaj @osoba1 z ?@plik1}

ogólnie wartością zagnieżdżenia funkcji z użyciem "wskaźnika wartości zwracanej" ?, jest ta właśnie zmienna wskazana znakiem ? z przodu.

{czytaj ?@osoba1 z @plik1} // wykonuje _code czytaj Osoba @o z Plik @p{} i zwraca @osoba1.
{czytaj @osoba1 z ?@plik1} // wykonuje _code czytaj Osoba @o z Plik @p{} i zwraca @plik1.

A co jeśli w zagnieżdżeniu nie wskażemy żadnej zmiennej/literału za pomocą ?.

{czytaj @osoba1 z @plik1}

wtedy w ciele funkcji-makra musi być zwrócona jakaś zmienna/literał za pomocą słowa kluczowego _return

_code czytaj Osoba @o z Plik @p
{
//...
_return @@p; teraz {czytaj @osoba1 z @plik1} zwraca @plik1 @@p jest parametrem aktualnym dla @p
//...
}

Aha, wspomiałem o literałach. Mają taką składnię, jak w przykładach użycia poniżej:

use Int
use StosInt

@liczba = Int'16'
@stos = StosInt'1,2,3,4'

literaly jeszcze muszę przemyśleć.

0
Shalom napisał(a):

Znowu odstawiłeś leki? o_O
Możesz wyjaśnić jaki miałby cel ten twój "rewolucyjny" pomysł? Bo chciałbym przenieść do perełek, ale liczę że jeszcze coś ciekawego napiszesz :)

Dzięki za chęć perełkizacji moich wpisów :-D

3

Ale to co opisałeś to nie jest język naturalny tylko taka dzika składnia po prostu. Popatrz na przykład na: https://en.wikipedia.org/wiki/Shakespeare_Programming_Language tam to jest dopiero ciekawie zrobione.

0
Shalom napisał(a):

Ale to co opisałeś to nie jest język naturalny tylko taka dzika składnia po prostu.

składnia wywolan funkcji-makr jest taka, używając wyrażenia regularnego: ()*

(napis | _slowo_kluczowe | [?]@zmienna | [?]Typ'literal' | { wywolanie })*

napisy mogą być bardzo dowolne, byle nie kolidowały z pozostałymi składnikami wywołania.

Popatrz na przykład na: https://en.wikipedia.org/wiki/Shakespeare_Programming_Language tam to jest dopiero ciekawie zrobione.

Ciekawe!

0

składnia wywolan funkcji-makr jest taka, używając wyrażenia regularnego: ()*

(napis | _slowo_kluczowe | [?]@zmienna | [?]Typ'literal' | { wywolanie })*

napisy mogą być bardzo dowolne, byle nie kolidowały z pozostałymi składnikami wywołania.

wywołaniu odpowiada wykonanie funkcji-makra o sygnaturze:

(napis | _slowo_kluczowe | Typ @parametr_formalny | Typ'@literal' | { wywolanie })*

przy czym dopasowanie wywolania i wykonania musi być dokładne co do joty, typy @zmiennych wywolania muszą być takie same jak Typy @parametrow_formalnych, z wyjątkiem możliwego mapowania polimorficznych funkcji-makr, tak jak opisałem to we wcześniejszym wpisie (Polimorfizm). Ale tam też reguła jest bardzo ścisła.

0
Irek Szpilewski napisał(a):

wywołaniu odpowiada wykonanie funkcji-makra o sygnaturze:

(napis | _slowo_kluczowe | Typ @parametr_formalny | Typ'@literal' | { wywolanie })*

miało być jeszcze _code z przodu:

_code (napis | _slowo_kluczowe | Typ @parametr_formalny | Typ'@literal' | { wywolanie })*
{
// to się wykona
}

3

Jaki problem Twój język rozwiązuje?
Na razie widzę, że raczej stwarza nowy problem: nauczyć się porytej składni. Ale zakładając, że się nauczę - co zyskuję?

0
Irek Szpilewski napisał(a):

składnia wywolan funkcji-makr jest taka, używając wyrażenia regularnego: ()*

(napis | _slowo_kluczowe | [?]@zmienna | [?]Typ'literal' | { wywolanie })*

napisy mogą być bardzo dowolne, byle nie kolidowały z pozostałymi składnikami wywołania.

wywołaniu odpowiada wykonanie funkcji-makra o sygnaturze:

(napis | _slowo_kluczowe | Typ @parametr_formalny | Typ'@literal' | { wywolanie })*

przy czym dopasowanie wywolania i wykonania musi być dokładne co do joty, typy @zmiennych wywolania muszą być takie same jak Typy @parametrow_formalnych, z wyjątkiem możliwego mapowania polimorficznych funkcji-makr, tak jak opisałem to we wcześniejszym wpisie (Polimorfizm). Ale tam też reguła jest bardzo ścisła.

Oczywiście źle napisałem. Najpierw obsługiuje się zagnieżdżenia {wywolanie}, a na koncu wywoluje

_code (napis | _slowo_kluczowe | Typ @parametr_formalny | Typ'@literal')*
{
}

1

Mało mnie interesują takie szczegóły składni na tym etapie. To trochę tak jakby ktoś zapytał, do czego służą klasy w C++, a w odpowiedzi dostał szczegółową listę reguł wyboru przeciążonej metody na podstawie typów argumentów. Nie ten poziom abstrakcji.

Ja chcę wiedzieć, co takiego ten język umożliwia, czego nie potrafią inne języki (których jest mnóstwo)?
Bez tego to wygląda trochę na "solution looking for a problem".

Pomysł jest taki, że pisze się makra-funkcje, z użyciem zmiennych, w języku w miarę naturalnym, a kompilator rozwija je rekurencujnie aż dojdzie do instrukcji #napis, która generuje napis na wyjściu programu. Można generować napisy w dowolnym języku, bo to zwykłe są zwykłe teksty

Wygląda jak opis makroprocesora działającego na poziomie tekstu. Jest już kilka preprocesorów np. preprocesor C, albo potężniejszy m4.
Oba mogą rozwijać makra rekurencyjnie. Oba mogą generować napisy w dowolnym języku, bo są to zwykłe teksty. Fajne na projekt na zaliczenie, ale... gdzie są elementy nowatorskie?

0
Krolik napisał(a):

Mało mnie interesują takie szczegóły składni na tym etapie. To trochę tak jakby ktoś zapytał, do czego służą klasy w C++, a w odpowiedzi dostał szczegółową listę reguł wyboru przeciążonej metody na podstawie typów argumentów. Nie ten poziom abstrakcji.

Ja chcę wiedzieć, co takiego ten język umożliwia, czego nie potrafią inne języki (których jest mnóstwo)?
Bez tego to wygląda trochę na "solution looking for a problem".

Pomysł jest taki, że pisze się makra-funkcje, z użyciem zmiennych, w języku w miarę naturalnym, a kompilator rozwija je rekurencujnie aż dojdzie do instrukcji #napis, która generuje napis na wyjściu programu. Można generować napisy w dowolnym języku, bo to zwykłe są zwykłe teksty

Wygląda jak opis makroprocesora działającego na poziomie tekstu. Jest już kilka preprocesorów np. preprocesor C, albo potężniejszy m4.
Oba mogą rozwijać makra rekurencyjnie. Oba mogą generować napisy w dowolnym języku, bo są to zwykłe teksty. Fajne na projekt na zaliczenie, ale... gdzie są elementy nowatorskie?

Umożliwia pisanie programów w języku zbliżonym do naturalnego, generując kod w dowolnym języku - asemblerze, C, HTML, SQL,..

0

Do tej pory język generował kod jakby w trybie inline, po prostu rozwijał makra. Teraz ogólnie napiszę jak używać funkcji.
Są 2 słowa kluczowe:

_func. // definicja funkcji, a w zasadzie jej prologu i epilogu
_. // wywołanie funkcji - call

po kropkach mozna samemu wpisac nazwe języka, bo w różnych językach różnie się wywołuje funkcje. Języki funkcji i wywołania muszą się zgodzić, inaczej wyjdzie błąd. Domyślnie można nie podawać języka, jeśli używamy tylko jednego. Wtedy można pominąć i kropkę.

przykładowa definicja funkcji:

_func.c
_code otworz Plik @p
{
// kod otwarcia pliku
}

przykładowe wywołanie funkcji:

_.c otworz @plik1

Jak zdefiniować w jednym miejscu epilog i prolog dla funkcji w C? Tutaj:

_code _func.c _Code @kod_funkcji // _Code to kod makra z nazwą, parametrami formalnymi; ma różne metody do odpytywania
{
// Tworzymy nagłówek funkcji w C:
// Tutaj wyciągamy z @kod_funkcji różne dane, jak typ zwracany, zmanglowana nazwa funkcji
// i lista parametrow

  1. @kod_funkcji._retval_type_name;
  2. ' ';
    #@kod_funkcji._name_mangled_base64; // tutaj nazwą kodu będzie otworz_Plik
    #'(';
    #@kod_funkcji._params_to_typed_list;
    #')';
    #'{'
  3. 'return'; #{@kod_funkcji}._returned_name; #';' // wywołujemy kod makra i zwracamy, nazwę tego,
    // co ono samo zwróciło

'}'

}

podobnie jednorazowo definiujemy kod potrzebny do wywołania funkcji w C

_code _.c _Call @wywolanie_funkcji
{
// tu generujemy od razu kod deklaracji i wywolania funkcji podobnie jak w _code _func.c, tyle,
// że korzystamy z obiektu typu _Call, który zawiera parametry aktualne i różne informacje o dopasowaniu
// funkcji, którą trzeba wywołać (także funkcji polimorficznej)
}

W jednym programie mogą koegzystować funkcje _func.c, _func.pascal itd.

0
Krolik napisał(a):

Jaki problem Twój język rozwiązuje?
Na razie widzę, że raczej stwarza nowy problem: nauczyć się porytej składni. Ale zakładając, że się nauczę - co zyskuję?

Taki, że zamiast pisać w C:

stosInt_wstaw(&stos1, liczba1);

piszę

wstaw @liczba1 na @stos1

wg mnie moja wersja jest czytelniejsza, ale oczywiscie nie musisz się z tym zgodzić.

0

Czytelniejsza od której opcji?

stack.push(number)
stack.push number
stack push number
push(number).on(stack)
push (number) on (stack)
0
spartanPAGE napisał(a):

Czytelniejsza od której opcji?
stack.push(number)
stack.push number
stack push number
push(number).on(stack)
push (number) on (stack)



To raczej nie jest kod w C.
0
  1. Tak, te opcje mogą istnieć w C
  2. Po co akurat C? Nie ma co dyskryminować innych języków
0
spartanPAGE napisał(a):
  1. Tak, te opcje mogą istnieć w C
  2. Po co akurat C? Nie ma co dyskryminować innych języków

Jak Ci się nie podoba mój pomysł, to po prostu odpuść i zignoruj temat, a tak obaj tracimy czas na przekomarzanie się.

0

Coś mam niejasne wrażenie, że ktoś tutaj próbuje wymyślić literate programming na nowo.

0

W PIERWSZYM WPISIE BYŁ BŁĄÐ!!!

Irek Szpilewski napisał(a):

w ogólności wywołanie funkcji-makr:

_use Int cena1;
_use StosInt stos1;

wrzuć @cena1 na stos liczb @stos1

> 
> sprowadza się do rozwinięcia (albo wywołania jako funkcja, żeby kod się nie rozdął) funkcji-makra:
> <code>
_code wrzuć Int @liczba na StosInt @stos
{
//... wywołania innych funkcji-makr ze zmiennymi i/lub generowanie kodu wynikowego
}

Powinno być:

_code wrzuć Int @liczba na stos liczb StosInt @stos
0

składnia wywolan funkcji jest taka, używając wyrażenia regularnego: ()*

_[.jezyk] (napis | _slowo_kluczowe | [?]@zmienna | [?]Typ'literal' | { wywolanie })*

wywołaniu odpowiada wykonanie funkcji o sygnaturze:

_func[.jezyk] (napis | _slowo_kluczowe | Typ @parametr_formalny | Typ'@literal' | { wywolanie })*

przy czym dopasowanie wywolania i wykonania musi być dokładne co do joty, język, typy @zmiennych wywolania muszą być takie same jak Typy @parametrow_formalnych, z wyjątkiem możliwego mapowania polimorficznych funkcji-makr, tak jak opisałem to we wcześniejszym wpisie (Polimorfizm). Ale tam też reguła jest bardzo ścisła.</quote>

0

POPRAWKA (czemu tu nie można poprawiać swoich wpisów???)

składnia wywolan funkcji jest taka, używając wyrażenia regularnego: ()*

_[.jezyk] (napis | _slowo_kluczowe | [?]@zmienna | [?]Typ'literal' | { wywolanie })*

Po wykonaniu rekurencyjnym {wywołanie} ostatecznemu wywołaniu odpowiada wykonanie funkcji o sygnaturze:

_func[.jezyk] (napis | _slowo_kluczowe | Typ @parametr_formalny | Typ'@literal' )*

przy czym dopasowanie wywolania i wykonania musi być dokładne co do joty, język, typy @zmiennych wywolania muszą być takie same jak Typy @parametrow_formalnych, z wyjątkiem możliwego mapowania polimorficznych funkcji-makr, tak jak opisałem to we wcześniejszym wpisie (Polimorfizm). Ale tam też reguła jest bardzo ścisła.</quote></quote>

1

Można, ale nie jesteś zalogowany :P Na jakiej podstawie anonim miałby poprawiać swoje wpisy?

0

Bloki kodu, sama idea, bez wgłebiania się w szczegóły

Sekwencje wywolan makr/funkcji mozna zgrupowac w blok kodu za pomocą {[ ]} i definiować sobie własną składnię instrukcji sterujących wykonaniem programu. Blok kodu jest zmienną typu _Code.

jeśli { @a == @b } , to wykonaj:
{[
   // zrób coś
   // zrób coś
   // zrób coś
]}

musimy sobie zdefiniować jak tłumaczymy nasze "jeśli" na kod "if" w C:

_code jeśli Boolean @warunek , to wykonaj: @_Code @kod
{[
# 'if('; # @@'warunek'; # ')'; // nazwa parametru aktualnego makra "jeśli", zmieniłem trochę składnię   
# '{'; 
# @{[kod]}; // emituj kod zawarty w parametrze @kod (kod zawarty w zmiennej typu _Code to @{[zmienna]} 
# '}';   
]}

podobnie można by zdefiniować sobie pętlę for:

dla { ?@i = Int'1' } , {[ @i < Int'4' ]} wykonaj:
{[
   // zrób coś
   // zrób coś
   // zrób coś
]}

_code dla Int @licznik , _Code @kod_warunku_wyjscia_z_petli wykonaj: _Code @kod_ciała_petli
{[
   // definiuj wyjście pętli for lub while w języku C
]}

UWAGA:

zamiast

_code
{
}

zacząłem pisać

_code
{[
]}

aby ujednolicić składnię _code z blokami kodu omawianymi tutaj. Cały czas jeszcze dopracowuję szczegóły języka.
Na razie kończę temat, jak będę miał czas, to może jeszcze coś tutaj dopiszę.

0

Skoro za pomocą mojego języka można definiować własne języki, to myślę, że słowa kluczowe Appesa zaczynały by się od 2 podkreśleń, a nie jednego jak do tej pory, aby jedno podkreślenie zarezerwować, dla składni języka użytkownika. Czyli raczej:

 __code, __use, __Code

Dodałbym też aliasy użytkownika dla słów kluczowych:

'_begin' __is '{['
'_end' __is ']}'

1 użytkowników online, w tym zalogowanych: 0, gości: 1