Forth и другие саморасширяющиеся системы программирования Locations of visitors to this page
Текущее время: Пт май 23, 2025 08:04

...
Google Search
Forth-FAQ Spy Grafic

Часовой пояс: UTC + 3 часа [ Летнее время ]




Ответить
Имя пользователя:
Заголовок:
Текст сообщения:
Введите текст вашего сообщения. Длина сообщения в символах не более: 60000

Размер шрифта:
Цвет шрифта
Настройки:
BBCode ВКЛЮЧЕН
[img] ВЫКЛЮЧЕН
[flash] ВЫКЛЮЧЕН
[url] ВКЛЮЧЕН
Смайлики ВЫКЛЮЧЕНЫ
Отключить в этом сообщении BBCode
Не преобразовывать адреса URL в ссылки
Вопрос
Теперь гостю придется вводить здесь пароль. Не от своей учетной записи, а ПАРОЛЬ ДЛЯ ГОСТЯ, получить который можно после регистрации на форуме через ЛС.:
Этот вопрос предназначен для выявления и предотвращения автоматических регистраций.
   

Обзор темы - Трансляторы Си в Форт
Автор Сообщение
  Заголовок сообщения:  Re: Трансляторы Си в Форт  Ответить с цитатой
Цитата:
А вообще странно, что они сделали CLEAR/LIST/RUN частью спецификации.

Идём в ногу со временем [сарказм]

Я бы дал этим словам такой функционал
  • CLEAR – очистка кэша
  • LIST – создание списка
  • RUN – запуск сторонней программы из оболочки форта
Сообщение Добавлено: Ср май 07, 2025 17:27
  Заголовок сообщения:  Re: Трансляторы Си в Форт  Ответить с цитатой
Total Vacuum писал(а):
Вот есть такое: https://en.wikipedia.org/wiki/Tiny_BASIC
Грамматика в части операторов там совсем простая:
Код:
    statement ::= PRINT expr-list
                  IF expression relop expression THEN statement
                  GOTO expression
                  INPUT var-list
                  LET var = expression
                  GOSUB expression
                  RETURN
                  CLEAR
                  LIST
                  RUN
                  END

А вообще странно, что они сделали CLEAR/LIST/RUN частью спецификации. Скорее уж это команды редактора или даже операционной системы, но никак не самого языка. Где-то они могут быть полезны (например, при построчном вводе программы через терминал), а где-то полноценный встроенный редактор и запуск по F9, либо внешний редактор и интерпретация или компиляция файлов через командную строку, и вот здесь-то эти команды точно не нужны.
Впрочем, спецификация Tiny BASIC уходит корнями в покрытую мхом почтенную древность, так что простительно. :) В этом даже какой-то шарм безвозвратно ушедшей в прошлое 8-битной эпохи.
Ну а в текущих реалиях надо отделять мух от котлет: редактор (если он вообще нужен) будет отдельно, а интерпретатор (BASIC, Forth, любой другой или все сразу) - отдельно.
Сообщение Добавлено: Ср май 07, 2025 12:01
  Заголовок сообщения:  Re: Трансляторы Си в Форт  Ответить с цитатой
Собственно, лежит тут: http://totalvacuum/UB/ubasic.zip
Сам ubasic.c компилировал при помощи TCC, но должно любым сишным компилироваться. В скомпилированном виде весит 3K. В папке TEST пара тестов, перекомпилируются при помощи соответствующих *.bat по схеме basic => ef => asm => com, хотя можно и под win сделать, если транслятор ef \ esoteric forth \ подменить.
Натравил на него свой сишный транслятор, там меньше 2K исполняемый файл получается, правда это 16-битный com-файл. Для форт-процессора будет и того меньше, раза в 2, наверное.

Интерпретатор в 100 строк, скорее всего, не уложится, он будет сложнее компилятора, но точно не в разы.

Да, кстати, для добавления poke/peek (а это ведь по сути фортовские !/@) достаточно в stmt() перед label дописать строки
Код:
   if (t("poke"))   {expr(); expr(); op(ASSIGN);} else
   if (t("peek"))   {var(); expr(); op(LOAD); op(ASSIGN);} else

