PDA

View Full Version : Forth :)



crazy-mike
10-08-2018, 07:50 AM
." Hello,World!"
2 2 + .
: HELLO ." Hello,World!" ;
HELLO
VARIABLE A
4 A !
2 B !
A @ B @ + .
VARIABLE C
A @ B @ + C !
C @ .
'C' EMIT
'H' 'E' 'L' 'L' 'O' EMIT O
'H' EMIT 'E' EMIT 'L' EMIT 'L' EMIT 'O' EMIT
'H' D !
D @ EMIT

:111:
Ну нет слов!!!!! Кто же на этом даже пишет!

Птиц
10-08-2018, 07:59 AM
Майки, выпей Клинского и сосредоточься. мне надо собрать новый комп.

системные требования такие:

проц Интел 2,4 Гц или выше
4 гига рэма
терабайт ХДД
видеокарта Нвидиа
Виндоуз 10

и карочи чо выйдет дешевле, системный блок без монитора или ноут с оным.

crazy-mike
10-08-2018, 08:24 AM
Майки, выпей Клинского и сосредоточься. мне надо собрать новый комп.

системные требования такие:

проц Интел 2,4 Гц или выше
4 гига рэма
терабайт ХДД
видеокарта Нвидиа
Виндоуз 10

и карочи чо выйдет дешевле, системный блок без монитора или ноут с оным.

честно - не советуют их собирать ни из чего кроме barebone комплектов. ( там на кучу разной дури напороться можно )

Птиц
10-08-2018, 08:29 AM
честно - не советуют их собирать ни из чего кроме barebone комплектов. ( там на кучу разной дури напороться можно )

карочи, нишаришь. вопщем, карочи, куплю лэптоп Асус с Интел Кор 6000, терабайт хдд, 4 гига рэма, нвидиа, Виндоуз 10 родной, штоб не ...ться, не устанавльвать колотый.

crazy-mike
10-08-2018, 08:38 AM
карочи, нишаришь. вопщем, карочи, куплю лэптоп Асус с Интел Кор 6000, терабайт хдд, 4 гига рэма, нвидиа, Виндоуз 10 родной, штоб не ...ться, не устанавльвать колотый.

лаптоп , может быть , и в самом деле лучше.

Птиц
10-08-2018, 08:54 AM
йа уже просёк фишку.

crazy-mike
10-08-2018, 09:33 AM
йа уже просёк фишку.

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

Птиц
10-08-2018, 09:41 AM
если в самом деле нужно , чтобы много аудио-видео обрабатывал , то обязательно лаптоп с кулером. Ни в коем случае безвентиляторные. Там процессор часто перегревается , когда видео-аудио обрабатывается хоть чем-то - безвентиляторные аварийно перегружаются.

это я уже посмотрел, штобы проц нормально тянул 6-й контакт, это надо в два раза больше денег. мне ща палить штуку баксов чиса ради того штобы слушать новые библы для контакта 6-го, при том, што я на них мифига не делаю, - выброшенные деньги.

crazy-mike
10-08-2018, 10:20 AM
это я уже посмотрел, штобы проц нормально тянул 6-й контакт, это надо в два раза больше денег. мне ща палить штуку баксов чиса ради того штобы слушать новые библы для контакта 6-го, при том, што я на них мифига не делаю, - выброшенные деньги.

если чуть поэкономить хочется - можно mini pc 64-битную попробовать поискать. ( хоть Shuttle-овскую. У GIGABYTE что-то приятное было )

P.S. Но в этой теме ведь в самом деле хочется о Forth поговорить.

crazy-mike
10-29-2018, 08:58 AM
Ну вот можно даже так ( по крайней мере для gforth ):

: 2 7 ; ok
2 2 + . 14 ok

