8911 loader: move ficl outb and inb into libi386
[unleashed.git] / usr / src / common / ficl / float.c
blob02f64b8c9b540e3c620e7a1f6dc9ff5503d22e73
1 /*
2 * f l o a t . c
3 * Forth Inspired Command Language
4 * ANS Forth FLOAT word-set written in C
5 * Author: Guy Carver & John Sadler (john_sadler@alum.mit.edu)
6 * Created: Apr 2001
7 * $Id: float.c,v 1.10 2010/09/13 18:43:04 asau Exp $
8 */
9 /*
10 * Copyright (c) 1997-2001 John Sadler (john_sadler@alum.mit.edu)
11 * All rights reserved.
13 * Get the latest Ficl release at http://ficl.sourceforge.net
15 * I am interested in hearing from anyone who uses Ficl. If you have
16 * a problem, a success story, a defect, an enhancement request, or
17 * if you would like to contribute to the Ficl release, please
18 * contact me by email at the address above.
20 * L I C E N S E and D I S C L A I M E R
22 * Redistribution and use in source and binary forms, with or without
23 * modification, are permitted provided that the following conditions
24 * are met:
25 * 1. Redistributions of source code must retain the above copyright
26 * notice, this list of conditions and the following disclaimer.
27 * 2. Redistributions in binary form must reproduce the above copyright
28 * notice, this list of conditions and the following disclaimer in the
29 * documentation and/or other materials provided with the distribution.
31 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
32 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
33 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
34 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
35 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
36 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
37 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
38 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
39 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
40 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
41 * SUCH DAMAGE.
44 #include "ficl.h"
46 #if FICL_WANT_FLOAT
47 #include <math.h>
48 #include <values.h>
52 * Create a floating point constant.
53 * fconstant ( r -"name"- )
55 static void
56 ficlPrimitiveFConstant(ficlVm *vm)
58 ficlDictionary *dictionary = ficlVmGetDictionary(vm);
59 ficlString name = ficlVmGetWord(vm);
61 FICL_STACK_CHECK(vm->floatStack, 1, 0);
63 ficlDictionaryAppendWord(dictionary, name,
64 (ficlPrimitive)ficlInstructionFConstantParen, FICL_WORD_DEFAULT);
65 ficlDictionaryAppendCell(dictionary, ficlStackPop(vm->floatStack));
69 ficlWord *
70 ficlDictionaryAppendFConstant(ficlDictionary *dictionary, char *name,
71 ficlFloat value)
73 ficlString s;
74 FICL_STRING_SET_FROM_CSTRING(s, name);
75 return (ficlDictionaryAppendConstantInstruction(dictionary, s,
76 ficlInstructionFConstantParen, *(ficlInteger *)(&value)));
80 ficlWord *
81 ficlDictionarySetFConstant(ficlDictionary *dictionary, char *name,
82 ficlFloat value)
84 ficlString s;
85 FICL_STRING_SET_FROM_CSTRING(s, name);
86 return (ficlDictionarySetConstantInstruction(dictionary, s,
87 ficlInstructionFConstantParen, *(ficlInteger *)(&value)));
93 static void
94 ficlPrimitiveF2Constant(ficlVm *vm)
96 ficlDictionary *dictionary = ficlVmGetDictionary(vm);
97 ficlString name = ficlVmGetWord(vm);
99 FICL_STACK_CHECK(vm->floatStack, 2, 0);
101 ficlDictionaryAppendWord(dictionary, name,
102 (ficlPrimitive)ficlInstructionF2ConstantParen, FICL_WORD_DEFAULT);
103 ficlDictionaryAppendCell(dictionary, ficlStackPop(vm->floatStack));
104 ficlDictionaryAppendCell(dictionary, ficlStackPop(vm->floatStack));
107 ficlWord *
108 ficlDictionaryAppendF2Constant(ficlDictionary *dictionary, char *name,
109 ficlFloat value)
111 ficlString s;
112 FICL_STRING_SET_FROM_CSTRING(s, name);
113 return (ficlDictionaryAppend2ConstantInstruction(dictionary, s,
114 ficlInstructionF2ConstantParen, *(ficl2Integer *)(&value)));
117 ficlWord *
118 ficlDictionarySetF2Constant(ficlDictionary *dictionary, char *name,
119 ficlFloat value)
121 ficlString s;
122 FICL_STRING_SET_FROM_CSTRING(s, name);
123 return (ficlDictionarySet2ConstantInstruction(dictionary, s,
124 ficlInstructionF2ConstantParen, *(ficl2Integer *)(&value)));
128 * Display a float in decimal format.
129 * f. ( r -- )
131 static void
132 ficlPrimitiveFDot(ficlVm *vm)
134 ficlFloat f;
136 FICL_STACK_CHECK(vm->floatStack, 1, 0);
138 f = ficlStackPopFloat(vm->floatStack);
139 sprintf(vm->pad, "%#f ", f);
140 ficlVmTextOut(vm, vm->pad);
144 * Display a float in engineering format.
145 * fe. ( r -- )
147 static void
148 ficlPrimitiveEDot(ficlVm *vm)
150 ficlFloat f;
152 FICL_STACK_CHECK(vm->floatStack, 1, 0);
154 f = ficlStackPopFloat(vm->floatStack);
155 sprintf(vm->pad, "%#e ", f);
156 ficlVmTextOut(vm, vm->pad);
160 * d i s p l a y FS t a c k
161 * Display the parameter stack (code for "f.s")
162 * f.s ( -- )
164 struct stackContext
166 ficlVm *vm;
167 int count;
170 static ficlInteger
171 ficlFloatStackDisplayCallback(void *c, ficlCell *cell)
173 struct stackContext *context = (struct stackContext *)c;
174 char buffer[80];
175 #ifdef _LP64
176 snprintf(buffer, sizeof (buffer), "[0x%016lx %3d] %20e (0x%016lx)\n",
177 (unsigned long) cell, context->count++, cell->f, cell->u);
178 #else
179 snprintf(buffer, sizeof (buffer), "[0x%08x %3d] %12e (0x%08x)\n",
180 (unsigned)cell, context->count++, cell->f, cell->u);
181 #endif
182 ficlVmTextOut(context->vm, buffer);
183 return (FICL_TRUE);
186 void
187 ficlVmDisplayFloatStack(ficlVm *vm)
189 struct stackContext context;
190 context.vm = vm;
191 context.count = 0;
192 ficlStackDisplay(vm->floatStack, ficlFloatStackDisplayCallback,
193 &context);
197 * Do float stack depth.
198 * fdepth ( -- n )
200 static void
201 ficlPrimitiveFDepth(ficlVm *vm)
203 int i;
205 FICL_STACK_CHECK(vm->dataStack, 0, 1);
207 i = ficlStackDepth(vm->floatStack);
208 ficlStackPushInteger(vm->dataStack, i);
212 * Compile a floating point literal.
214 static void
215 ficlPrimitiveFLiteralImmediate(ficlVm *vm)
217 ficlDictionary *dictionary = ficlVmGetDictionary(vm);
218 ficlCell cell;
220 FICL_STACK_CHECK(vm->floatStack, 1, 0);
222 cell = ficlStackPop(vm->floatStack);
223 if (cell.f == 1.0f) {
224 ficlDictionaryAppendUnsigned(dictionary, ficlInstructionF1);
225 } else if (cell.f == 0.0f) {
226 ficlDictionaryAppendUnsigned(dictionary, ficlInstructionF0);
227 } else if (cell.f == -1.0f) {
228 ficlDictionaryAppendUnsigned(dictionary, ficlInstructionFNeg1);
229 } else {
230 ficlDictionaryAppendUnsigned(dictionary,
231 ficlInstructionFLiteralParen);
232 ficlDictionaryAppendCell(dictionary, cell);
237 * F l o a t P a r s e S t a t e
238 * Enum to determine the current segement of a floating point number
239 * being parsed.
241 #define NUMISNEG 1
242 #define EXPISNEG 2
244 typedef enum _floatParseState
246 FPS_START,
247 FPS_ININT,
248 FPS_INMANT,
249 FPS_STARTEXP,
250 FPS_INEXP
251 } FloatParseState;
254 * f i c l P a r s e F l o a t N u m b e r
255 * vm -- Virtual Machine pointer.
256 * s -- String to parse.
257 * Returns 1 if successful, 0 if not.
260 ficlVmParseFloatNumber(ficlVm *vm, ficlString s)
262 unsigned char c;
263 unsigned char digit;
264 char *trace;
265 ficlUnsigned length;
266 ficlFloat power;
267 ficlFloat accum = 0.0f;
268 ficlFloat mant = 0.1f;
269 ficlInteger exponent = 0;
270 char flag = 0;
271 FloatParseState estate = FPS_START;
273 FICL_STACK_CHECK(vm->floatStack, 0, 1);
276 * floating point numbers only allowed in base 10
278 if (vm->base != 10)
279 return (0);
281 trace = FICL_STRING_GET_POINTER(s);
282 length = FICL_STRING_GET_LENGTH(s);
284 /* Loop through the string's characters. */
285 while ((length--) && ((c = *trace++) != 0)) {
286 switch (estate) {
287 /* At start of the number so look for a sign. */
288 case FPS_START:
289 estate = FPS_ININT;
290 if (c == '-') {
291 flag |= NUMISNEG;
292 break;
294 if (c == '+') {
295 break;
297 /* FALLTHROUGH */
299 * Converting integer part of number.
300 * Only allow digits, decimal and 'E'.
302 case FPS_ININT:
303 if (c == '.') {
304 estate = FPS_INMANT;
305 } else if ((c == 'e') || (c == 'E')) {
306 estate = FPS_STARTEXP;
307 } else {
308 digit = (unsigned char)(c - '0');
309 if (digit > 9)
310 return (0);
312 accum = accum * 10 + digit;
314 break;
316 * Processing the fraction part of number.
317 * Only allow digits and 'E'
319 case FPS_INMANT:
320 if ((c == 'e') || (c == 'E')) {
321 estate = FPS_STARTEXP;
322 } else {
323 digit = (unsigned char)(c - '0');
324 if (digit > 9)
325 return (0);
327 accum += digit * mant;
328 mant *= 0.1f;
330 break;
331 /* Start processing the exponent part of number. */
332 /* Look for sign. */
333 case FPS_STARTEXP:
334 estate = FPS_INEXP;
336 if (c == '-') {
337 flag |= EXPISNEG;
338 break;
339 } else if (c == '+') {
340 break;
342 /* FALLTHROUGH */
344 * Processing the exponent part of number.
345 * Only allow digits.
347 case FPS_INEXP:
348 digit = (unsigned char)(c - '0');
349 if (digit > 9)
350 return (0);
352 exponent = exponent * 10 + digit;
354 break;
358 /* If parser never made it to the exponent this is not a float. */
359 if (estate < FPS_STARTEXP)
360 return (0);
362 /* Set the sign of the number. */
363 if (flag & NUMISNEG)
364 accum = -accum;
366 /* If exponent is not 0 then adjust number by it. */
367 if (exponent != 0) {
368 /* Determine if exponent is negative. */
369 if (flag & EXPISNEG) {
370 exponent = -exponent;
372 /* power = 10^x */
373 #if defined(_LP64)
374 power = (ficlFloat)pow(10.0, exponent);
375 #else
376 power = (ficlFloat)powf(10.0, exponent);
377 #endif
378 accum *= power;
381 ficlStackPushFloat(vm->floatStack, accum);
382 if (vm->state == FICL_VM_STATE_COMPILE)
383 ficlPrimitiveFLiteralImmediate(vm);
385 return (1);
387 #endif /* FICL_WANT_FLOAT */
389 #if FICL_WANT_LOCALS
390 static void
391 ficlPrimitiveFLocalParen(ficlVm *vm)
393 ficlLocalParen(vm, 0, 1);
396 static void
397 ficlPrimitiveF2LocalParen(ficlVm *vm)
399 ficlLocalParen(vm, 1, 1);
401 #endif /* FICL_WANT_LOCALS */
404 * Add float words to a system's dictionary.
405 * system -- Pointer to the Ficl sytem to add float words to.
407 void
408 ficlSystemCompileFloat(ficlSystem *system)
410 ficlDictionary *dictionary = ficlSystemGetDictionary(system);
411 ficlDictionary *environment = ficlSystemGetEnvironment(system);
412 #if FICL_WANT_FLOAT
413 ficlCell data;
414 #endif
416 FICL_SYSTEM_ASSERT(system, dictionary);
417 FICL_SYSTEM_ASSERT(system, environment);
419 #if FICL_WANT_LOCALS
420 ficlDictionarySetPrimitive(dictionary, "(flocal)",
421 ficlPrimitiveFLocalParen, FICL_WORD_COMPILE_ONLY);
422 ficlDictionarySetPrimitive(dictionary, "(f2local)",
423 ficlPrimitiveF2LocalParen, FICL_WORD_COMPILE_ONLY);
424 #endif /* FICL_WANT_LOCALS */
426 #if FICL_WANT_FLOAT
427 ficlDictionarySetPrimitive(dictionary, "fconstant",
428 ficlPrimitiveFConstant, FICL_WORD_DEFAULT);
429 ficlDictionarySetPrimitive(dictionary, "fvalue",
430 ficlPrimitiveFConstant, FICL_WORD_DEFAULT);
431 ficlDictionarySetPrimitive(dictionary, "f2constant",
432 ficlPrimitiveF2Constant, FICL_WORD_DEFAULT);
433 ficlDictionarySetPrimitive(dictionary, "f2value",
434 ficlPrimitiveF2Constant, FICL_WORD_DEFAULT);
435 ficlDictionarySetPrimitive(dictionary, "fdepth", ficlPrimitiveFDepth,
436 FICL_WORD_DEFAULT);
437 ficlDictionarySetPrimitive(dictionary, "fliteral",
438 ficlPrimitiveFLiteralImmediate, FICL_WORD_IMMEDIATE);
439 ficlDictionarySetPrimitive(dictionary, "f.", ficlPrimitiveFDot,
440 FICL_WORD_DEFAULT);
441 ficlDictionarySetPrimitive(dictionary, "f.s", ficlVmDisplayFloatStack,
442 FICL_WORD_DEFAULT);
443 ficlDictionarySetPrimitive(dictionary, "fe.", ficlPrimitiveEDot,
444 FICL_WORD_DEFAULT);
447 * Missing words:
449 * d>f
450 * f>d
451 * falign
452 * faligned
453 * float+
454 * floats
455 * floor
456 * fmax
457 * fmin
460 #if defined(_LP64)
461 data.f = MAXDOUBLE;
462 #else
463 data.f = MAXFLOAT;
464 #endif
465 ficlDictionarySetConstant(environment, "max-float", data.i);
466 /* not all required words are present */
467 ficlDictionarySetConstant(environment, "floating", FICL_FALSE);
468 ficlDictionarySetConstant(environment, "floating-ext", FICL_FALSE);
469 ficlDictionarySetConstant(environment, "floating-stack",
470 system->stackSize);
471 #else
472 ficlDictionarySetConstant(environment, "floating", FICL_FALSE);
473 #endif