А, например, для push/pop:
Код:
   if (t("push"))   {expr();} else
   if (t("pop"))    {var(); op("!");} else

Хотя peek можно оформить в виде функции, чтобы была возможность использования в выражениях. В этом случае нужно добавить в prim() строку
Код:
   else if (t("peek")) {unary(); op(LOAD);}


Забавно будет, если по итогу интерпретатор BASIC на борту Форт-процессора в ПЛИС окажется шустрее спектрумовского :D
Сообщение Добавлено: Вт май 06, 2025 01:33
  Заголовок сообщения:  Re: Трансляторы Си в Форт  Ответить с цитатой
Hishnik писал(а):
Из добавляемого очень уж просятся именованные подпрограммы.
:) И да, есть возможность использования именованных подпрограмм. Например:
Код:
let r = 1
let n = 8
gosub fact
print r
end

fact
   let r = r * n
   let n = n - 1
   if n > 1 gosub fact
return
А всё потому, что поленился сделать обработку ошибок. В результате всё непонятное автоматически считается меткой. Лень - двигатель прогресса, однако. :)
Кроме того, строки не обязаны начинаться с метки, в строке допускается размещать несколько операторов и меток. И наоборот: допускается размещать опкод и операнды на разных строках. Т.е. в каком-то смысле полная свобода в оформлении кода.
Сообщение Добавлено: Пн май 05, 2025 23:26
  Заголовок сообщения:  Re: Трансляторы Си в Форт  Ответить с цитатой
Платформо-зависимые вещи убраны в отдельный файл в шапке:
Код:
#include "x86.h"

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
Транслируется в uf \ micro forth \ и ef \ esoteric forth \ :) При желании можно и напрямую в асм перегонять, достаточно лишь заменить соответствующие дефайны в подключаемом файле.
Например,
Код:
#define ADD    "+"
заменить на что-то вроде
Код:
#define ADD    "pop ax\npop bx\nadd ax,bx\npush ax\n"
и т.д.
В сумме 2 файла занимают ровно 100 строк :)

В версии под ef \ esoteric forth \ нельзя использовать двух- и более- значные числа, а также переменные c/b/h/s/x/o/g (они задействованы в stdio), ну а в остальном отличий нет.
Примеры выложу чуть позже здесь: [url]totalvacuum.ru/UB/ubasic.zip[/url]
Сообщение Добавлено: Пн май 05, 2025 23:13
  Заголовок сообщения:  Re: Трансляторы Си в Форт  Ответить с цитатой
Ну и операторы:
Код:
/* stmt */

void print () {
   token(); hold();
   if (s[0]=='"') {expr(); op(PUTS);} else {expr(); op(PUTH);}
}

int stmt () {
   if (n("")) return 0;
   if (t("print"))  {print();} else
   if (t("if"))     {cmp(); op(IF); stmt(); op(ENDIF);} else
   if (t("goto"))   {token(); printf(JMP,s);} else
/*   if (t("input"))  {var(); op(INPUT);} else */
   if (t("let"))    {var(); token(); expr(); op(ASSIGN);} else
   if (t("gosub"))  {token(); printf(CALL,s);} else
   if (t("return")) {op(RET);} else
/*   if (t("clear")||t("list")||t("run")) {} else */
   if (t("end"))    {op(EXIT);} else
                    {printf(LABEL,s); stmt();}
   return 1;
}

void main () {op(TARGET); while (stmt());}
clear/list/run в режиме "компиляции" не нужны, поэтому убрал. input тоже убрал, т.к. в ПЛИС реализация будет другая, а проверять пока можно и без него.
Сообщение Добавлено: Пн май 05, 2025 22:58
  Заголовок сообщения:  Re: Трансляторы Си в Форт  Ответить с цитатой
Разбор выражений:
Код:
/* expr */

void op (char *s) {printf(CMD,s);}

void expr ();

void prim () {
   if (t("(")) {expr(); token();}
   else {op(s); if ((s[0]>='a')&&(s[0]<='z')) op(LOAD);}
}

void unary () {if (n("-")) {unary(); op(NEGATE);} else prim();}

void mul () {
   unary();
   while (n("*")||t("/")) if (t("*")) {unary(); op(MUL);} else {unary(); op(DIV);}
   hold();
}