crazy-mike
11-14-2018, 02:55 PM
Ну прикольный язык - на работе пришлось для него начать писать интерпретатор - потому что ничего готового под Cortex M3 не хотело работать. Компилировалось и линковалось нормально - но потом тупо не могло даже свой собственный словарь загрузить.

На github этих "фортов" как бы много - но все чуточку разные.

У меня сначала был критерий выбора - чтобы всё было на С и никакого ассемблера. ( потому что мне собирать при помощи кросс-компилятора всю эту дурь как бы надо было ).

Выбор оказался не таким уж и большим ( из бесплатно-халявно простого для расширения ). Есть очень хороший на http://forth.com/ - со своим IDE и т.д. Но оно всё же платное.

Ну попробовал два разных собрать из исходников -

http://www.softsynth.com/pforth/
https://github.com/philburk/pforth

- очень хороший. Но - он создаёт свой собственный словарь методом самораскрутки. Соответственно не совсем подходит для standalone embedded application.

Нечто Standalone Embedded не должно практически использовать "функции операционной системы" - только что-то из libnano. А ещё у этого pforth структура словаря является machine dependent. Словарь для 32bit mcu не работаёт со словарём для 64bit mcu.

Поэтому пришлось глянуть на https://github.com/zevv/zForth

Понравилось - внешне очень короткий и базовый словарь системы подгружается из обычного текстового файла. Полностью на С и используются функции только stdio и stdlib.
Не понравилось - кое-какие команды не совпадают со "стандартами forth". ( quit вместо bye , var вместо variable и куча другой шизы ).

Для Standalone Embedded конечно же нужно переписать printf , puts , gets - написать свои и подменить имена для ld. ( это если кросс-компилятор gcc использовать ).

Ну провёл все эти манипуляции - собрал всё это при помощи Cube MX. Всё скомпилировалось и даже запустилось - но оказалось , что зараз не может загрузить словарь. Ну а без словаря она ни одного слова языка Forth вообще распознать не может. ( не на embedded , а под qemu тем не менее работала нормально )

Ну - начал искать причину глюка. Оказалось - libnano не обеспечивает работу функций atof, strtod и ещё чего-то для преобразования чисел из строк. Хотя строковые функции в libnano как раз работают правильно. В этом идиотском zForth идентификатор от числа пытались отличить по результату выполнения функции sscanf(buf,"%f", &d) для float d. Если всё нормально - то buf считалось числом. Иначе - идентификатором. Но в этой libnano уже на Cortex M3 sscanf всегда возвращало "всё нормально". И поэтому идентификаторы так вообще нельзя было распознать. Соответственно словарь ( а словарь как раз из идентификаторов и состоит ) нельзя было загрузить.

Короче - надоели они со своими глюками - а для поиска ошибки всё равно пришлось начать кусочек чего-то похожего на интерпретатор этого Forth-а писать. Ну хотя бы - чтобы уточнить причины ошибочной работы того интерпретатора. ( размер используемой памяти ? переполнение стека ? - ну мало ли что. ).

В итоге за два рабочих дня у меня получился свой собственный интерпретатор подмножества Forth - который работает как standalone embedded application.

crazy-mike
11-14-2018, 03:34 PM
для начала с горя пришлось написать что-то такое:



int myNum(char *t) {
int k; int d; int r,p;
d=1; r=0; k=0;
while(t[k]!=0) k++;
while(k>0) {
k--;
p=(int)(t[k]-'0');
r+=p*d; d*=10;
};
return r;
}


Если atoi не поддерживается - то приходится что-то своё сделать.
Ну а дальше самое смешное. Этот Forth кое-кто умудряется классифицировать как "аддикативный" язык программирования. Считается - что т.н. "программа" состоит из последовательности слов. Именно слов , а не "инструкций" ( операторов ). Слово в свою очередь может состоять из других слов. Для этого описание слова заносят в т.н. словарь. Признаком окончания описания слова является точка-с-запятой. ( ; ). И эта точка-с-запятой тоже является словом. Слова между собой разделяются пробелами.

