Re: Компиляция Refal6 для Linux (commens on data striucrture


Subject: Re: Компиляция Refal6 для Linux (commens on data striucrture
From: Nikolai Kondratiev (Nikolai.Kondratiev@gmx.de)
Date: Fri Nov 02 2001 - 11:17:19 MSK


Привет!

Я использовал обработку сигналов только для отлова Ctl-C, чтобы можно было
выдать нормальную рефальскую диагностику в случае зацикливания.

Ниже - выдержки из сохранившейся у меня версии Рефала-6

refcom.h:

#define BRKINIT signal(SIGINT,handint);

rfserv.c:

void handint()
{
   while (BRKTEST) getch();
   if (rftrcmode) {
   if (rftrace) trcsigfl = TRUE;
   BRKINIT;
   return;
         }
   rf_error = ERRBRK;
}

Использовался, помнится, борландовский компилятор С.

Ниже - выдержка из Help'a C-Builder 3.0, к сожалению, по-немецки.

Syntax

#include <signal.h>
void (_USERENTRY *signal(int sig, void (_USERENTRY *func)
                                  (int sig[, int subcode])))(int);

Beschreibung

Legt fest, wie das Programm auf Signale reagiert.

Uber die Funktion signal konnen Sie festlegen, wie Ihr Programm auf die
Auslosung des Signals sig reagiert. Sie konnen durch das Argument func eine
eigene Routine zur Bearbeitung des Signals (einen Signal-Handler) definieren
oder auch eine der beiden in signal.h vordefinierten Routinen SIG_DEFL und
SIG_IGN einsetzen. Die Funktion func mu? mit der Aufrufkonvention _USERENTRY
benutzt werden.

Eine Routine, die ein Signal auffangt (wie zum Beispiel eine
Gleitkommazahl), loscht auch das Signal. Um den Empfang von Signalen
fortsetzen zu konnen, mu? eine Signalbehandlung durch den erneuten Aufruf
von signal reinstalliert werden.

Funktionszeiger Bedeutung

SIG_DFL Das Programm wird beendet.
SIG_ERR Zeigt an, da? signal einen Fehler ergeben hat.
SIG_IGN Dieser Signaltyp wird ignoriert.

In der folgenden Tabelle finden Sie Signaltypen zusammen mit den von ihnen
ausgelosten Standardaktionen:

Signaltyp Bedeutung

SIGBREAK Tastatur mu? sich im Modus "raw" (Zeichen nicht interpretieren)
befinden
SIGARBRT Anormales Ende. Standardaktion entspricht dem Aufruf von _exit(3).
SIGFPE Arithmetischer Fehler aufgrund einer Division durch Null, einer
ungultigen Operation usw. Standardaktion entspricht Aufruf von _exit(1).
SIGILL Unzulassige Operation. Standardaktion entspricht Aufruf von _exit(1).
SIGINT Strg+C-Interrupt. Standardaktion ist Aufruf von INT 23h.

SIGSEGV Ungultiger Speicherzugriff. Standardaktion entspricht Aufruf von
_exit
(1).
SIGTERM Beendigung des Programms wird angefordert. Standardaktion entspricht
Aufruf von _exit(1).
SIGUSR1, SIGUSR2, SIGUSR3 Benutzerdefinierte Signale (nur in Win32
verfugbar), die nur durch den Aufruf von raise erzeugt werden konnen.
Standardaktion: Das Signal wird ignoriert.

signal.h definiert einen Datentyp sig_atomic_t als gro?ten atomaren
Speicherzugriff, den der Prozessor automatisch laden oder speichern kann und
der auch durch asynchrone Interrupts nicht unterbrochen werden kann. Fur die
Prozessoren der 8086-Familie ist dies ein Wort der Lange 16 Bit, fur 80386
und hoher ist es ein Wort der Lange 32 Bit, also ein Borland C++ Integer.

Wenn ein Signal durch die Funktion raise oder ein externes Ereignis erzeugt
wird, geschieht folgendes:

Wurde fur das Signal ein benutzerdefinierter Signal-Handler installiert,
wird die Aktion fur diesen Signaltyp auf SIG_DFL gesetzt.
 Der benutzerdefinierte Handler wird aufgerufen. Der Signaltyp wird dabei
als Parameter ubergeben.

Benutzerdefinerte Handler konnen mit einem Aufruf von abort, _exit, exit
oder longjmp enden oder auch mit einem normalen Rucksprung zum
unterbrochenen Programm. Soll Ihre Handler-Funktion weitere Signale
empfangen und verarbeiten, so mussen Sie signal innerhalb der
Handler-Funktion erneut aufrufen.

Borland C++ implementiert bei den Signaltypen SIGFPE, SIGSEGV und SIGILL
eine Erweiterung von ANSI C. Die entsprechenden benutzerdefinierten
Signal-Handler erhalten nicht nur den Signaltyp, sondern auch noch einen
oder zwei zusatzliche Parameter. Wenn einer dieser drei Signaltypen uber
raise ausgelost wird, erhalt der Handler einen der in der nachfolgenden
Tabelle aufgefuhrten Werte als zusatzlichen Parameter (und kann daran
erkennen, da? er explizit aufgerufen wurde). Die explizit aktivierenden
Werte fur SIGFPE, SIGSEGV und SIGILL sind:

Hinweis: Deklarationen dieser Typen sind in float.h definiert.

Signal Parameter

SIGFPE FPE_EXPLICITGEN
SIGSEGV SEGV_EXPLICITGEN
SIGILL ILL_EXPLICITGEN

Wird ein Signal des Typs SIGFPE als Folge einer Gleitkomma-Exception
ausgelost, bekommt der benutzerdefinierte Handler die Art dieses Fehlers als
einen zusatzlichen Parameter ubergeben, das den Typ FPE_xxx des Signals
festlegt. Wenn die Signaltypen SIGSEGV und SIGILL oder Varianten des Typs
SIGFPE (FPE_INTOVFLOW oder FPE_INTDIV0) als Folge einer Prozessor-Exception
auftauchen, wird der Handler mit zwei zusatzlichen Parametern aufgerufen:

1. Die Exception-Typen SIGSEGV, SIGILL oder SIGFPE (siehe float.h fur diese
Typen). Dieser erste Parameter ist der gewohnliche Signaltyp von ANSI.
2. Einen Integer-Zeiger in den Stack der interrupt-Routine, die den
benutzerdefinierten Signal-Handler aufgerufen hat. Dieser Zeiger zeigt auf
eine Liste der Prozessorregister, die beim Auftreten des Fehlers gespeichert
wurden. Die Register sind in derselben Reihenfolge wie die Parameter der
Interrupt-Funktion (BP, DI, SI, DS, ES, DX, CX, BX, AX, IP, CS, FLAGS)
gespeichert. Um bei der Ruckgabe des Handlers einen veranderten Registerwert
geandert zu erhalten, andern sie einen der Platze in dieser Liste.

Um beispielsweise einen neuen SI-Wert zu erhalten, konnten Sie so etwas tun:

*((int*)list_pointer + 2) = new_SI_value;

Auf diese Weise kann der Handler die Register uberprufen und alle von Ihnen
gewunschten Einstellungen vornehmen.

Die folgenden Signale des SIGFPE-Typs konnen auftreten (bzw. generiert
werden). Sie entsprechen den Fehlern, die der 8087-Prozessor erkennen kann,
sowie INTEGER DIVIDE BY ZERO und INTERRUPT ON OVERFLOW bei der Haupt-CPU.
(Die entsprechenden Deklarationen befinden sich in float.h.)

SIGFPE-Signal Bedeutung

FPE_INTOVFLOW INTO-Befehl mit gesetztem OF-Flag
FPE_INTDIV0 Integer duch 0 geteilt
FPE_INVALID Ungultige Operation
FPE_ZERODIVIDE Division durch Null
FPE_OVERFLOW Numerischer Uberlauf
FPE_UNDERFLOW Numerischer Unterlauf
FPE_INEXACT Ungenaues Ergebnis
FPE_EXPLICITGEN Anwendungsprogramm fuhrte raise(SIGFPE) aus
FPE_STACKFAULT Uber-/Unterlauf des Gleitkomma-Stack
FPE_STACKFAULT Stack-Uberlauf

Die Signale FPE_INTOVFLOW und FPE_INTDIV0 werden durch Integer-Operationen
ausgelost, die restlichen Signale durch Gleitkommaoperationen. Ob eine
Gleitkomma-Exception ein Signal setzt, hangt vom Steuerwort des Koprozessors
ab, das uber die Routine _control87
 verandert werden kann. Denormalisierte Exceptions werden direkt von Borland
C++ behandelt und nicht an den Handler ubergeben.

Folgende Signale des Typs SEGSEGV konnen auftreten:

SEGV_BOUND ausgelost durch BOUND-Befehl
SEGV_EXPLICITGEN ausgelost durch die Ausfuhrung von raise(SIGSEGV
)

Der Prozessorbefehl BOUND ist fur die Prozessortypen 8088/86 nicht
definiert. Die Prozessoren 186, 286, 386 sowie NEC V kennen diesen Befehl.
Auf 80088/86 Prozessoren kann daher der Type SEGV_BOUND des Signals SIGSEGV
nicht auftreten. Borland C++ generiert den BOUND-Befehl nicht, doch kann er
in Inline-Assemblercode sowie separat assemblierten und eingebundenen
Routinen verwendet werden.

Fur Signale des Typs SIGILL sind die folgenden Konstanten definiert:

ILL_EXECUTION ungultige Operationsanforderung
ILL_EXPLICITGEN ausgelost durch Ausfuhrung von raise(SIGILL)

Die Prozessortypen 8088/86, NEC V20 und NEC V30 losen bei illegalen Befehlen
keinen Interrupt aus - SIGILL kann hier nur durch einen Aufruf von raise
ausgelost werden. Die Prozessortypen 186, 286, 386, NECV40 und NECV50
hingegen haben diesen Exception-Typ. Auf 8088-, 8086-, NEC V20- und NEC
V30-Systemen kann der ILL_EXECUTION-Typ von SIGILL nicht auftreten.

Bei den Signalen SIGFPE, SIGSEGV oder SIGILL ist ein Rucksprung des
Signal-Handler im allgemeinen nicht zu empfehlen, wenn der Koprozessorstatus
fehlerhaft, das Ergebnis einer Integer-Division falsch, ein zu vermeidender
Uberlauf entstanden, ein BOUND-Befehl erfolglos oder eine Operation
unzulassig ist. Ein Rucksprung ist nur dann empfehlenswert, wenn der
Signal-Handler die Register so verandert, da? ein sinnvoller
Rucksprungkontext existiert oder wenn sich anhand des Signaltyps
(beispielsweise FPE_EXPLICITGEN, SEG_EXPLICITGEN oder ILL_EXPLICITGEN)
erkennen la?t, da? das Signal explizit erzeugt wurde. Im allgemeinen sollten
Sie jedoch eine Fehlermeldung ausgeben und das Programm mit _exit, exit oder
abort beenden. Wird dennoch ein Rucksprung vorgenommen, sind die Folgen kaum
vorhersehbar.

Hinweis: Seien Sie besonders vorsichtig, wenn sie die Funktion signal in
einem Multithread-Programm verwenden. Die Signale SIGINT, SIGTERM und
SIGBREAK sind in einer Nicht-Win32-Anwendung nur im Haupt-Thread (Thread 1)
verwendbar. Wenn eines dieser Signale auftritt, wird der aktuell ausgefuhrte
Thread angehalten, und die Kontrolle wechselt zu dem von Thread 1
eingerichteten Signal-Handler (falls vorhanden). Andere Signale konnen durch
jeden Thread verarbeitet werden.

Ein Signal-Handler sollte keine Laufzeitbibliotheksfunktionen von C++
verwenden, weil ein Deadlock von Semaphoren auftreten konnte. Statt dessen
sollte der Handler einfach ein Flag oder einen Semaphor setzen und sofort
zuruckkehren.

Ruckgabewert

Bei fehlerfreier Ausfuhrung liefert signal einen Zeiger auf die Routine, die
zuvor als Handler fur Signale des angegebenen Typs gesetzt war.

Bei einem Fehler ist das Ergebnis von signal der Zeiger SIG_ERR, und errno
 wird auf den Wert EINVAL gesetzt.

Успехов,

Николай Кондратьев

----- Original Message -----
From: "Arkady Klimov" <klark@bagirra.net>
To: "Andrey Slepuhin" <pooh@msu.ru>; <dmsidorov@mtu-net.ru>
Cc: "refal" <refal@botik.ru>
Sent: Thursday, November 01, 2001 3:32 PM
Subject: Re: Компиляция Refal6 для Linux (comments on data striucrture)

> Посылаю ответ также в группу refal для архива, так как здесь содержится
> полезная информация о структурах данных реализации Рефала-6 и
> ее использовании на уровне С.
>
> ----- Original Message -----
> From: <dmsidorov@mtu-net.ru>
> To: Arkady Klimov <klark@bagirra.net>; Andrey Slepuhin <pooh@msu.ru>
> Sent: Wednesday, October 31, 2001 9:30 PM
> Subject: Re: Компиляция Refal6 для Linux
>
>
> | On Sun, Oct 28, 2001 at 06:24:25PM +0300, Arkady Klimov wrote:
> | > matherr - это, как говорят, callback-функция для перехвата
арифметических ошибок
> | > (типа деления на 0). Она должна иметь определенный заголовок.
> | > Можете попробовать поставить тот, который тут написан (вероятно,
нижний,
> | > поскольку используется С, а не С++).
> |
> | On Mon, Oct 29, 2001 at 01:13:00PM +0300, Andrey Slepuhin wrote:
> | > То есть использовать эту функцию не рекомендуется. Вместо этого
> | > предлагается использовать стандартные механизмы обработки сигналов -
> | > при исключительных ситуациях во время операций с плавающей точкой
> | > вырабатывается сигнал SIGFPE.
> |
> | Замена в строке 252 _exception на exception позволила скомпилировать
файл,
> | но хотелось бы знать, что Вы думаете насчет предложения Andrey Slepuhin
> | о перехвате сигнала ошибки арифметической операции вместо использования
> | matherr? Насколько я понимаю, в DOS сигналов нет. Но, может, в
компиляторах
> | DOS есть функция назначения обработчиков сигналов signal, тогда какой у
нее
> | интерфейс?
>
> Что-то в этом роде, кажется там есть. И даже, если мне не изменяет память,
этот вариант
> у меня в системе когда-то был, возможно сделанный еще начальным автором -
Николаем
> Кондратьевым. Потом я сделал почему-то иначе, но уже не помню почему.
Сейчас можно
> тоже переделать, главное, чтобы со знанием дела.
>
>
> |
> | On Mon, Oct 29, 2001 at 01:13:00PM +0300, Andrey Slepuhin wrote:
> | > > Сообщение об ошибке в rfarm.c совершенно непонятно:
> | > >
> | > > rfarm.c: In function `rf_cgetnumb':
> | > > rfarm.c:289: Unable to generate reloads for:
> | > > (insn 45 43 47 (parallel[
> | > > (set (reg:SI 0 %eax)
> | > > (fix:SI (fix:SF (reg/v:SF 0 %eax))))
> | > > (clobber (mem:HI (plus:SI (reg:SI 6 %ebp)
> | > > (const_int -2 [0xfffffffe])) 0))
> | > > (clobber (mem:HI (plus:SI (reg:SI 6 %ebp)
> | > > (const_int -4 [0xfffffffc])) 0))
> | > > (clobber (mem:SI (plus:SI (reg:SI 6 %ebp)
> | > > (const_int -8 [0xfffffff8])) 0))
> | > > (clobber (scratch:HI))
> | > > ] ) 145 {fix_truncsfsi2+1} (insn_list 92 (nil))
> | > > (expr_list:REG_EQUIV (mem:SI (reg/v:SI 3 %ebx) 0)
> | > > (expr_list:REG_DEAD (reg/v:SF 0 %eax)
> | > > (expr_list:REG_UNUSED (scratch:HI)
> | > > (nil)))))
> | > > make: *** [rfarm.o] Error 1
> | > >
> | >
> | > Здесь однозначно ошибка компилятора, который не смог справиться с
перегрузкой
> | > значений регистров (в силу малого их количества в x86 архитектуре). В
качестве
> | > воркэраунда вокруг таких ситуаций обычно достаточно немного потасовать
код
> | > функции, не меняя ее смысл. Хотя лично я посоветовал бы переходить на
> | > gcc-3.0.2. По крайней мере многие вещи там сделаны идеологически
намного более
> | > правильно.
> |
> | Функция rf_cgetnumb оказалось весьма интересной. Посмотрев определения
> | использованных в ней макросов IS_REF, IS_REAL, IS_SNUMB, CVAL, CTYPE
> | CREF00 в refelem.h, я не понял, что они делают. Наверно, тут виновато
> | мое плохое знание C, но каков смысл выражения типа
> | int t = ((unsigned short) (unsigned) (cc))
> | в отношении нетипизированной ссылки cc? Какое назначение у всех
> | этих макросов и у rf_cgetnumb? Без этого непонятно, как ее нужно
> | перекраивать, чтобы скормить компилятору.
>
> Аргумент здесь - значение звена (терма) типа cvalue, которое представляет
собой упакованное
> в одно слово размеченное объединение, включающее указатели (скобки или
символы ссылки),
> числа, слова, литеры, ... .В качестве дискриминанта используются
последние два бита, которые
> в указателях на звено всегда нулевые. Отсюда мнемоника CREF00 - взять (из
cvalue) значение указателя,
> с обнулением младших двух битов. Вышенаписанное выражение, похоже,
использовано для
> извлечения младшей (содержащей тег) двухбайтной части значение
(CTYPE(cc)).
> Функция rf_getnumb проверяет, что терм есть символ-число
> и вырабатывает значение этого числа (типа long, то есть с усечением до
32-разрядов). Применяется
> в системе обычно для извлечения значений, которые заведомо невелики -
номера каналов,
> индексы элементов и т.п.
> elemptr p - указатель на звено (типа elem или elemstr), содержащее
32-разрядное значение info
> и пару ссылок вперед и назад.
> DATA(p) выдает значение info, типизированное как cvalue.
> Абстрактно, значение cvalue состоит из типа и собственно значения.
> TYPE(p), CTYPE(c) выдают типовую часть t значения в виде short.
> Перечисленные макросы вида IS_...(t) служат для распознания категорий
символов, запакованных
> в значении.
> VAL(p), CVAL(c) выдает само значение в виде short, при условии, что оно
туда помещается
> (например, короткое целое - IS_SNUMB).
> Более крупные значения извлекаются специфическими макросами, типа CREF00,
SWDBODY,
> или функциями, типа rf_cgetnumb.
> Важно заметить, что система допускает генерацию с несколькими различными
вариантами
> представления звена и адреса звена, поэтому, чтобы не нарушить этого
свойства, ковыряться
> в звеньях нужно только через упомянутые макросы и функции. К сожалению,
компилятор С
> не защищает от ошибок в этом деле. Фактическое расположение частей
значения зависит
> также от архитектуры компьютера - big endian или little endian.
>
> Обращаю внимание, что большие числа с произвольной разрядностью
представляются
> в системе как массивы коротких 16-разрядных чисел (short) - макроцифр:
x[0]- младшая часть,
> x[l-1] - знак (0 или -1), где l- длина массива (l>=1). Учитывая
зависимость от архитектуры,
> следует заметить, что пара младших макроцифр не обязательно образует
вместе
> младшую часть типа long, но ее всегда можно получить выражением
x[1]<<16+x[0], которое
> и используется при реализации функции rf_cgetnumb (для длинных чисел).
>
> Аркадий
>
>
> |
> | Дмитрий
>
>
>



This archive was generated by hypermail 2b25 : Mon Oct 25 2004 - 21:24:59 MSD