void expr () {
   mul();
   while (n("+")||t("-")) if (t("+")) {mul(); op(ADD);} else {mul(); op(SUB);}
   hold();
}

void cmp () {char r[3]; expr(); token(); strcpy(r,s); expr(); op(r);}

void var () {token(); op(s);}
Это следует читать так:
Выражение - это сумма слагаемых, слагаемое - это произведение множителей, множитель - это первичное выражение со знаком или без, а первичное выражение - это выражение в скобках, число или переменная.
Сообщение Добавлено: Пн май 05, 2025 22:53
  Заголовок сообщения:  Re: Трансляторы Си в Форт  Ответить с цитатой
Немного упростил себе жизнь на первом этапе, заменив expr-list и var-list на expr и var соответственно, еще токены пока надо вручную разделять пробелами, ну и then в операторе if убрал за ненадобностью. Все это пока не так принципиально. В итоге набросалось на скорую руку такое:

Сканер (потрошит исходник на отдельные лексемы):
Код:
/* scan */

char h = 0, c, s[32];

int gc () {return c = getchar();}

void hold () {h = 1;}

void token () {
   if (h) {h = 0; return;}
   s[0] = 0;
   while (gc()<'!') if (c==-1) return;
   s[0] = c;
   int p = 1;
   if (c=='"') do s[p++] = gc(); while (c!='"');
   else while (gc()>' ') s[p++] = c;
   s[p] = 0;
}

int t (char *x) {return !strcmp(s,x);}

int n (char *x) {token(); return t(x);}
Сообщение Добавлено: Пн май 05, 2025 22:50
  Заголовок сообщения:  Re: Трансляторы Си в Форт  Ответить с цитатой
Hishnik писал(а):
"не больше 100 строк во всей программе".
Не, ну 100 строк, конечно, маловато, но можно и в них транслятор впихнуть, если не сильно переживать по поводу красивости отступов :D
Сообщение Добавлено: Пн май 05, 2025 22:42
  Заголовок сообщения:  Re: Трансляторы Си в Форт  Ответить с цитатой
Из добавляемого очень уж просятся именованные подпрограммы. GOSUB по номеру строки - это просто уже что-то... на уровне "не больше 100 строк во всей программе".
Сообщение Добавлено: Чт май 01, 2025 16:26
  Заголовок сообщения:  Re: Трансляторы Си в Форт  Ответить с цитатой
В соседней теме зашла речь про Бейсики. Еще одну тему плодить не хочется, а по смысле эта тема ближе.
Вот есть такое: https://en.wikipedia.org/wiki/Tiny_BASIC
Грамматика в части операторов там совсем простая:
Код:
    statement ::= PRINT expr-list
                  IF expression relop expression THEN statement
                  GOTO expression
                  INPUT var-list
                  LET var = expression
                  GOSUB expression
                  RETURN
                  CLEAR
                  LIST
                  RUN
                  END
Понятно, что дословно повторять такое не обязательно, по желанию/необходимости удаляем/меняем/добавляем что угодно. На первый взгляд, оно совсем простое и непригодно для чего-то серьезного, но если добавить хотя бы PEEK/POKE/PUSH/POP/массивы, то сразу же заиграет новыми красками.
В идеале на выходе должен получиться готовый рецепт Бейсика на Си (и, как следствие, на Форте). Реализация должна получиться очень простой, но при этом сможет служить неплохой иллюстрацией того, что транслятор своими руками - это достаточно просто, особенно в случае, когда в качестве целевой платформы используется Форт или что-то близкое к нему по духу.
Сообщение Добавлено: Чт май 01, 2025 14:25
  Заголовок сообщения:  Re: Трансляторы Си в Форт  Ответить с цитатой
Hishnik писал(а):
В целом да, тут две крайности. Можно последовательно воспроизводить все, "как у всех", постоянно натыкаясь на особенности стека. Можно принципиально не делать ничего "как у всех". Истина где-то посередине, как обычно.
Ну я не то, чтобы специально делаю всё нестандартно и наперекор. Но если при реализации какого-то очередного функционала появляется выбор между громоздким, но зато полностью стандартным решением и простым, но не совсем стандартным, то выберу простое. :)
Сообщение Добавлено: Чт апр 17, 2025 14:46
  Заголовок сообщения:  Re: Трансляторы Си в Форт  Ответить с цитатой