Понятно - что слово де-факто является функцией. Ну есть "стандартные слова" - из "базового словаря системы". Но у нас ведь embedded application - и "базовый словарь" не хочется загружать. Т.е. проще все слова "базового словаря" реализовать напрямую в коде. При этом одним из слов "базового словая" является слово variable - которое используется для создания самых настоящих переменных в этом идиотском языке. Поэтому интерпертировать последовательность слов в этом языке нужно бы примерно так;

1) выбираем лексему ( лексемой здесь является любая последовательность символов между пробелами ).
2) если лексема является числом - заносим получившееся число в стек
3) если лексема не является числом - то ищем лексему в словаре. Если она есть в словаре - выбираем из словаря правила интерпретации лексемы.

Но "есть в словаре" у нас означает или "поддерживается" как "стандартное слово" ( сразу выполняется и при этом вынимает данные из стека или пишет данные в стек ) , или "находится в пользовательском словаре" - ну как бы выполняем соответствующую подпрограмму.. Если оно является именем переменной ( одна из тех , которые ввели по variable ) - тогда заносим ссылку на дескриптор переменной в стек.

Птиц
11-14-2018, 03:39 PM
для начала с горя пришлось написать что-то такое:



int myNum(char *t) {
int k; int d; int r,p;
d=1; r=0; k=0;
while(t[k]!=0) k++;
while(k>0) {
k--;
p=(int)(t[k]-'0');
r+=p*d; d*=10;
};
return r;
}


Если atoi не поддерживается - то приходится что-то своё сделать.

у меня супернаипесдатейший ноутбук Сони, щас таких не делают. я к нему подключаю монитор Сони SHD-968, смарю на нём фильмы и сериалы.

crazy-mike
11-14-2018, 03:54 PM
у меня супернаипесдатейший ноутбук Сони, щас таких не делают. я к нему подключаю монитор Сони SHD-968, смарю на нём фильмы и сериалы.

на полном серьёзе - здесь тема о языке Forth. ( мне чуточку похвастаться хочется - как минимум ). :111:

crazy-mike
11-14-2018, 04:04 PM
Так вот - стек данных как раз в этом языке Forth является чем-то очень интересным. Можно пытаться туда писать "данные как они есть" и дескриптор длины. А можно считать , что стек данных является стеком атомов. Ну и при этом каждый атом является дескриптором данных. Мне вариант "стек атомов" нравится больше - потому что там проще манипулировать с элементами стека.

у дескриптора данных скорее всего должен быть тег типа данных и указатель на место расположения данных. С числовыми данными всё проще - если элементом данных является число , то это число можно писать непосредственно в каком-то поле "атома".



typedef union {
int i; int ref; double f;
} Number;

typedef struct {
Number n;
char xtag;
} Atom;


xtag = тег типа данных. У меня там допустимые значения :



enum Tags {
EOJ = 0, INT = 1, WORD = 2, STD = 3, VARNAME = 4, STRING = 5
};


Строки держатся в отдельной AREA ( хотя её даже логичнее назвать heap. ). Если атом описывает строку - то ref указывает на смещение внутри этой "кучи".
Если атом является "именем переменной" , то ref - индекс в таблице дескрипторов переменных.

В zForth всё было совсем не так. Там дескриптор данных кодировался битами длины данных , а данные и длина заносились в стек.

Дескриптор переменной в таблице переменных может быть таким:



typedef struct {
char xname[16];
int xtag;
union { int ref; int i; double f; } w;
} Xvar;


xtag - тип переменной. ref - ccылка на кучу для строк. i или f - собственно значение переменной числового типа.

crazy-mike
11-14-2018, 04:39 PM
Интерпретатор языка Forth ( обычно ) может находится в двух режимах: непосредственный ввод команд с выполнением команд и добавление описания в пользовательский словарь.

