#include "ficl.h"
#if FICL_WANT_FLOAT
#include <math.h>
#include <values.h>
static void
ficlPrimitiveFConstant(ficlVm *vm)
{
ficlDictionary *dictionary = ficlVmGetDictionary(vm);
ficlString name = ficlVmGetWord(vm);
FICL_STACK_CHECK(vm->floatStack, 1, 0);
(void) ficlDictionaryAppendWord(dictionary, name,
(ficlPrimitive)ficlInstructionFConstantParen, FICL_WORD_DEFAULT);
ficlDictionaryAppendCell(dictionary, ficlStackPop(vm->floatStack));
}
ficlWord *
ficlDictionaryAppendFConstant(ficlDictionary *dictionary, char *name,
ficlFloat value)
{
ficlString s;
FICL_STRING_SET_FROM_CSTRING(s, name);
return (ficlDictionaryAppendConstantInstruction(dictionary, s,
ficlInstructionFConstantParen, *(ficlInteger *)(&value)));
}
ficlWord *
ficlDictionarySetFConstant(ficlDictionary *dictionary, char *name,
ficlFloat value)
{
ficlString s;
FICL_STRING_SET_FROM_CSTRING(s, name);
return (ficlDictionarySetConstantInstruction(dictionary, s,
ficlInstructionFConstantParen, *(ficlInteger *)(&value)));
}
static void
ficlPrimitiveF2Constant(ficlVm *vm)
{
ficlDictionary *dictionary = ficlVmGetDictionary(vm);
ficlString name = ficlVmGetWord(vm);
FICL_STACK_CHECK(vm->floatStack, 2, 0);
(void) ficlDictionaryAppendWord(dictionary, name,
(ficlPrimitive)ficlInstructionF2ConstantParen, FICL_WORD_DEFAULT);
ficlDictionaryAppendCell(dictionary, ficlStackPop(vm->floatStack));
ficlDictionaryAppendCell(dictionary, ficlStackPop(vm->floatStack));
}
ficlWord *
ficlDictionaryAppendF2Constant(ficlDictionary *dictionary, char *name,
ficlFloat value)
{
ficlString s;
FICL_STRING_SET_FROM_CSTRING(s, name);
return (ficlDictionaryAppend2ConstantInstruction(dictionary, s,
ficlInstructionF2ConstantParen, *(ficl2Integer *)(&value)));
}
ficlWord *
ficlDictionarySetF2Constant(ficlDictionary *dictionary, char *name,
ficlFloat value)
{
ficlString s;
FICL_STRING_SET_FROM_CSTRING(s, name);
return (ficlDictionarySet2ConstantInstruction(dictionary, s,
ficlInstructionF2ConstantParen, *(ficl2Integer *)(&value)));
}
static void
ficlPrimitiveFDot(ficlVm *vm)
{
ficlFloat f;
FICL_STACK_CHECK(vm->floatStack, 1, 0);
f = ficlStackPopFloat(vm->floatStack);
(void) sprintf(vm->pad, "%#f ", f);
ficlVmTextOut(vm, vm->pad);
}
static void
ficlPrimitiveEDot(ficlVm *vm)
{
ficlFloat f;
FICL_STACK_CHECK(vm->floatStack, 1, 0);
f = ficlStackPopFloat(vm->floatStack);
(void) sprintf(vm->pad, "%#e ", f);
ficlVmTextOut(vm, vm->pad);
}
struct stackContext
{
ficlVm *vm;
int count;
};
static ficlInteger
ficlFloatStackDisplayCallback(void *c, ficlCell *cell)
{
struct stackContext *context = (struct stackContext *)c;
char buffer[80];
#ifdef _LP64
(void) snprintf(buffer, sizeof (buffer),
"[0x%016lx %3d] %20e (0x%016lx)\n",
(unsigned long) cell, context->count++, cell->f, cell->u);
#else
(void) snprintf(buffer, sizeof (buffer), "[0x%08x %3d] %12e (0x%08x)\n",
(unsigned)cell, context->count++, cell->f, cell->u);
#endif
ficlVmTextOut(context->vm, buffer);
return (FICL_TRUE);
}
void
ficlVmDisplayFloatStack(ficlVm *vm)
{
struct stackContext context;
context.vm = vm;
context.count = 0;
ficlStackDisplay(vm->floatStack, ficlFloatStackDisplayCallback,
&context);
}
static void
ficlPrimitiveFDepth(ficlVm *vm)
{
int i;
FICL_STACK_CHECK(vm->dataStack, 0, 1);
i = ficlStackDepth(vm->floatStack);
ficlStackPushInteger(vm->dataStack, i);
}
static void
ficlPrimitiveFLiteralImmediate(ficlVm *vm)
{
ficlDictionary *dictionary = ficlVmGetDictionary(vm);
ficlCell cell;
FICL_STACK_CHECK(vm->floatStack, 1, 0);
cell = ficlStackPop(vm->floatStack);
if (cell.f == 1.0f) {
ficlDictionaryAppendUnsigned(dictionary, ficlInstructionF1);
} else if (cell.f == 0.0f) {
ficlDictionaryAppendUnsigned(dictionary, ficlInstructionF0);
} else if (cell.f == -1.0f) {
ficlDictionaryAppendUnsigned(dictionary, ficlInstructionFNeg1);
} else {
ficlDictionaryAppendUnsigned(dictionary,
ficlInstructionFLiteralParen);
ficlDictionaryAppendCell(dictionary, cell);
}
}
#define NUMISNEG 1
#define EXPISNEG 2
typedef enum _floatParseState
{
FPS_START,
FPS_ININT,
FPS_INMANT,
FPS_STARTEXP,
FPS_INEXP
} FloatParseState;
int
ficlVmParseFloatNumber(ficlVm *vm, ficlString s)
{
unsigned char c;
unsigned char digit;
char *trace;
ficlUnsigned length;
ficlFloat power;
ficlFloat accum = 0.0f;
ficlFloat mant = 0.1f;
ficlInteger exponent = 0;
char flag = 0;
FloatParseState estate = FPS_START;
FICL_STACK_CHECK(vm->floatStack, 0, 1);
if (vm->base != 10)
return (0);
trace = FICL_STRING_GET_POINTER(s);
length = FICL_STRING_GET_LENGTH(s);
while ((length--) && ((c = *trace++) != 0)) {
switch (estate) {
case FPS_START:
estate = FPS_ININT;
if (c == '-') {
flag |= NUMISNEG;
break;
}
if (c == '+') {
break;
}
case FPS_ININT:
if (c == '.') {
estate = FPS_INMANT;
} else if ((c == 'e') || (c == 'E')) {
estate = FPS_STARTEXP;
} else {
digit = (unsigned char)(c - '0');
if (digit > 9)
return (0);
accum = accum * 10 + digit;
}
break;
case FPS_INMANT:
if ((c == 'e') || (c == 'E')) {
estate = FPS_STARTEXP;
} else {
digit = (unsigned char)(c - '0');
if (digit > 9)
return (0);
accum += digit * mant;
mant *= 0.1f;
}
break;
case FPS_STARTEXP:
estate = FPS_INEXP;
if (c == '-') {
flag |= EXPISNEG;
break;
} else if (c == '+') {
break;
}
case FPS_INEXP:
digit = (unsigned char)(c - '0');
if (digit > 9)
return (0);
exponent = exponent * 10 + digit;
break;
}
}
if (estate < FPS_STARTEXP)
return (0);
if (flag & NUMISNEG)
accum = -accum;
if (exponent != 0) {
if (flag & EXPISNEG) {
exponent = -exponent;
}
#if defined(_LP64)
power = (ficlFloat)pow(10.0, exponent);
#else
power = (ficlFloat)powf(10.0, exponent);
#endif
accum *= power;
}
ficlStackPushFloat(vm->floatStack, accum);
if (vm->state == FICL_VM_STATE_COMPILE)
ficlPrimitiveFLiteralImmediate(vm);
return (1);
}
#endif
#if FICL_WANT_LOCALS
static void
ficlPrimitiveFLocalParen(ficlVm *vm)
{
ficlLocalParen(vm, 0, 1);
}
static void
ficlPrimitiveF2LocalParen(ficlVm *vm)
{
ficlLocalParen(vm, 1, 1);
}
#endif
void
ficlSystemCompileFloat(ficlSystem *system)
{
ficlDictionary *dictionary = ficlSystemGetDictionary(system);
ficlDictionary *environment = ficlSystemGetEnvironment(system);
#if FICL_WANT_FLOAT
ficlCell data;
#endif
FICL_SYSTEM_ASSERT(system, dictionary);
FICL_SYSTEM_ASSERT(system, environment);
#if FICL_WANT_LOCALS
(void) ficlDictionarySetPrimitive(dictionary, "(flocal)",
ficlPrimitiveFLocalParen, FICL_WORD_COMPILE_ONLY);
(void) ficlDictionarySetPrimitive(dictionary, "(f2local)",
ficlPrimitiveF2LocalParen, FICL_WORD_COMPILE_ONLY);
#endif
#if FICL_WANT_FLOAT
(void) ficlDictionarySetPrimitive(dictionary, "fconstant",
ficlPrimitiveFConstant, FICL_WORD_DEFAULT);
(void) ficlDictionarySetPrimitive(dictionary, "fvalue",
ficlPrimitiveFConstant, FICL_WORD_DEFAULT);
(void) ficlDictionarySetPrimitive(dictionary, "f2constant",
ficlPrimitiveF2Constant, FICL_WORD_DEFAULT);
(void) ficlDictionarySetPrimitive(dictionary, "f2value",
ficlPrimitiveF2Constant, FICL_WORD_DEFAULT);
(void) ficlDictionarySetPrimitive(dictionary, "fdepth",
ficlPrimitiveFDepth, FICL_WORD_DEFAULT);
(void) ficlDictionarySetPrimitive(dictionary, "fliteral",
ficlPrimitiveFLiteralImmediate, FICL_WORD_IMMEDIATE);
(void) ficlDictionarySetPrimitive(dictionary, "f.",
ficlPrimitiveFDot, FICL_WORD_DEFAULT);
(void) ficlDictionarySetPrimitive(dictionary, "f.s",
ficlVmDisplayFloatStack, FICL_WORD_DEFAULT);
(void) ficlDictionarySetPrimitive(dictionary, "fe.",
ficlPrimitiveEDot, FICL_WORD_DEFAULT);
#if defined(_LP64)
data.f = MAXDOUBLE;
#else
data.f = MAXFLOAT;
#endif
(void) ficlDictionarySetConstant(environment, "max-float", data.i);
(void) ficlDictionarySetConstant(environment, "floating", FICL_FALSE);
(void) ficlDictionarySetConstant(environment, "floating-ext",
FICL_FALSE);
(void) ficlDictionarySetConstant(environment, "floating-stack",
system->stackSize);
#else
(void) ficlDictionarySetConstant(environment, "floating", FICL_FALSE);
#endif
}