Минутка юмора :)
Когда начинал делать транслятор, за основу взял грамматику из стандарта C89.
Но при этом что-то сразу исключил:
- триграфы;
- определения функций в старом стиле K&R;
А что-то сделал не совсем стандартно:
- возможность объявления функций с переменным числом параметров в т.ч. и без обязательного первого (первых) параметра, т.е. вида void f (...);
- поддержка в т.ч. двоичных чисел с префиксом 0b;
- функции вида f() считаются функциями без параметров, а не функциями с неопределенным числом параметров;
- переменные могут объявляться в любом месте блока, а не только в его начале;
Ну и сразу заложил по мелочи что-то из того, что может пригодиться в будущем (например, inline).

Решил глянуть, что там сейчас стандартописатели напридумывали. После стандарта C89 были C99, C11, C17, ну и вроде как самый свежий на сегодня C23.
Понятное дело, что в следующих стандартах добавились inline и возможность объявления переменных в любом месте блока.
И будете смеяться, но в C23:
- убрали функции в стиле K&R и триграфы;
- обязательные параметры в вариадических функциях теперь не требуются, а в макросе va_start второй параметр (как раз тот самый обязательный параметр, про который ломали копья не так давно в этой ветке) не является обязательным, а если даже и указан, то игнорируется;
- добавили поддержку двоичных чисел с префиксом 0b (наконец-то!);
- и да, функции f() - это теперь официально функции без параметров.

Вот и выходит, что пишешь вроде как C89, а получается почему-то C23 :)
Сообщение Добавлено: Чт апр 17, 2025 14:39
  Заголовок сообщения:  Re: Трансляторы Си в Форт  Ответить с цитатой
В целом да, тут две крайности. Можно последовательно воспроизводить все, "как у всех", постоянно натыкаясь на особенности стека. Можно принципиально не делать ничего "как у всех". Истина где-то посередине, как обычно. Удобство стековой модели для ПЛИС в компактном коде, и можно просто учитывать эту особенность, не создавая много параметров специально. А оно часто так и оказывается в простых приложениях, в ПЛИС в основном нужно манипулировать регистрами IP-ядер, и выжимать максимум из процессора совершенно ни к чему.
Сообщение Добавлено: Пт апр 11, 2025 16:13
  Заголовок сообщения:  Re: Трансляторы Си в Форт  Ответить с цитатой
Да, безусловно, аппаратно стековый кадр (или кадровый стек :) ) можно поддержать, предусмотрев нужный функционал в архитектуре и системе команд. Но когда начинал делать компилятор, исходил из того, что нужно не только максимально простое, но и в каком-то смысле универсальное решение, которое должно работать в т.ч. и в самых запущенных случаях, а именно:
- небольшой стек (для локальных переменных в нем просто не хватит места);
- запись в стек только через вершину, прочие ячейки недоступны для записи (если локальные переменные разместить в стеке, не сможем менять их значение);
- примитивная система команд (отдельным командам для работы с кадром стека и сложным режимам адресации здесь не место).
Все написанное выше относится не только к моим Форт-процессорам, но и к разномастным Фортам: если не лезть в бутылку ассемблер и кишки каждой конкретной Форт-системы, то в арсенале у нас лишь небольшое количество милых сердцу каждого фортера слов (dup/drop/...), а стек в общем случае непригоден для хранения локальных переменных.
Да, можно было бы программно реализовать стек данных, чтобы в нем было место и для локальных переменных. Но зачем эти гири на ногах Форт-процессору? Через аппаратный стек ему считать быстрее. Да и какой смысл в точности повторять реализацию стекового кадра из условного x86? Главное, что есть агрументы/результаты/локальные переменные, а как оно там под капотом сделано - не принципиально.
Сообщение Добавлено: Пт апр 11, 2025 11:30

Часовой пояс: UTC + 3 часа [ Летнее время ]


Powered by phpBB © 2000, 2002, 2005, 2007 phpBB Group
phpBB сборка от FladeX // Русская поддержка phpBB