При добавлении описания в пользовательский словарь это описание лучше бы перевести в форму , удобную для выполнения. Другими словами - скомпилировать в "код виртуальной машины".
Код виртуальной машины ведь может быть каким понравится - хоть байт-коды Java-машины или "последовательность команд на виртуальном ассемблере" ( или даже реальные машинные команды в каком-нибудь "позиционно независимом формате" ). Но ведь слова ( "команды" ) языка Forth используют данные из "стека" ( стека атомов ) - поэтому не так уж и сильно нужно придумывать отдельную систему команд виртуально машины. Важно только правильно описать ветвление и циклы ( расставить "переходы" ). Именно к этому и сводится "компиляция" фактически. Соответственно команды виртуальной машины могут пародировать даже какую-нибудь "архитектуру VLIW" ( Very Large Instruction Word ).

В итоге я ограничился "кодословом" :



typedef struct {
int xtag,ok,fail,br;
union { int opcode; int ref; int n; double f; } w;
} Icode;


Ну и откомпилированое слово является в этом случае "последовательностью кодослов". Каждое "кодослово" в этом случае имеет одинаковую длину , но у "кодослова" есть тэг - в зависимости от которого кодослово является или "командой загрузки непосредственного значения в стек" или "командой вызова подпрограммы" или "стандартной командой" или командой конца цепочки команд. При "стандартными командами" являются команды переходов и ветвлений. Для организации ветвлений-перходов используются поля ок,fail,br - куда заносятся "адреса переходов". Адрес перехода - это индекс в последовательности кодослов.

допустимые значения тегов кодослов:


enum Tags {
EOJ = 0, INT = 1, WORD = 2, STD = 3, VARNAME = 4, STRING = 5
};

crazy-mike
11-14-2018, 05:20 PM
Пусть теперь последовательности кодослов находятся в Icode xec[MANY_KILOBYTES] , а стек атомов в Atom pp[]. Указатель стека атомов - ip. Cчётчик команд ( кодослов ) - ic.


тогда цикл интерпретации кодослов , начиная со смещения start может выглядеть примерно так:



ret[nret]=-1; nret++;
for(;;) {
if(xec[ic].xtag==STRING) {
pp[ip].xtag='s'; pp[ip].n.ref=xec[ic].w.ref;
ip++; ic++; continue;
};
if(xec[ic].xtag==EOJ) {
nret--;
if(nret>=0) { ic=ret[nret];
if(ic==-1) { printf("\r\n completed\r\n"); ic=0; break; };
continue;
};
/* printf("\r\n execution completed at %04u\r\n",ic); */
return;
};
if(xec[ic].xtag==VARNAME) {
curvar=xec[ic].w.ref;
ic++; continue;
};
if(xec[ic].xtag==WORD) {
ret[nret]=ic+1; nret++;
ic=xec[ic].br; continue;
};
if(xec[ic].xtag==INT) {
pp[ip].xtag='i';
pp[ip].n.i=xec[ic].w.n; ip++;
ic++; continue;
};
if(xec[ic].xtag==STD) {
rc=goInstruction(xec[ic].w.opcode);
if(!rc) {
if(AbortIP) { printf("\r\n Execution terminated due stack is empty at %04u\r\n",ic);
return;
};
ic++; continue;
};
printf("\r\n illegal opcode at %04u %d\r\n",ic,xec[ic].w.opcode);
break;
};
printf("\r\n illegal opcode! Execution terminated!\r\n"); break;
};

