Page 2 of 3 FirstFirst 123 LastLast
Results 11 to 20 of 22

Thread: Forth :)

  1. #11
    подниматель пингвинов crazy-mike's Avatar
    Join Date
    Nov 2006
    Location
    L'viv
    Posts
    177,974

    Default Re: Forth :)

    Ну прикольный язык - на работе пришлось для него начать писать интерпретатор - потому что ничего готового под 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.
    Last edited by crazy-mike; 11-14-2018 at 03:28 PM.
    Жизнь дается человеку один раз и прожить ее надо так, чтобы не ошибиться в рецептах.
    Строить Асгардию побуждает тьма, посетившая людские души

  2. #12
    подниматель пингвинов crazy-mike's Avatar
    Join Date
    Nov 2006
    Location
    L'viv
    Posts
    177,974

    Default Re: Forth :)

    для начала с горя пришлось написать что-то такое:

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

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

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

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

    Но "есть в словаре" у нас означает или "поддерживается" как "стандартное слово" ( сразу выполняется и при этом вынимает данные из стека или пишет данные в стек ) , или "находится в пользовательском словаре" - ну как бы выполняем соответствующую подпрограмму.. Если оно является именем переменной ( одна из тех , которые ввели по variable ) - тогда заносим ссылку на дескриптор переменной в стек.
    Last edited by crazy-mike; 11-14-2018 at 03:53 PM.
    Жизнь дается человеку один раз и прожить ее надо так, чтобы не ошибиться в рецептах.
    Строить Асгардию побуждает тьма, посетившая людские души

  3. #13
    Eulen Spegel Птиц's Avatar
    Join Date
    Sep 2004
    Location
    Москва
    Posts
    132,063

    Default Re: Forth :)

    Quote Originally Posted by crazy-mike View Post
    для начала с горя пришлось написать что-то такое:

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

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

  4. #14
    подниматель пингвинов crazy-mike's Avatar
    Join Date
    Nov 2006
    Location
    L'viv
    Posts
    177,974

    Default Re: Forth :)

    Quote Originally Posted by Птиц View Post
    у меня супернаипесдатейший ноутбук Сони, щас таких не делают. я к нему подключаю монитор Сони SHD-968, смарю на нём фильмы и сериалы.
    на полном серьёзе - здесь тема о языке Forth. ( мне чуточку похвастаться хочется - как минимум ).
    Жизнь дается человеку один раз и прожить ее надо так, чтобы не ошибиться в рецептах.
    Строить Асгардию побуждает тьма, посетившая людские души

  5. #15
    подниматель пингвинов crazy-mike's Avatar
    Join Date
    Nov 2006
    Location
    L'viv
    Posts
    177,974

    Default Re: Forth :)

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

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

    PHP Code:
     typedef union {
      
    int iint refdouble f;
    Number;

    typedef struct {
      
    Number n;
      
    char xtag;
    Atom
    xtag = тег типа данных. У меня там допустимые значения :

    PHP Code:
    enum Tags {
      
    EOJ 0INT 1WORD 2STD 3VARNAME 4STRING 5
    }; 
    Строки держатся в отдельной AREA ( хотя её даже логичнее назвать heap. ). Если атом описывает строку - то ref указывает на смещение внутри этой "кучи".
    Если атом является "именем переменной" , то ref - индекс в таблице дескрипторов переменных.

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

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

    PHP Code:
    typedef struct {
      
    char xname[16];
      
    int xtag;
      
    union int refint i;  double f; } w;
    Xvar
    xtag - тип переменной. ref - ccылка на кучу для строк. i или f - собственно значение переменной числового типа.
    Last edited by crazy-mike; 11-14-2018 at 04:19 PM.
    Жизнь дается человеку один раз и прожить ее надо так, чтобы не ошибиться в рецептах.
    Строить Асгардию побуждает тьма, посетившая людские души

  6. #16
    подниматель пингвинов crazy-mike's Avatar
    Join Date
    Nov 2006
    Location
    L'viv
    Posts
    177,974

    Default Re: Forth :)

    Интерпретатор языка Forth ( обычно ) может находится в двух режимах: непосредственный ввод команд с выполнением команд и добавление описания в пользовательский словарь.

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

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

    PHP Code:
    typedef struct {
      
    int xtag,ok,fail,br;
      
    union int opcodeint refint ndouble f; } w;
    Icode
    Ну и откомпилированое слово является в этом случае "последовательностью кодослов". Каждое "кодослово" в этом случае имеет одинаковую длину , но у "кодослова" есть тэг - в зависимости от которого кодослово является или "командой загрузки непосредственного значения в стек" или "командой вызова подпрограммы" или "стандартной командой" или командой конца цепочки команд. При "стандартными командами" являются команды переходов и ветвлений. Для организации ветвлений-перходов используются поля ок,fail,br - куда заносятся "адреса переходов". Адрес перехода - это индекс в последовательности кодослов.

    допустимые значения тегов кодослов:
    PHP Code:
    enum Tags {
      
    EOJ 0INT 1WORD 2STD 3VARNAME 4STRING 5
    }; 
    Last edited by crazy-mike; 11-14-2018 at 04:51 PM.
    Жизнь дается человеку один раз и прожить ее надо так, чтобы не ошибиться в рецептах.
    Строить Асгардию побуждает тьма, посетившая людские души

  7. #17
    подниматель пингвинов crazy-mike's Avatar
    Join Date
    Nov 2006
    Location
    L'viv
    Posts
    177,974

    Default Re: Forth :)

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


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

    PHP Code:
      ret[nret]=-1nret++; 
      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+1nret++;
          
    ic=xec[ic].br; continue;
        };
        if(
    xec[ic].xtag==INT) {
          
    pp[ip].xtag='i';
          
    pp[ip].n.i=xec[ic].w.nip++;
          
    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;
      }; 
    Жизнь дается человеку один раз и прожить ее надо так, чтобы не ошибиться в рецептах.
    Строить Асгардию побуждает тьма, посетившая людские души

  8. #18
    подниматель пингвинов crazy-mike's Avatar
    Join Date
    Nov 2006
    Location
    L'viv
    Posts
    177,974

    Default Re: Forth :)

    PHP Code:

    static const instruction InstructionSet[] = {
      { 
    X_LTgLT }, { X_GTgGT }, { X_NEgNE }, { X_EQgEQ }, { X_TYPEgTYPE }, { X_PUSHVARgPUSHVAR },
      { 
    X_SETVARgSETVAR }, { X_DOTgDOT }, { X_PLUSgPLUS }, { X_MINUSgMINUS }, { X_MULgMUL },
      { 
    X_DIVgDIV }, { X_EMITgEMIT }, { X_CRgCR }, { X_BLgBL },
      { 
    X_IFgIF },{ X_ELSEgELSE },{ X_THENgTHEN },{ X_BEGINgBEGIN },{ X_UNTILgUNTIL },
      { 
    X_AGAINgAGAIN },{ X_LEAVEgLEAVE },{ X_WHILEgWHILE },{ X_REPEATgREPEAT },
      { 
    X_FORgFOR }, { X_NEXTgNEXT },{ X_SWAPgSWAP }, { X_DROPgDROP },
      { -
    1NULL  }
    };

    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 ведь что-то похожее на:
    PHP Code:
    typedef struct {
       const 
    int codevoid (*cmd)(void);
    instruction
    code - "код стандартной команды Forth". cmd - функция , которая реализует соответствующую команду.

    например: вынимание двух чисел из стека , их сложение и запись результата в стек по +
    PHP Code:
    void gPLUS(void) { pop2(); pp[ip].xtag=a1.xtagpp[ip].n.i=a1.n.i+a2.n.iip++; } 
    а "conditional statement IF" :

    PHP Code:
    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 даже в этом идиотски-расточительном варианте ( и там не только интерпретатор но и дизассемблер ).
    Last edited by crazy-mike; 11-14-2018 at 06:02 PM.
    Жизнь дается человеку один раз и прожить ее надо так, чтобы не ошибиться в рецептах.
    Строить Асгардию побуждает тьма, посетившая людские души

  9. #19
    подниматель пингвинов crazy-mike's Avatar
    Join Date
    Nov 2006
    Location
    L'viv
    Posts
    177,974

    Default Re: Forth :)

    https://concatenative.org/wiki/view/...ive%20language

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

  10. #20
    Forum Regular реднек's Avatar
    Join Date
    Dec 2011
    Posts
    4,427

    Default Re: Forth :)

    Quote Originally Posted by crazy-mike View Post
    https://concatenative.org/wiki/view/...ive%20language

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

Page 2 of 3 FirstFirst 123 LastLast

Thread Information

Users Browsing this Thread

There are currently 1 users browsing this thread. (0 members and 1 guests)

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  
Russian America Top. Рейтинг ресурсов Русской Америки. Terms of Service | Privacy Policy Рейтинг@Mail.ru