crazy-mike
11-14-2018, 05:29 PM
static const instruction InstructionSet[] = {
{ X_LT, gLT }, { X_GT, gGT }, { X_NE, gNE }, { X_EQ, gEQ }, { X_TYPE, gTYPE }, { X_PUSHVAR, gPUSHVAR },
{ X_SETVAR, gSETVAR }, { X_DOT, gDOT }, { X_PLUS, gPLUS }, { X_MINUS, gMINUS }, { X_MUL, gMUL },
{ X_DIV, gDIV }, { X_EMIT, gEMIT }, { X_CR, gCR }, { X_BL, gBL },
{ X_IF, gIF },{ X_ELSE, gELSE },{ X_THEN, gTHEN },{ X_BEGIN, gBEGIN },{ X_UNTIL, gUNTIL },
{ X_AGAIN, gAGAIN },{ X_LEAVE, gLEAVE },{ X_WHILE, gWHILE },{ X_REPEAT, gREPEAT },
{ X_FOR, gFOR }, { X_NEXT, gNEXT },{ X_SWAP, gSWAP }, { X_DROP, gDROP },
{ -1, NULL }
};

int goInstruction(int command) {
int i;
i=0;
while(InstructionSet[i].code!=-1) {
if(InstructionSet[i].code==command) { InstructionSet[i].cmd(); return 0; };
i++;
};
return -1;
}


тип instruction ведь что-то похожее на:


typedef struct {
const int code; void (*cmd)(void);
} instruction;


code - "код стандартной команды Forth". cmd - функция , которая реализует соответствующую команду.

например: вынимание двух чисел из стека , их сложение и запись результата в стек по +


void gPLUS(void) { pop2(); pp[ip].xtag=a1.xtag; pp[ip].n.i=a1.n.i+a2.n.i; ip++; }


а "conditional statement IF" : :111:



void gIF(void) {
if(ip==0) { AbortIP=1; return; };
pop1();
if(a1.xtag!='i') { AbortIP=1; return; };
if(a1.n.i==1) {
ic=xec[ic].ok-1;
} else {
ic=xec[ic].fail-1;
};
}


Но в поля .ok , .fail и .br нужные для организации переходов значения заносились во время компиляции соответствующей последовательности слов языка Forth.

Например - для слова IF всё заполняется аж поcле компиляции слова THEN и слова ELSE ( если оно есть ). Здесь важно только то , что компиляция очень легко делается за один проход именно благодаря структуре языка Forth.
Если бы хотелось сильно экономить память - можно было бы сделать два или три прохода. В "байт-код Java" мне просто не хотелось - тем более , что для Embedded Application всё равно нужно дописывать вызовы функций для работы с реальной памятью и подключаемыми дивайсами. Под Linux 64bit эта радость занимает 29 K исполняемый файл. bin-файл для Cortex M3 примерно 60 K даже в этом идиотски-расточительном варианте ( и там не только интерпретатор но и дизассемблер ).

crazy-mike
11-15-2018, 09:18 AM
https://concatenative.org/wiki/view/Concatenative%20language

воообще-то не аддикактивный, а конкатенативный язык программирования - Forth так "классифицируют".

реднек
11-21-2018, 09:35 PM
https://concatenative.org/wiki/view/Concatenative%20language

воообще-то не аддикактивный, а конкатенативный язык программирования - Forth так "классифицируют".

Моноиды везде.

crazy-mike
11-22-2018, 11:32 AM
Моноиды везде.

я на этих всех github-овских разозлился и свой вариант Forth нарисовал ( скромненько так назвал - my-forth и даже выделил архитектурно-независимую часть ). Самое прикольное - работает ( массивы - такая хреновина с allot и cells вчера туда вставил ). Но я так и не могу понять - а кто на таком идиотизме всерьёз может программировать хоть что-нибудь ? У нас на работе хотят с его помощью что-то с STM32 делать - и думют почему-то , что это будет проще чем на C.

P.S. Основные возражения у меня как раз к простоте относятся.

crazy-mike
12-05-2018, 10:53 AM
Gforth 0.7.3, Copyright (C) 1995-2008 Free Software Foundation, Inc.
Gforth comes with ABSOLUTELY NO WARRANTY; for details type `license'
Type `bye' to exit
: 2 4 ; ok
2 2 + . 8 ok