OpenBIOS
Threads by month
- ----- 2026 -----
- July
- June
- May
- April
- March
- February
- January
- ----- 2025 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2024 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2023 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2022 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2021 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2020 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2019 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2018 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2017 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2016 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2015 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2014 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2013 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2012 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2011 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2010 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2009 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2008 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2007 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2006 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2005 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2004 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2003 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2002 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2001 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2000 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 1999 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 1998 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 1997 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 1996 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 1995 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 1994 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 1993 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 1992 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 1991 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 1990 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 1989 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 1988 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 1987 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 1986 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 1985 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 1984 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 1983 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 1982 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 1981 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 1980 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 1979 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 1978 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 1977 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 1976 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 1975 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 1974 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 1973 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 1972 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 1971 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 1970 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 1969 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 1968 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 1967 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 1966 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 1965 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 1964 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 1963 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 1962 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 1961 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 1960 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 1959 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 1958 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 1957 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 1956 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 1955 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 1954 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 1953 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 1952 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 1951 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 1950 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 1949 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 1948 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 1947 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 1946 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 1945 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 1944 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 1943 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 1942 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 1941 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 1940 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 1939 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 1938 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 1937 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 1936 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 1935 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 1934 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 1933 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 1932 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 1931 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 1930 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 1929 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 1928 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 1927 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 1926 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 1925 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 1924 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 1923 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 1922 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 1921 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 1920 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 1919 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 1918 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 1917 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 1916 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 1915 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 1914 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 1913 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 1912 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 1911 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 1910 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 1909 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 1908 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 1907 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 1906 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 1905 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 1904 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
August 2006
- 8 participants
- 16 discussions
The current esp code will perform partial reads on devices with sector sizes >
512. The attached patch makes it read the whole sector from the device, and
uses the additional if multiple blocks are requested.
I'm not sure if the old behavior is technically wrong, but it confused me when
debugging the qemu device emulation :-)
Paul
2
1
Yes, that's essentially what I want. The runiso target in the makefile uses qemu. So that part was easy.
Trying to decipher all the rest of it is where I'm stuck.
John
________________________________
From: Asif Haswarey [mailto:asif.haswarey@qlogic.com]
Sent: Wednesday, August 23, 2006 12:31 PM
To: Fusco, John (GE Healthcare)
Subject: RE: [OpenBIOS] Basic Questions
John,
Exercising the PCI config space is probably what you are looking to do.
Have you actually been able to install OpenBIOS in your Qemu environment/platform?
_____________
Äsif Haswaréy
QLogic Corporation
FCode Driver Development
Phone: 949.389.7607
Fax: 949.389.6308
asif.haswarey(a)qlogic.com
________________________________
From: openbios-bounces(a)openbios.org [mailto:openbios-bounces@openbios.org] On Behalf Of Fusco, John (GE Healthcare)
Sent: Wednesday, August 23, 2006 10:12 AM
To: openbios(a)openbios.org
Subject: [OpenBIOS] Basic Questions
I am investigating the possiblity of using Openbios as a tool to verify our custom PCI designs.
Specifically what I am interested in is the ability to modify the PCI base address registers and excercise the address decoders on the cards. What I'm after is some basic PCI compliance testing that is hard to do with a full blown OS.
My problem is that I'm having a tough time with the learning curve of openbios. I'm having trouble figuring out how to do some basic things, like query the BARs of a PCI device. I'm using Qemu as a sandbox to play with openbios, but I can't even figure out how print the value of configuration register zero of a particular device!
Can anyone steer me in the right direction? Am I wasting my time, or does it sound like Openbios is going to do what I want.
Thanks,
John
2
9
I am investigating the possiblity of using Openbios as a tool to verify
our custom PCI designs.
Specifically what I am interested in is the ability to modify the PCI
base address registers and excercise the address decoders on the cards.
What I'm after is some basic PCI compliance testing that is hard to do
with a full blown OS.
My problem is that I'm having a tough time with the learning curve of
openbios. I'm having trouble figuring out how to do some basic things,
like query the BARs of a PCI device. I'm using Qemu as a sandbox to play
with openbios, but I can't even figure out how print the value of
configuration register zero of a particular device!
Can anyone steer me in the right direction? Am I wasting my time, or
does it sound like Openbios is going to do what I want.
Thanks,
John
1
0
Author: stepan
Date: 2006-08-20 17:59:02 +0200 (Sun, 20 Aug 2006)
New Revision: 79
Modified:
openbios-devel/drivers/esp.c
Log:
Fix booting without CD in drive.
Modified: openbios-devel/drivers/esp.c
===================================================================
--- openbios-devel/drivers/esp.c 2006-08-18 12:57:14 UTC (rev 78)
+++ openbios-devel/drivers/esp.c 2006-08-20 15:59:02 UTC (rev 79)
@@ -118,7 +118,12 @@
// Check status
status = esp->ll->regs[ESP_STATUS];
- if ((status & ESP_STAT_TCNT) != ESP_STAT_TCNT)
+ DPRINTF("do_command: id %d, cmd[0] 0x%x, status 0x%x\n", sd->id, esp->buffer[0], status);
+
+ // Target didn't want all command data or went to status phase
+ // instead of data phase?
+ if ((status & ESP_STAT_TCNT) != ESP_STAT_TCNT
+ || (status & ESP_STAT_PMASK) == ESP_STATP)
return status;
// Get reply
@@ -136,6 +141,8 @@
// Check status
status = esp->ll->regs[ESP_STATUS];
+ DPRINTF("do_command_reply: status 0x%x\n", status);
+
if ((status & ESP_STAT_TCNT) != ESP_STAT_TCNT)
return status;
else
1
0
The attached patch fixes a booting problem when there is no CD in drive.
Please apply.
When there is no disc in drive, READ_CAPACITY command fails and there won't
be any data transfers. Trying to transfer data hangs in recent Qemu.
Remedy: check if target went to status phase instead of data transfer phase,
if so return with error.
_________________________________________________________________
FREE pop-up blocking with the new MSN Toolbar - get it now!
http://toolbar.msn.click-url.com/go/onm00200415ave/direct/01/
1
0
* David L Paktor <dlpaktor(a)us.ibm.com> [060817 21:29]:
> I would like to make two small amendments:
>
> The test suite contains exactly 162 tests. Still a lot, but let's not
> mis-advertise even to a small degree.
Sorry, this is true of course. I just did a rough estimate by counting
the .fth files, which is a little bit inaccurate.
> Modesty prohibits me from saying much more than this, but I hope a look at the
> New Features document,
> and at the Test Log files, will suffice to demonstrate that "a couple of
> significant improvements"
> is very much an understatement... ;-}
Yes, definitely. To emphasize this we have pushed the version number of
the tokenizer to 1.0.
If you want to have a look at the old and the new version, go to:
http://www.openbios.org/~stepan/toke/
Stefan
--
coresystems GmbH • Brahmsstr. 16 • D-79104 Freiburg i. Br.
Tel.: +49 761 7668825 • Fax: +49 761 7664613
Email: info(a)coresystems.de • http://www.coresystems.de/
1
1
Author: stepan
Date: 2006-08-18 14:57:14 +0200 (Fri, 18 Aug 2006)
New Revision: 78
Added:
fcode-utils/toke/toke.doxygen
Modified:
fcode-utils/toke/Makefile
Log:
add toke doxygen documentation target
Modified: fcode-utils/toke/Makefile
===================================================================
--- fcode-utils/toke/Makefile 2006-08-18 12:56:03 UTC (rev 77)
+++ fcode-utils/toke/Makefile 2006-08-18 12:57:14 UTC (rev 78)
@@ -51,6 +51,9 @@
.dependencies: *.c
@$(CC) $(CFLAGS) $(INCLUDES) -MM *.c > .dependencies
+documentation:: *.c *.h toke.doxygen
+ @doxygen toke.doxygen
+
.PHONY: all clean distclean
-include .dependencies
Added: fcode-utils/toke/toke.doxygen
===================================================================
--- fcode-utils/toke/toke.doxygen (rev 0)
+++ fcode-utils/toke/toke.doxygen 2006-08-18 12:57:14 UTC (rev 78)
@@ -0,0 +1,272 @@
+# Doxyfile 1.4.4
+
+#---------------------------------------------------------------------------
+# Project related configuration options
+#---------------------------------------------------------------------------
+PROJECT_NAME = Toke
+PROJECT_NUMBER =
+OUTPUT_DIRECTORY = .
+CREATE_SUBDIRS = YES
+OUTPUT_LANGUAGE = English
+USE_WINDOWS_ENCODING = NO
+BRIEF_MEMBER_DESC = YES
+REPEAT_BRIEF = YES
+ABBREVIATE_BRIEF = "The $name class" \
+ "The $name widget" \
+ "The $name file" \
+ is \
+ provides \
+ specifies \
+ contains \
+ represents \
+ a \
+ an \
+ the
+ALWAYS_DETAILED_SEC = NO
+INLINE_INHERITED_MEMB = NO
+FULL_PATH_NAMES = NO
+STRIP_FROM_PATH =
+STRIP_FROM_INC_PATH =
+SHORT_NAMES = NO
+JAVADOC_AUTOBRIEF = YES
+MULTILINE_CPP_IS_BRIEF = NO
+DETAILS_AT_TOP = NO
+INHERIT_DOCS = YES
+DISTRIBUTE_GROUP_DOC = NO
+SEPARATE_MEMBER_PAGES = NO
+TAB_SIZE = 8
+ALIASES =
+OPTIMIZE_OUTPUT_FOR_C = YES
+OPTIMIZE_OUTPUT_JAVA = NO
+SUBGROUPING = YES
+#---------------------------------------------------------------------------
+# Build related configuration options
+#---------------------------------------------------------------------------
+EXTRACT_ALL = YES
+EXTRACT_PRIVATE = YES
+EXTRACT_STATIC = YES
+EXTRACT_LOCAL_CLASSES = YES
+EXTRACT_LOCAL_METHODS = NO
+HIDE_UNDOC_MEMBERS = NO
+HIDE_UNDOC_CLASSES = NO
+HIDE_FRIEND_COMPOUNDS = NO
+HIDE_IN_BODY_DOCS = NO
+INTERNAL_DOCS = NO
+CASE_SENSE_NAMES = YES
+HIDE_SCOPE_NAMES = NO
+SHOW_INCLUDE_FILES = YES
+INLINE_INFO = YES
+SORT_MEMBER_DOCS = YES
+SORT_BRIEF_DOCS = NO
+SORT_BY_SCOPE_NAME = NO
+GENERATE_TODOLIST = YES
+GENERATE_TESTLIST = YES
+GENERATE_BUGLIST = YES
+GENERATE_DEPRECATEDLIST= YES
+ENABLED_SECTIONS =
+MAX_INITIALIZER_LINES = 30
+SHOW_USED_FILES = YES
+SHOW_DIRECTORIES = YES
+FILE_VERSION_FILTER =
+#---------------------------------------------------------------------------
+# configuration options related to warning and progress messages
+#---------------------------------------------------------------------------
+QUIET = NO
+WARNINGS = YES
+WARN_IF_UNDOCUMENTED = YES
+WARN_IF_DOC_ERROR = YES
+WARN_NO_PARAMDOC = NO
+WARN_FORMAT = "$file:$line: $text"
+WARN_LOGFILE =
+#---------------------------------------------------------------------------
+# configuration options related to the input files
+#---------------------------------------------------------------------------
+INPUT =
+FILE_PATTERNS = *.c \
+ *.cc \
+ *.cxx \
+ *.cpp \
+ *.c++ \
+ *.d \
+ *.java \
+ *.ii \
+ *.ixx \
+ *.ipp \
+ *.i++ \
+ *.inl \
+ *.h \
+ *.hh \
+ *.hxx \
+ *.hpp \
+ *.h++ \
+ *.idl \
+ *.odl \
+ *.cs \
+ *.php \
+ *.php3 \
+ *.inc \
+ *.m \
+ *.mm \
+ *.dox \
+ *.C \
+ *.CC \
+ *.C++ \
+ *.II \
+ *.I++ \
+ *.H \
+ *.HH \
+ *.H++ \
+ *.CS \
+ *.PHP \
+ *.PHP3 \
+ *.M \
+ *.MM
+RECURSIVE = YES
+EXCLUDE =
+EXCLUDE_SYMLINKS = NO
+EXCLUDE_PATTERNS =
+EXAMPLE_PATH =
+EXAMPLE_PATTERNS =
+EXAMPLE_RECURSIVE = NO
+IMAGE_PATH =
+INPUT_FILTER =
+FILTER_PATTERNS =
+FILTER_SOURCE_FILES = NO
+#---------------------------------------------------------------------------
+# configuration options related to source browsing
+#---------------------------------------------------------------------------
+SOURCE_BROWSER = YES
+INLINE_SOURCES = NO
+STRIP_CODE_COMMENTS = YES
+REFERENCED_BY_RELATION = YES
+REFERENCES_RELATION = YES
+USE_HTAGS = NO
+VERBATIM_HEADERS = YES
+#---------------------------------------------------------------------------
+# configuration options related to the alphabetical class index
+#---------------------------------------------------------------------------
+ALPHABETICAL_INDEX = NO
+COLS_IN_ALPHA_INDEX = 5
+IGNORE_PREFIX =
+#---------------------------------------------------------------------------
+# configuration options related to the HTML output
+#---------------------------------------------------------------------------
+GENERATE_HTML = YES
+HTML_OUTPUT = toke-html
+HTML_FILE_EXTENSION = .html
+HTML_HEADER =
+HTML_FOOTER =
+HTML_STYLESHEET =
+HTML_ALIGN_MEMBERS = YES
+GENERATE_HTMLHELP = NO
+CHM_FILE =
+HHC_LOCATION =
+GENERATE_CHI = NO
+BINARY_TOC = NO
+TOC_EXPAND = NO
+DISABLE_INDEX = NO
+ENUM_VALUES_PER_LINE = 4
+GENERATE_TREEVIEW = YES
+TREEVIEW_WIDTH = 250
+#---------------------------------------------------------------------------
+# configuration options related to the LaTeX output
+#---------------------------------------------------------------------------
+GENERATE_LATEX = NO
+LATEX_OUTPUT = latex
+LATEX_CMD_NAME = latex
+MAKEINDEX_CMD_NAME = makeindex
+COMPACT_LATEX = NO
+PAPER_TYPE = a4wide
+EXTRA_PACKAGES =
+LATEX_HEADER =
+PDF_HYPERLINKS = YES
+USE_PDFLATEX = YES
+LATEX_BATCHMODE = NO
+LATEX_HIDE_INDICES = NO
+#---------------------------------------------------------------------------
+# configuration options related to the RTF output
+#---------------------------------------------------------------------------
+GENERATE_RTF = NO
+RTF_OUTPUT = rtf
+COMPACT_RTF = NO
+RTF_HYPERLINKS = NO
+RTF_STYLESHEET_FILE =
+RTF_EXTENSIONS_FILE =
+#---------------------------------------------------------------------------
+# configuration options related to the man page output
+#---------------------------------------------------------------------------
+GENERATE_MAN = NO
+MAN_OUTPUT = man
+MAN_EXTENSION = .3
+MAN_LINKS = NO
+#---------------------------------------------------------------------------
+# configuration options related to the XML output
+#---------------------------------------------------------------------------
+GENERATE_XML = NO
+XML_OUTPUT = xml
+XML_SCHEMA =
+XML_DTD =
+XML_PROGRAMLISTING = YES
+#---------------------------------------------------------------------------
+# configuration options for the AutoGen Definitions output
+#---------------------------------------------------------------------------
+GENERATE_AUTOGEN_DEF = NO
+#---------------------------------------------------------------------------
+# configuration options related to the Perl module output
+#---------------------------------------------------------------------------
+GENERATE_PERLMOD = NO
+PERLMOD_LATEX = NO
+PERLMOD_PRETTY = YES
+PERLMOD_MAKEVAR_PREFIX =
+#---------------------------------------------------------------------------
+# Configuration options related to the preprocessor
+#---------------------------------------------------------------------------
+ENABLE_PREPROCESSING = YES
+MACRO_EXPANSION = NO
+EXPAND_ONLY_PREDEF = NO
+SEARCH_INCLUDES = YES
+INCLUDE_PATH =
+INCLUDE_FILE_PATTERNS =
+PREDEFINED =
+EXPAND_AS_DEFINED =
+SKIP_FUNCTION_MACROS = YES
+#---------------------------------------------------------------------------
+# Configuration::additions related to external references
+#---------------------------------------------------------------------------
+TAGFILES =
+GENERATE_TAGFILE =
+ALLEXTERNALS = NO
+EXTERNAL_GROUPS = YES
+PERL_PATH = /usr/bin/perl
+#---------------------------------------------------------------------------
+# Configuration options related to the dot tool
+#---------------------------------------------------------------------------
+CLASS_DIAGRAMS = YES
+HIDE_UNDOC_RELATIONS = YES
+HAVE_DOT = YES
+CLASS_GRAPH = YES
+COLLABORATION_GRAPH = YES
+GROUP_GRAPHS = YES
+UML_LOOK = YES
+TEMPLATE_RELATIONS = NO
+INCLUDE_GRAPH = YES
+INCLUDED_BY_GRAPH = YES
+CALL_GRAPH = YES
+CALLER_GRAPH = YES
+GRAPHICAL_HIERARCHY = YES
+DIRECTORY_GRAPH = YES
+DOT_IMAGE_FORMAT = png
+DOT_PATH =
+DOTFILE_DIRS =
+MAX_DOT_GRAPH_WIDTH = 1024
+MAX_DOT_GRAPH_HEIGHT = 1024
+MAX_DOT_GRAPH_DEPTH = 1000
+DOT_TRANSPARENT = NO
+DOT_MULTI_TARGETS = NO
+GENERATE_LEGEND = YES
+DOT_CLEANUP = YES
+#---------------------------------------------------------------------------
+# Configuration::additions related to the search engine
+#---------------------------------------------------------------------------
+SEARCHENGINE = NO
+INPUT= clflags.c clflags.h conditl.c conditl.h devnode.c devnode.h dictionary.c dictionary.h emit.c emit.h errhandler.c errhandler.h flowcontrol.c flowcontrol.h macros.c macros.h nextfcode.c nextfcode.h parselocals.c parselocals.h scanner.c scanner.h stack.c stack.h stream.c stream.h strsubvocab.c strsubvocab.h ticvocab.c ticvocab.h toke.c toke.h tokzesc.c tokzesc.h tracesyms.c tracesyms.h usersymbols.c usersymbols.h vocabfuncts.h
1
0
Author: stepan
Date: 2006-08-18 14:56:03 +0200 (Fri, 18 Aug 2006)
New Revision: 77
Added:
fcode-utils/Makefile
fcode-utils/shared/
fcode-utils/shared/classcodes.c
fcode-utils/shared/pcihdr.h
fcode-utils/shared/types.h
Log:
add shared files
Added: fcode-utils/Makefile
===================================================================
--- fcode-utils/Makefile (rev 0)
+++ fcode-utils/Makefile 2006-08-18 12:56:03 UTC (rev 77)
@@ -0,0 +1,47 @@
+#
+# OpenBIOS - free your system!
+# ( Utilities )
+#
+# This program is part of a free implementation of the IEEE 1275-1994
+# Standard for Boot (Initialization Configuration) Firmware.
+#
+# Copyright (C) 2006 coresystems GmbH <info(a)coresystems.de>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; version 2 of the License.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA, 02110-1301 USA
+#
+
+all:
+ make -C toke
+ make -C detok
+ make -C romheaders
+
+install:
+ make -C toke install
+ make -C detok install
+ make -C romheaders install
+
+clean:
+ make -C toke clean
+ make -C detok clean
+ make -C romheaders clean
+
+distclean: clean
+ make -C toke distclean
+ make -C detok distclean
+ make -C romheaders distclean
+
+
+
+.PHONY: all clean distclean toke detok romheaders
+
Added: fcode-utils/shared/classcodes.c
===================================================================
--- fcode-utils/shared/classcodes.c (rev 0)
+++ fcode-utils/shared/classcodes.c 2006-08-18 12:56:03 UTC (rev 77)
@@ -0,0 +1,415 @@
+/*
+ * OpenBIOS - free your system!
+ * ( FCode tokenizer )
+ *
+ * This program is part of a free implementation of the IEEE 1275-1994
+ * Standard for Boot (Initialization Configuration) Firmware.
+ *
+ * Copyright (C) 2001-2005 Stefan Reinauer, <stepan(a)openbios.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA, 02110-1301 USA
+ *
+ */
+
+/* **************************************************************************
+ *
+ * Functions to correlate PCI Device Class-Codes and PCI Code Types
+ * with their printable names.
+ *
+ * (C) Copyright 2005 IBM Corporation. All Rights Reserved.
+ * Module Author: David L. Paktor dlpaktor(a)us.ibm.com
+ *
+ **************************************************************************** */
+
+#include <stdlib.h>
+#include "types.h"
+
+/* **************************************************************************
+ *
+ * Functions Eported:
+ * pci_device_class_name
+ * Convert a numeric PCI Class Code to the Device Class Name
+ *
+ * pci_code_type_name
+ * Convert a numeric PCI Code Type to a printable Name
+ *
+ **************************************************************************** */
+
+const char *pci_device_class_name( u32 code);
+const char *pci_code_type_name(u8 code);
+
+
+typedef struct {
+ const u32 classcode;
+ const char *classname;
+} num_to_name_table ;
+
+
+/* **************************************************************************
+ *
+ * Function name: convert_num_to_name
+ * Synopsis: Find the Name, in the given table, for the given Number.
+ * Support function for Exported Functions.
+ *
+ * Inputs:
+ * Parameters:
+ * u32 num Number to look up
+ * num_to_name_table *table Pointer to Table to scan
+ * int max Maximum Index of Table
+ * char *not_found String to return if Number not in Table
+ *
+ * Outputs:
+ * Returned Value: Pointer to string giving the Name
+ *
+ * Error Detection:
+ * Unrecognized Number
+ * Return "not_found" string
+ *
+ * Process Explanation:
+ * Scan the Table for a match.
+ *
+ * Still to be done / Misc remarks:
+ * Had been considering a more sophisticated binary search,
+ * but the database is too small to merit the extra code.
+ * Stayed with the KISS principle...
+ *
+ *
+ **************************************************************************** */
+
+static const char *convert_num_to_name(u32 num,
+ num_to_name_table *table,
+ int max,
+ const char *not_found)
+{
+ int indx;
+ const char *retval;
+
+ retval = not_found;
+
+ for (indx = 0; indx < max ; indx++)
+ {
+ if ( num == table[indx].classcode )
+ {
+ retval = table[indx].classname ;
+ break ;
+ }
+ }
+ return ( retval );
+}
+
+
+/* **************************************************************************
+ *
+ *
+ * Structures:
+ * pci_code_type_name_table Constant Data Table that correlates
+ * PCI Code Types with their Names.
+ *
+ * pci_dev_class_name_table Constant Data Table that correlates
+ * Class Codes with their Class Names.
+ * This list of codes and names is current
+ * as of PCI Local Bus Specification
+ * Revision 3.0 dated February 3, 2004
+ *
+ **************************************************************************** */
+
+
+static const num_to_name_table pci_code_type_name_table[] = {
+ { 0 , "Intel x86" },
+ { 1 , "Open Firmware" },
+ { 2 , "HP PA Risc" },
+ { 3 , "Intel EFI (unofficial)" }
+};
+
+
+static const num_to_name_table pci_dev_class_name_table[] = {
+ { 0x000000 , "Legacy Device" },
+ { 0x000100 , "VGA-Compatible Device" },
+
+ { 0x010000 , "SCSI bus controller" },
+ /* { 0x0101xx , "IDE controller" }, */
+ { 0x010200 , "Floppy disk controller" },
+ { 0x010300 , "IPI bus controller" },
+ { 0x010400 , "RAID controller" },
+ { 0x010520 , "ATA controller, single stepping" },
+ { 0x010530 , "ATA controller, continuous" },
+ { 0x010600 , "Serial ATA controller - vendor specific interface" },
+ { 0x010601 , "Serial ATA controller - AHCI 1.0 interface" },
+ { 0x010700 , "Serial Attached SCSI controller" },
+ { 0x018000 , "Mass Storage controller" },
+
+ { 0x020000 , "Ethernet controller" },
+ { 0x020100 , "Token Ring controller" },
+ { 0x020200 , "FDDI controller" },
+ { 0x020300 , "ATM controller" },
+ { 0x020400 , "ISDN controller" },
+ { 0x020500 , "WorldFip controller" },
+ /* { 0x0206xx , "PICMG 2.14 Multi Computing" }, */
+ { 0x028000 , "Network controller" },
+
+ { 0x030000 , "VGA Display controller" },
+ { 0x030001 , "8514-compatible Display controller" },
+ { 0x030100 , "XGA Display controller" },
+ { 0x030200 , "3D Display controller" },
+ { 0x038000 , "Display controller" },
+
+ { 0x040000 , "Video device" },
+ { 0x040100 , "Audio device" },
+ { 0x040200 , "Computer Telephony device" },
+ { 0x048000 , "Multimedia device" },
+
+ { 0x050000 , "RAM memory controller" },
+ { 0x050100 , "Flash memory controller" },
+ { 0x058000 , "Memory controller" },
+
+ { 0x060000 , "Host bridge" },
+ { 0x060100 , "ISA bridge" },
+ { 0x060200 , "EISA bridge" },
+ { 0x060300 , "MCA bridge" },
+ { 0x060400 , "PCI-to-PCI bridge" },
+ { 0x060401 , "PCI-to-PCI bridge (subtractive decoding)" },
+ { 0x060500 , "PCMCIA bridge" },
+ { 0x060600 , "NuBus bridge" },
+ { 0x060700 , "CardBus bridge" },
+ /* { 0x0608xx , "RACEway bridge" }, */
+ { 0x060940 , "PCI-to-PCI bridge, Semi-transparent, primary facing Host" },
+ { 0x060980 , "PCI-to-PCI bridge, Semi-transparent, secondary facing Host" },
+ { 0x060A00 , "InfiniBand-to-PCI host bridge" },
+ { 0x068000 , "Bridge device" },
+
+ { 0x070000 , "Generic XT-compatible serial controller" },
+ { 0x070001 , "16450-compatible serial controller" },
+ { 0x070002 , "16550-compatible serial controller" },
+ { 0x070003 , "16650-compatible serial controller" },
+ { 0x070004 , "16750-compatible serial controller" },
+ { 0x070005 , "16850-compatible serial controller" },
+ { 0x070006 , "16950-compatible serial controller" },
+
+ { 0x070100 , "Parallel port" },
+ { 0x070101 , "Bi-directional parallel port" },
+ { 0x070102 , "ECP 1.X compliant parallel port" },
+ { 0x070103 , "IEEE1284 controller" },
+ { 0x0701FE , "IEEE1284 target device" },
+ { 0x070200 , "Multiport serial controller" },
+
+ { 0x070300 , "Generic modem" },
+ { 0x070301 , "Hayes 16450-compatible modem" },
+ { 0x070302 , "Hayes 16550-compatible modem" },
+ { 0x070303 , "Hayes 16650-compatible modem" },
+ { 0x070304 , "Hayes 16750-compatible modem" },
+ { 0x070400 , "GPIB (IEEE 488.1/2) controller" },
+ { 0x070500 , "Smart Card" },
+ { 0x078000 , "Communications device" },
+
+ { 0x080000 , "Generic 8259 PIC" },
+ { 0x080001 , "ISA PIC" },
+ { 0x080002 , "EISA PIC" },
+ { 0x080010 , "I/O APIC interrupt controller" },
+ { 0x080020 , "I/O(x) APIC interrupt controller" },
+
+ { 0x080100 , "Generic 8237 DMA controller" },
+ { 0x080101 , "ISA DMA controller" },
+ { 0x080102 , "EISA DMA controller" },
+
+ { 0x080200 , "Generic 8254 system timer" },
+ { 0x080201 , "ISA system timer" },
+ { 0x080202 , "EISA system timer-pair" },
+
+ { 0x080300 , "Generic RTC controller" },
+ { 0x080301 , "ISA RTC controller" },
+
+ { 0x080400 , "Generic PCI Hot-Plug controller" },
+ { 0x080500 , "SD Host controller" },
+ { 0x088000 , "System peripheral" },
+
+ { 0x090000 , "Keyboard controller" },
+ { 0x090100 , "Digitizer (pen)" },
+ { 0x090200 , "Mouse controller" },
+ { 0x090300 , "Scanner controller" },
+ { 0x090400 , "Generic Gameport controller" },
+ { 0x090410 , "Legacy Gameport controller" },
+ { 0x098000 , "Input controller" },
+
+ { 0x0a0000 , "Generic docking station" },
+ { 0x0a8000 , "Docking station" },
+
+ { 0x0b0000 , "386 Processor" },
+ { 0x0b0100 , "486 Processor" },
+ { 0x0b0200 , "Pentium Processor" },
+ { 0x0b1000 , "Alpha Processor" },
+ { 0x0b2000 , "PowerPC Processor" },
+ { 0x0b3000 , "MIPS Processor" },
+ { 0x0b4000 , "Co-processor" },
+
+ { 0x0c0000 , "IEEE 1394 (FireWire)" },
+ { 0x0c0010 , "IEEE 1394 -- OpenHCI spec" },
+ { 0x0c0100 , "ACCESS.bus" },
+ { 0x0c0200 , "SSA" },
+ { 0x0c0300 , "Universal Serial Bus (UHC spec)" },
+ { 0x0c0310 , "Universal Serial Bus (Open Host spec)" },
+ { 0x0c0320 , "USB2 Host controller (Intel Enhanced HCI spec)" },
+ { 0x0c0380 , "Universal Serial Bus (no PI spec)" },
+ { 0x0c03FE , "USB Target Device" },
+ { 0x0c0400 , "Fibre Channel" },
+ { 0x0c0500 , "System Management Bus" },
+ { 0x0c0600 , "InfiniBand" },
+ { 0x0c0700 , "IPMI SMIC Interface" },
+ { 0x0c0701 , "IPMI Kybd Controller Style Interface" },
+ { 0x0c0702 , "IPMI Block Transfer Interface" },
+ /* { 0x0c08xx , "SERCOS Interface" }, */
+ { 0x0c0900 , "CANbus" },
+
+ { 0x0d100 , "iRDA compatible controller" },
+ { 0x0d100 , "Consumer IR controller" },
+ { 0x0d100 , "RF controller" },
+ { 0x0d100 , "Bluetooth controller" },
+ { 0x0d100 , "Broadband controller" },
+ { 0x0d100 , "Ethernet (802.11a 5 GHz) controller" },
+ { 0x0d100 , "Ethernet (802.11b 2.4 GHz) controller" },
+ { 0x0d100 , "Wireless controller" },
+
+ /* { 0x0e00xx , "I2O Intelligent I/O, spec 1.0" }, */
+ { 0x0e0000 , "Message FIFO at offset 040h" },
+
+ { 0x0f0100 , "TV satellite comm. controller" },
+ { 0x0f0200 , "Audio satellite comm. controller" },
+ { 0x0f0300 , "Voice satellite comm. controller" },
+ { 0x0f0400 , "Data satellite comm. controller" },
+
+ { 0x100000 , "Network and computing en/decryption" },
+ { 0x101000 , "Entertainment en/decryption" },
+ { 0x108000 , "En/Decryption" },
+
+ { 0x110000 , "DPIO modules" },
+ { 0x110100 , "Perf. counters" },
+ { 0x111000 , "Comm. synch., time and freq. test" },
+ { 0x112000 , "Management card" },
+ { 0x118000 , "Data acq./Signal proc." },
+
+};
+
+
+/* **************************************************************************
+ *
+ * PCI Class Code name calculations are further complicated by the
+ * fact that there are some combinations of Base Class and
+ * Sub-Class for which no specific register-level programming
+ * interfaces are defined, or, in other words, for which all
+ * possible numeric values of Programming Interface codes
+ * (i.e., the low-byte) are valid.
+ *
+ * The following table lists the Base Class / Sub-Class pairs to
+ * accept without matching the Programming Interface, along
+ * with their names.
+ *
+ **************************************************************************** */
+
+
+static const num_to_name_table pci_all_prg_intfcs_table[] = {
+ { 0x0101 , "IDE controller" },
+ { 0x0206 , "PICMG 2.14 Multi Computing" },
+ { 0x0608 , "RACEway bridge" },
+ { 0x0c08 , "SERCOS Interface" },
+ { 0x0e00 , "I2O Intelligent I/O, spec 1.0" },
+};
+
+
+/* **************************************************************************
+ *
+ * Function name: pci_device_class_name
+ * Synopsis: Return the Device Class Name for the given Class Code
+ *
+ * Inputs:
+ * Parameters:
+ * u32 code Numeric PCI Class Code
+ *
+ * Outputs:
+ * Returned Value: Pointer to string giving the Device Class Name
+ *
+ * Error Detection:
+ * Unrecognized Class Code
+ * String returned is "unknown"
+ *
+ * Process Explanation:
+ * Scan the pci_dev_class_name_table for a match.
+ * If one is not found there, drop the low (Programming Interface)
+ * byte of the code and scan the pci_all_prg_intfcs_table
+ * for a match that way
+ * If you didn't find one there, you've exhausted your options...
+ *
+ **************************************************************************** */
+
+const char *pci_device_class_name( u32 code)
+{
+ const int pdc_max_indx =
+ sizeof(pci_dev_class_name_table)/sizeof(num_to_name_table) ;
+ const char *result ;
+
+ result = convert_num_to_name(
+ code,
+ (num_to_name_table *)pci_dev_class_name_table,
+ pdc_max_indx,
+ NULL);
+
+ if ( result == NULL)
+ {
+ const int pallpi_max_indx =
+ sizeof(pci_all_prg_intfcs_table)/sizeof(num_to_name_table) ;
+
+ result = convert_num_to_name(
+ code>>8,
+ (num_to_name_table *)pci_all_prg_intfcs_table,
+ pallpi_max_indx,
+ "unknown");
+ }
+ return ( result );
+}
+
+
+/* **************************************************************************
+ *
+ * Function name: pci_code_type_name
+ * Synopsis: Return a printable Name for the given PCI Code Type
+ *
+ * Inputs:
+ * Parameters:
+ * u8 code Numeric PCI Code Type
+ *
+ * Outputs:
+ * Returned Value: Pointer to string giving printable Name
+ *
+ * Error Detection:
+ * Unrecognized PCI Code Type
+ * String returned is "unknown as of PCI specs 2.2"
+ *
+ * Process Explanation:
+ * Scan the pci_code_type_name_table for a match.
+ *
+ *
+ **************************************************************************** */
+
+const char *pci_code_type_name(u8 code)
+{
+ const int pct_max_indx =
+ sizeof(pci_code_type_name_table)/sizeof(num_to_name_table) ;
+ const char *result ;
+
+ result = convert_num_to_name(
+ (u32)code,
+ (num_to_name_table *)pci_code_type_name_table,
+ pct_max_indx,
+ "unknown as of PCI specs 2.2");
+ return ( result );
+}
+
Added: fcode-utils/shared/pcihdr.h
===================================================================
--- fcode-utils/shared/pcihdr.h (rev 0)
+++ fcode-utils/shared/pcihdr.h 2006-08-18 12:56:03 UTC (rev 77)
@@ -0,0 +1,176 @@
+#ifndef _PCIHDR_H
+#define _PCIHDR_H
+/*
+ * OpenBIOS - free your system!
+ * ( PCI headers )
+ *
+ * This program is part of a free implementation of the IEEE 1275-1994
+ * Standard for Boot (Initialization Configuration) Firmware.
+ *
+ * Copyright (C) 2001-2005 Stefan Reinauer, <stepan(a)openbios.org>
+ * Copyright (C) 2006 coresystems GmbH <info(a)coresystems.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA, 02110-1301 USA
+ *
+ */
+
+/* **************************************************************************
+ *
+ * PCI Header and PCI Data Structures, as defined in
+ * PCI FIRMWARE SPECIFICATION, REV. 3.
+ * taken from openbios/utils/romheaders/romheaders.c
+ *
+ * (C) Copyright 2005 IBM Corporation. All Rights Reserved.
+ * Module Author: David L. Paktor dlpaktor(a)us.ibm.com
+ *
+ *
+ **************************************************************************** */
+
+
+/* **************************************************************************
+ *
+ * Structures:
+ * rom_header_t Type definition for a PCI ROM Header
+ * pci_data_t Type definition for a PCI Data Header
+ *
+ *
+ * Macros:
+ * PCI_DATA_HDR Construct the PCI Data Header signature
+ * as an integer. Use this to create
+ * a constant, in order to allow its
+ * value to be calculated at compile-
+ * -time rather than at run-time.
+ * BIG_ENDIAN_WORD_FETCH Fetch a big-endian word from 2
+ * unsigned chars in sequence.
+ * LITTLE_ENDIAN_WORD_FETCH ...... little-endian word from 2 ....
+ * BIG_ENDIAN_LONG_FETCH ...... big-endian long from 4 ...
+ * LITTLE_ENDIAN_LONG_FETCH ...... little-endian long from 4 ....
+ * LITTLE_ENDIAN_TRIPLET_FETCH ...... little-endian triplet from 3 ...
+ * CLASS_CODE_FETCH Special fetch for Class-Code triplet
+ * BIG_ENDIAN_WORD_STORE Store an integer into 2 unsigned
+ * chars in big-endian sequence
+ * LITTLE_ENDIAN_WORD_STORE ..... into 2 ... little-endian ...
+ * BIG_ENDIAN_LONG_STORE ..... into 4 ... big-endian ...
+ * LITTLE_ENDIAN_LONG_STORE ..... into 4 ... little-endian ...
+ * LITTLE_ENDIAN_TRIPLET_STORE ..... 3 ... little-endian triplet ...
+ * CLASS_CODE_STORE Special store for Class-Code triplet
+ *
+ **************************************************************************** */
+
+/* **************************************************************************
+ *
+ * Still to be done:
+ * The "Endian" macros are beginning to appear to be more
+ * generally useful that previously thought, and should,
+ * perhaps, be moved into types.h
+ *
+ **************************************************************************** */
+
+#include "types.h"
+/* Construct the PCI Data Header signature as an integer */
+#define PCI_DATA_HDR (u32) ( ('P' << 24) | ('C' << 16) | ('I' << 8) | 'R' )
+
+#ifndef bswap_16
+#define bswap_16(x) \
+ ((((x) >> 8) & 0xff) | (((x) & 0xff) << 8))
+#endif
+
+#define little_word(x) bswap_16(x)
+
+/* These are mnemonics for the programmer. The compiler doesn't care... */
+#define le_u16(x) u8 x[2]
+#define be_u16(x) u8 x[2]
+#define le_u32(x) u8 x[4]
+#define be_u32(x) u8 x[4]
+
+/* Fetch a big-endian word from 2 unsigned chars in sequence */
+#define BIG_ENDIAN_WORD_FETCH(x) (u16)( (x[0] << 8) | x[1] )
+
+/* Fetch a little-endian word from 2 unsigned chars in sequence */
+#define LITTLE_ENDIAN_WORD_FETCH(x) (u16)( (x[1] << 8) | x[0] )
+
+/* Fetch a big-endian long from 4 unsigned chars in sequence */
+#define BIG_ENDIAN_LONG_FETCH(x) (u32)( (x[0] << 24) | (x[1] << 16) | (x[2] << 8) | x[3] )
+
+/* Fetch a little-endian long from 4 unsigned chars in sequence */
+#define LITTLE_ENDIAN_LONG_FETCH(x) (u32)( (x[3] << 24) | (x[2] << 16) | (x[1] << 8) | x[0] )
+
+#define LE_U24(x) u8 x[3]
+/* Fetch a little-endian triplet from 3 unsigned chars in sequence */
+#define LITTLE_ENDIAN_TRIPLET_FETCH(x) (u32)( (x[2] << 16) | (x[1] << 8) | x[0] )
+
+
+/* Special case for Class-Code triplet: lo, mid, hi */
+#define class_code_u24(x) u8 x[3]
+/* Special fetch for Class-Code triplet */
+#define CLASS_CODE_FETCH(x) (u32)( (x[2] << 16) | (x[1] << 8) | x[0] )
+/* Special store for Class-Code triplet */
+#define CLASS_CODE_STORE(dest,x) \
+ dest[2] = (u8)( x >> 16); dest[1] = (u8)(x >> 8); dest[0] = (u8)x;
+ /* NOTE Class-Code triplet is the same as little-endian triplet */
+ /* Change over some time, eh? */
+
+/* Store an integer into 2 unsigned chars in big-endian sequence */
+#define BIG_ENDIAN_WORD_STORE(dest,x) dest[0] = (u8)(x >> 8); dest[1]=(u8)x;
+
+/* Store an integer into 2 unsigned chars in little-endian sequence */
+#define LITTLE_ENDIAN_WORD_STORE(dest,x) dest[1] = (u8)(x >> 8); dest[0]=(u8)x;
+
+/* Store an integer into 4 unsigned chars in big-endian sequence */
+#define BIG_ENDIAN_LONG_STORE(dest,x) \
+ dest[0] = (u8)(x >> 24); dest[1] =(u8)( x >> 16); \
+ dest[2] = (u8)(x >> 8); dest[3] =(u8)x;
+
+/* Store an integer into 4 unsigned chars in little-endian sequence */
+#define LITTLE_ENDIAN_LONG_STORE(dest,x) \
+ dest[3] = (u8)(x >> 24); dest[2] =(u8)( x >> 16); \
+ dest[1] = (u8)(x >> 8); dest[0] =(u8)x;
+
+/* Store an integer into 3 unsigned chars in little-endian triplet sequence */
+#define LITTLE_ENDIAN_TRIPLET_STORE(dest,x) \
+ dest[2] = (u8)( x >> 16); dest[1] = (u8)(x >> 8); dest[0] = (u8)x;
+
+
+typedef struct {
+ be_u16(signature);
+ u8 reserved[0x16];
+ le_u16(data_ptr);
+ le_u16(padd);
+} rom_header_t;
+
+
+typedef struct {
+ be_u32 (signature);
+ le_u16 (vendor);
+ le_u16 (device);
+ le_u16 (vpd);
+ le_u16 (dlen);
+ u8 drevision;
+ class_code_u24 (class_code);
+ le_u16 (ilen);
+ le_u16 (irevision);
+ u8 code_type;
+ u8 last_image_flag;
+ u16 reserved_2;
+} pci_data_t;
+
+#define PCI_DATA_STRUCT_REV 0
+
+/* Prototypes for functions exported from devsupp/pci/classcodes.c */
+char *pci_device_class_name( u32 code);
+char *pci_code_type_name(u8 code);
+
+
+
+#endif /* _PCIHDR_H */
Added: fcode-utils/shared/types.h
===================================================================
--- fcode-utils/shared/types.h (rev 0)
+++ fcode-utils/shared/types.h 2006-08-18 12:56:03 UTC (rev 77)
@@ -0,0 +1,97 @@
+#ifndef _OPENBIOS_TYPES_H
+#define _OPENBIOS_TYPES_H
+
+/*
+ * OpenBIOS - free your system!
+ * ( FCode tokenizer )
+ *
+ * This program is part of a free implementation of the IEEE 1275-1994
+ * Standard for Boot (Initialization Configuration) Firmware.
+ *
+ * Copyright (C) 2001-2005 Stefan Reinauer, <stepan(a)openbios.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA, 02110-1301 USA
+ *
+ */
+
+/* **************************************************************************
+ *
+ * Convert system short-name data-types found in asm/types.h
+ * to OpenBios-style names. (Mainly, remove the leading
+ * double-Underbar).
+ *
+ * Also, define a very useful "bool" type for logical operations,
+ * and maybe a macro (or several) to go with it...
+ *
+ * (C) Copyright 2005 IBM Corporation. All Rights Reserved.
+ * Module Author: David L. Paktor dlpaktor(a)us.ibm.com
+ *
+ **************************************************************************** */
+
+
+#include <asm/types.h>
+
+typedef __s8 s8;
+typedef __u8 u8;
+
+typedef __s16 s16;
+typedef __u16 u16;
+
+typedef __s32 s32;
+typedef __u32 u32;
+
+#ifdef FALSE /* Hack for AIX. */
+#undef FALSE
+#undef TRUE
+#endif /* Hack for AIX. */
+
+typedef enum boolean { FALSE = 0 , TRUE = -1 } bool ;
+
+
+/* **************************************************************************
+ * Macro Name: BOOLVAL
+ * Convert the supplied variable or expression to
+ * a formal boolean.
+ * Argument:
+ * x (bool) Variable or expression, operand.
+ *
+ **************************************************************************** */
+
+#define BOOLVAL(x) (x ? TRUE : FALSE)
+
+
+/* **************************************************************************
+ * Macro Name: INVERSE
+ * Return the logical inversion of the
+ * supplied boolean variable or expression.
+ * Argument:
+ * x (bool) Variable or expression, operand.
+ *
+ **************************************************************************** */
+
+#define INVERSE(x) (x ? FALSE : TRUE)
+
+
+/* **************************************************************************
+*
+ * Some hacks stuck in for systems w/ incomplete includes
+ * or libraries or whatever.
+ *
+ **************************************************************************** */
+
+#ifndef _PTR
+#define _PTR void *
+#endif
+
+#endif /* _OPENBIOS_TYPES_H */
1
0
Author: stepan
Date: 2006-08-18 14:47:12 +0200 (Fri, 18 Aug 2006)
New Revision: 76
Added:
fcode-utils/detok/addfcodes.c
fcode-utils/detok/addfcodes.h
fcode-utils/detok/pcihdr.c
fcode-utils/detok/printformats.c
fcode-utils/toke/clflags.c
fcode-utils/toke/clflags.h
fcode-utils/toke/conditl.c
fcode-utils/toke/conditl.h
fcode-utils/toke/devnode.c
fcode-utils/toke/devnode.h
fcode-utils/toke/errhandler.c
fcode-utils/toke/errhandler.h
fcode-utils/toke/flowcontrol.c
fcode-utils/toke/flowcontrol.h
fcode-utils/toke/macros.h
fcode-utils/toke/nextfcode.c
fcode-utils/toke/nextfcode.h
fcode-utils/toke/parselocals.c
fcode-utils/toke/parselocals.h
fcode-utils/toke/scanner.h
fcode-utils/toke/strsubvocab.c
fcode-utils/toke/strsubvocab.h
fcode-utils/toke/ticvocab.c
fcode-utils/toke/ticvocab.h
fcode-utils/toke/tokzesc.c
fcode-utils/toke/tokzesc.h
fcode-utils/toke/tracesyms.c
fcode-utils/toke/tracesyms.h
fcode-utils/toke/usersymbols.c
fcode-utils/toke/usersymbols.h
fcode-utils/toke/vocabfuncts.h
Removed:
fcode-utils/detok/Rules.make
fcode-utils/toke/Rules.make
Modified:
fcode-utils/detok/Makefile
fcode-utils/detok/decode.c
fcode-utils/detok/detok.c
fcode-utils/detok/detok.h
fcode-utils/detok/dictionary.c
fcode-utils/detok/stream.c
fcode-utils/detok/stream.h
fcode-utils/romheaders/Makefile
fcode-utils/romheaders/romheaders.c
fcode-utils/toke/Makefile
fcode-utils/toke/dictionary.c
fcode-utils/toke/dictionary.h
fcode-utils/toke/emit.c
fcode-utils/toke/emit.h
fcode-utils/toke/macros.c
fcode-utils/toke/scanner.c
fcode-utils/toke/stack.c
fcode-utils/toke/stack.h
fcode-utils/toke/stream.c
fcode-utils/toke/stream.h
fcode-utils/toke/toke.c
fcode-utils/toke/toke.h
Log:
initial merge of David Paktor's fine work.
I redid all of the Makefiles and fixed some minor
issues with the code.
Modified: fcode-utils/detok/Makefile
===================================================================
--- fcode-utils/detok/Makefile 2006-08-18 09:45:11 UTC (rev 75)
+++ fcode-utils/detok/Makefile 2006-08-18 12:47:12 UTC (rev 76)
@@ -1,11 +1,12 @@
#
-# OpenBIOS - free your system!
-# ( detokenizer )
-#
-# This program is part of a free implementation of the IEEE 1275-1994
+# OpenBIOS - free your system!
+# ( Utilities )
+#
+# This program is part of a free implementation of the IEEE 1275-1994
# Standard for Boot (Initialization Configuration) Firmware.
#
-# Copyright (C) 2001-2005 Stefan Reinauer, <stepan(a)openbios.org>
+# Copyright (C) 2001-2006 Stefan Reinauer <stepan(a)openbios.org>
+# Copyright (C) 2006 coresystems GmbH <info(a)coresystems.de>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
@@ -21,48 +22,37 @@
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA, 02110-1301 USA
#
-ARCH := $(shell uname -m | sed -e s/i.86/x86/ -e s/sun4u/sparc64/ -e s/arm.*/arm/ -e s/sa110/arm/ -e s/x86_64/amd64/ -e "s/Power Macintosh/ppc/")
-TOPDIR := $(shell /bin/pwd)
-BUILDDIR ?= $(TOPDIR)/obj-$(ARCH)
+PROGRAM = detok
-VPATH := $(BUILDDIR)
+CC = gcc
+STRIP = strip
+INCLUDES = -I../shared
+#CFLAGS = -O2 -g -Wall
+CFLAGS = -Os -Wall -Wno-pointer-sign
+LDFLAGS =
+OBJS = addfcodes.o decode.o detok.o dictionary.o pcihdr.o printformats.o \
+ stream.o ../shared/classcodes.o
-include $(TOPDIR)/Rules.make
+all: .dependencies $(PROGRAM)
+$(PROGRAM): $(OBJS)
+ $(CC) -o $(PROGRAM) $(OBJS) $(LDFLAGS)
+ $(STRIP) -s $(PROGRAM)
-CC = gcc
-CFLAGS = -O2 -Wall -ansi
+clean:
+ rm -f $(OBJS) *~
-# For debugging the indentation code of detok, define DEBUG_INDENT
-#CFLAGS := $(CFLAGS) -DDEBUG_INDENT
+distclean: clean
+ rm -f $(PROGRAM) .dependencies
+
+.dependencies: *.c
+ @$(CC) $(CFLAGS) $(INCLUDES) -MM *.c > .dependencies
-all: main detok
- @echo -e "\nOpenBIOS detokenizer detok build finished\n"
+.PHONY: all clean distclean
-main:
- @echo -e "\nWelcome to the OpenBIOS detokenizer.."
- @test -r $(BUILDDIR) || ( mkdir -p $(BUILDDIR); \
- echo -e "\nCreating build directory $(BUILDDIR)" )
-
-detok: detok.o dictionary.o decode.o stream.o
- @echo -en "\nLinking fcode detokenizer detok..."
- @cd $(BUILDDIR) && ( $(CC) $(CFLAGS) $^ -o $@; strip detok )
- @echo -e "\tok"
-
-clean:
- @test ! -d $(BUILDDIR) && \
- echo "Architecture $(ARCH) is already clean." || \
- ( \
- echo "Cleaning up architecture $(ARCH)"; \
- rm -rf $(BUILDDIR) \
- rm forth.dict.core \
- )
+-include .dependencies
-distclean: clean
- rm -f detok
+.c.o:
+ $(CC) -c $(CFLAGS) $(INCLUDES) $< -o $@
-detok.o: detok.h stream.h detok.c
-stream.o: detok.h stream.c
-decode.o: detok.h stream.h decode.c Makefile
-dictionary.o: detok.h dictionary.c
Deleted: fcode-utils/detok/Rules.make
===================================================================
--- fcode-utils/detok/Rules.make 2006-08-18 09:45:11 UTC (rev 75)
+++ fcode-utils/detok/Rules.make 2006-08-18 12:47:12 UTC (rev 76)
@@ -1,17 +0,0 @@
-# tag: Makefile rules
-
-VPATH := $(VPATH):.
-
-.S.o:
- echo -n " assembling $<... "
- $(CC) -c -nostdlib $(INCLUDES) $(CFLAGS) $< -o $(BUILDDIR)/$@ && \
- echo -e " \t\tok" || \
- echo -e " \t\tfailed"
-
-.c.o:
- @echo -n " compiling $<... "
- @$(CC) -c $(CFLAGS) $(INCLUDES) $< -o $(BUILDDIR)/$@ && \
- echo -e " \t\tok" || \
- echo -e " \t\failed"
-
-
Added: fcode-utils/detok/addfcodes.c
===================================================================
--- fcode-utils/detok/addfcodes.c (rev 0)
+++ fcode-utils/detok/addfcodes.c 2006-08-18 12:47:12 UTC (rev 76)
@@ -0,0 +1,343 @@
+/*
+ * OpenBIOS - free your system!
+ * ( FCode tokenizer )
+ *
+ * This program is part of a free implementation of the IEEE 1275-1994
+ * Standard for Boot (Initialization Configuration) Firmware.
+ *
+ * Copyright (C) 2001-2005 Stefan Reinauer, <stepan(a)openbios.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA, 02110-1301 USA
+ *
+ */
+
+/* **************************************************************************
+ *
+ * Function(s) for entering Vendor-Specific FCodes to detokenizer.
+ *
+ * (C) Copyright 2006 IBM Corporation. All Rights Reserved.
+ * Module Author: David L. Paktor dlpaktor(a)us.ibm.com
+ *
+ **************************************************************************** */
+
+/* **************************************************************************
+ *
+ * Functions Exported:
+ * add_fcodes_from_list Add Vendor-Specific FCodes from
+ * the file whose name is supplied.
+ *
+ **************************************************************************** */
+
+/* **************************************************************************
+ *
+ * Revision History:
+ * Tue, 25 Apr 2006 by David L. Paktor
+ * Identified this need when working with in-house code,
+ * which uses some custom functions. This solution
+ * is (hoped to be) general enough to cover all cases.
+ *
+ **************************************************************************** */
+
+
+/* **************************************************************************
+ *
+ * Global Variables Imported
+ * indata Buffer into which the file will be read
+ * stream_max Size of the file buffer.
+ *
+ **************************************************************************** */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "detok.h"
+#include "stream.h"
+#include "addfcodes.h"
+
+/* **************************************************************************
+ *
+ * Internal Static Variables
+ * current_vfc_line Line to be scanned in Vendor-FCodes buffer
+ * vfc_remainder Remainder of Vendor-FCodes buffer to be scanned
+ * vfc_line_no Number of current line in Vendor-FCodes buffer
+ * vfc_buf_end Pointer to end of Vendor-FCodes buffer
+ *
+ **************************************************************************** */
+
+static char *current_vfc_line;
+static char *vfc_remainder;
+static int vfc_line_no = 0;
+static char *vfc_buf_end;
+
+/* **************************************************************************
+ *
+ * Function name: skip_whitespace
+ * Synopsis: Advance the given string-pointer past blanks and tabs.
+ * (String is presumed to end before new-line)
+ *
+ * Inputs:
+ * Parameters:
+ * string_line_ptr Address of pointer to string
+ *
+ * Outputs:
+ * Returned Value: None
+ * *string_line_ptr Advanced past blanks and tabs
+ *
+ **************************************************************************** */
+
+static void skip_whitespace( char **string_line_ptr)
+{
+ char *cur_char_ptr = *string_line_ptr;
+ for ( ; *cur_char_ptr != 0 ; cur_char_ptr++ )
+ {
+ if ( (*cur_char_ptr != '\t') && (*cur_char_ptr != ' ') )
+ {
+ *string_line_ptr = cur_char_ptr;
+ break;
+ }
+ }
+}
+
+/* **************************************************************************
+ *
+ * Function name: get_next_vfc_line
+ * Synopsis: Advance to the next vfc_line to be processed.
+ * Skip blanks and comments. Indicate when end reached.
+ *
+ * Inputs:
+ * Parameters: None
+ * Local Static Variables:
+ * vfc_remainder
+ * vfc_buf_end
+ *
+ * Outputs:
+ * Returned Value: FALSE if reached end of buffer
+ * Local Static Variables:
+ * current_vfc_line Advanced to next line to be scanned
+ * vfc_line_no Kept in sync with line number in file
+ *
+ * Process Explanation:
+ * Comments begin with a pound-sign ('#') or a backslash ('\')
+ * Comment-lines or blank or empty lines will be skipped.
+ *
+ **************************************************************************** */
+
+static bool get_next_vfc_line( void )
+{
+ bool retval = FALSE; /* TRUE = not at end yet */
+ while ( vfc_remainder < vfc_buf_end )
+ {
+ current_vfc_line = vfc_remainder;
+ vfc_remainder = strchr( current_vfc_line, '\n');
+ *vfc_remainder = 0;
+ vfc_remainder++;
+ vfc_line_no++;
+ skip_whitespace( ¤t_vfc_line);
+ if ( *current_vfc_line == 0 ) continue; /* Blank line */
+ if ( *current_vfc_line == '#' ) continue; /* Comment */
+ if ( *current_vfc_line == '\\' ) continue; /* Comment */
+ retval = TRUE;
+ break; /* Found something */
+ }
+ return( retval);
+}
+
+/* **************************************************************************
+ *
+ * Function name: vfc_splash
+ * Synopsis: Print a "splash" message to show that we
+ * are processing Vendor-Specific FCodes,
+ * but only once.
+ *
+ * Inputs:
+ * Parameters:
+ * vf_file_name Vendor-Specific FCodes file name
+ * Local Static Variables:
+ * did_not_splash Control printing; once only.
+ *
+ * Outputs:
+ * Returned Value: None
+ * Local Static Variables:
+ * did_not_splash FALSE after first call.
+ * Printout:
+ * "Splash" message...
+ *
+ **************************************************************************** */
+static bool did_not_splash = TRUE;
+static void vfc_splash( char *vf_file_name)
+{
+ if ( did_not_splash )
+ {
+ /* Temporary substring buffer */
+ /* Guarantee that the malloc will be big enough. */
+ char *strbfr = malloc( strlen( vf_file_name) +65 ) ;
+ sprintf( strbfr,
+ "Reading additional FCodes from file: %s\n",
+ vf_file_name);
+ printremark( strbfr);
+ free( strbfr);
+ did_not_splash = FALSE;
+ }
+}
+
+/* **************************************************************************
+ *
+ * Function name: add_fcodes_from_list
+ * Synopsis: Add Vendor-Specific FCodes from the named file
+ * to the permanent resident dictionary.
+ *
+ * Inputs:
+ * Parameters:
+ * vf_file_name Vendor-Specific FCodes file name
+ * Global Variables:
+ * verbose "Verbose" flag.
+ * indata Start of file buffer
+ * stream_max Size of the file buffer.
+ *
+ * Outputs:
+ * Returned Value: TRUE if FCodes have actually been added
+ * Global Variables:
+ * check_tok_seq Cleared to FALSE, then restored to TRUE
+ * Local Static Variables:
+ * vfc_remainder Initted to start of file buffer
+ * vfc_buf_end Initted to end of file buffer
+ * Memory Allocated
+ * Permanent copy of FCode Name
+ * When Freed?
+ * Never. Rmeains until program termination.
+ * Printout:
+ * If verbose, "Splash" line and count of added entries.
+ *
+ * Error Detection:
+ * Fail to open or read Vendor-FCodes file -- Exit program
+ * Improperly formatted input line -- print message and ignore
+ * FCode value out of valid range -- print message and ignore
+ * FCode value already in use -- print message and ignore
+ *
+ * Process Explanation:
+ * Valid lines are formatted with the FCode number first
+ * and the name after, one entry per line. Extra text
+ * after the name will be ignored, so an extra "comment"
+ * is permitted. The FCode number must be in hex, with
+ * an optional leading 0x or 0X For example: 0X407
+ * The valid range is 0x010 to 0x7ff. Numbers above 0x800
+ * infringe upon the are reserved for FCodes generated
+ * by the tokenization process.
+ * Numbers already in use will be ignored. A Message will be
+ * printed even if the name matches the one on the line.
+ *
+ **************************************************************************** */
+
+bool add_fcodes_from_list( char *vf_file_name)
+{
+ bool retval = FALSE;
+ int added_fc_count = 0;
+ check_tok_seq = FALSE;
+
+ if ( verbose ) vfc_splash( vf_file_name);
+
+ if ( init_stream( vf_file_name) != 0 )
+ {
+ char *strbfr = malloc( strlen( vf_file_name) +65 );
+ sprintf( strbfr,
+ "Could not open Additional FCodes file: %s\n",
+ vf_file_name);
+ printremark( strbfr);
+ free( strbfr);
+ exit(1);
+ }
+ vfc_remainder = indata;
+ vfc_buf_end = indata + stream_max -1;
+
+ while ( get_next_vfc_line() )
+ {
+ char vs_fc_name[36];
+ int vs_fc_number;
+ int scan_result;
+ char *lookup_result;
+ char *fc_name_cpy;
+
+ scan_result = sscanf( current_vfc_line, "0x%x %32s",
+ &vs_fc_number, vs_fc_name);
+
+ if ( scan_result != 2 ) /* Allow a capital 0X */
+ {
+ scan_result = sscanf( current_vfc_line, "0X%x %32s",
+ &vs_fc_number, vs_fc_name);
+ }
+ if ( scan_result != 2 ) /* Try it without the 0x */
+ {
+ scan_result = sscanf( current_vfc_line, "%x %32s",
+ &vs_fc_number, vs_fc_name);
+ }
+
+ if ( scan_result != 2 ) /* That's it... */
+ {
+ char *strbfr = malloc( strlen( current_vfc_line) +65 );
+ vfc_splash( vf_file_name);
+ sprintf( strbfr,
+ "Line #%d, invalid format. Ignoring: %s\n",
+ vfc_line_no, current_vfc_line);
+ printremark( strbfr);
+ free( strbfr);
+ continue;
+ }
+
+ if ( ( vs_fc_number < 0x10 ) || ( vs_fc_number > 0x7ff ) )
+ {
+ char *strbfr = malloc( 85 );
+ vfc_splash( vf_file_name);
+ sprintf( strbfr,
+ "Line #%d, FCode number out of range: 0x%x Ignoring.\n",
+ vfc_line_no, vs_fc_number);
+ printremark( strbfr);
+ free( strbfr);
+ continue;
+ }
+
+ lookup_result = lookup_token( (u16)vs_fc_number);
+ if ( strcmp( lookup_result, "ferror") != 0 )
+ {
+ char *strbfr = malloc( strlen( lookup_result) + 85 );
+ vfc_splash( vf_file_name);
+ sprintf( strbfr,
+ "Line #%d. FCode number 0x%x is already "
+ "defined as %s Ignoring.\n",
+ vfc_line_no, vs_fc_number, lookup_result);
+ printremark( strbfr);
+ free( strbfr);
+ continue;
+ }
+
+ /* We've passed all the tests! */
+ fc_name_cpy = strdup( vs_fc_name);
+ add_token( (u16)vs_fc_number, fc_name_cpy);
+ added_fc_count++;
+ retval = TRUE;
+ }
+
+ if ( verbose )
+ {
+ char *strbfr = malloc( 85 );
+ sprintf( strbfr,
+ "Added %d FCode numbers\n", added_fc_count);
+ printremark( strbfr);
+ free( strbfr);
+ }
+
+ close_stream();
+ check_tok_seq = TRUE;
+ return( retval);
+}
Added: fcode-utils/detok/addfcodes.h
===================================================================
--- fcode-utils/detok/addfcodes.h (rev 0)
+++ fcode-utils/detok/addfcodes.h 2006-08-18 12:47:12 UTC (rev 76)
@@ -0,0 +1,48 @@
+#ifndef _DETOK_VSFCODES_H
+#define _DETOK_VSFCODES_H
+
+/*
+ * OpenBIOS - free your system!
+ * ( FCode tokenizer )
+ *
+ * This program is part of a free implementation of the IEEE 1275-1994
+ * Standard for Boot (Initialization Configuration) Firmware.
+ *
+ * Copyright (C) 2001-2005 Stefan Reinauer, <stepan(a)openbios.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA, 02110-1301 USA
+ *
+ */
+
+/* **************************************************************************
+ *
+ * Header for function for entering Vendor-Specific FCodes
+ * to detokenizer.
+ *
+ * (C) Copyright 2006 IBM Corporation. All Rights Reserved.
+ * Module Author: David L. Paktor dlpaktor(a)us.ibm.com
+ *
+ **************************************************************************** */
+
+#include "types.h"
+
+/* ************************************************************************** *
+ *
+ * Function Prototypes / Functions Exported:
+ *
+ **************************************************************************** */
+
+bool add_fcodes_from_list( char *vf_file_name);
+
+#endif /* _DETOK_VSFCODES_H */
Modified: fcode-utils/detok/decode.c
===================================================================
--- fcode-utils/detok/decode.c 2006-08-18 09:45:11 UTC (rev 75)
+++ fcode-utils/detok/decode.c 2006-08-18 12:47:12 UTC (rev 76)
@@ -24,96 +24,322 @@
*
*/
+/* **************************************************************************
+ * Modifications made in 2005 by IBM Corporation
+ * (C) Copyright 2005 IBM Corporation. All Rights Reserved.
+ * Modifications Author: David L. Paktor dlpaktor(a)us.ibm.com
+ **************************************************************************** */
+
#include <stdio.h>
#include <stdlib.h>
+#include <string.h>
#include <ctype.h>
+#include <setjmp.h>
#include "detok.h"
#include "stream.h"
-/* Dictionary function prototypes */
-char *lookup_token(u16 number);
-int add_token(u16 number, char *name);
+static int indent; /* Current level of indentation */
-extern u16 fcode;
+/* **************************************************************************
+ *
+ * Still to be done:
+ * Handling of indent-level is not correct. Branches should
+ * balance with their resolvers; constructs like do..loop
+ * case/of/endof/endcase are a few major examples.
+ * This will be tricky; the rules need to be carefully thought
+ * out, and the implementation might be more complex than
+ * at first meets the eye...
+ *
+ **************************************************************************** */
+static bool ended_okay = TRUE; /* FALSE if finished prematurely */
+
bool offs16=TRUE;
-int indent, verbose=0, decode_all=0, linenumbers=0, linenum;
-u32 fclen;
+unsigned int linenum;
+bool end_found=FALSE;
+unsigned int token_streampos; /* Streampos() of currently-gotten token */
+u16 last_defined_token = 0;
-static u8 *unnamed=(u8 *)"(unnamed-fcode)";
+jmp_buf eof_exception;
-void pretty_string(u8 *string)
+static int fclen;
+static const char *unnamed = "(unnamed-fcode)" ;
+
+static void decode_indent(void)
{
- u8 c;
- unsigned int i;
- bool qopen=TRUE;
+ int i;
+ if (indent<0) {
+#ifdef DEBUG_INDENT
+ printf("detok: error in indentation code.\n");
+#endif
+ indent=0;
+ }
+ for (i=0; i<indent; i++)
+ printf (" ");
+}
+/* Print forth string ( [len] char[0] ... char[len] ) */
+static void pretty_print_string(void)
+{
+ u8 len;
+ u8 *strptr;
+ int indx;
+ bool in_parens = FALSE ; /* Are we already inside parentheses? */
+
+ strptr = get_string( &len );
+
+ printf("( len=%s%x", len >= 10 ? "0x":"", len);
+ if ( len >= 10 ) printf(" [%d bytes]", len);
+ printf(" )\n");
+ if (show_linenumbers) printf(" ");
+ decode_indent();
printf("\" ");
- for (i=1; i<1+(unsigned int)string[0]; i++) {
- c=string[i];
+ for ( indx = 0; indx < len; indx++ )
+ {
+ u8 c = *strptr++;
if (isprint(c)) {
- if (!qopen) {
+ if ( in_parens )
+ {
printf(" )");
- qopen=TRUE;
+ in_parens = FALSE;
}
printf("%c",c);
+ /* Quote-mark must escape itself */
+ if ( c == '"' ) printf("%c",c);
} else {
- if (qopen) {
+ if ( !in_parens )
+ {
printf("\"(");
- qopen=FALSE;
+ in_parens = TRUE;
}
printf(" %02x",c);
}
}
- if (!qopen)
+ if ( in_parens )
printf(" )");
printf("\"");
}
-static void decode_indent(void)
+static void decode_lines(void)
{
- int i;
-#ifdef DEBUG_INDENT
- if (indent<0) {
- printf("detok: error in indentation code.\n");
- indent=0;
+ if (show_linenumbers) {
+ printf("%6d: ",show_offsets ? token_streampos : linenum++);
}
-#endif
- for (i=0; i<indent; i++)
- printf (" ");
}
-static void decode_lines(void)
+/* **************************************************************************
+ *
+ * Function name: output_token_name
+ * Synopsis: Print the name of the token just retrieved
+ * along with any interesting related information...
+ *
+ * Inputs:
+ * Global/Static Variables:
+ * fcode The token # just retrieved
+ * last_defined_token Used to screen invalid tokens.
+ * token_streampos Location of token just retrieved
+ * Global/Static Constants:
+ * unnamed Namefield of headerless token
+ *
+ * Outputs:
+ * Printout:
+ * Print the function name (if known) and the FCode number,
+ * if interesting.
+ * The fcode number is interesting if either
+ * a) the token has no name
+ * or
+ * b) verbose mode is in effect.
+ * If the token is named, show its FCode number in
+ * the syntax of a FORTH Comment, otherwise, its
+ * FCode number -- in [brackets] -- acts as its name.
+ *
+ * Error Detection:
+ * If the token # is larger than the last defined token, it is
+ * probably an artifact of an error that was allowed in the
+ * tokenization; if it were treated normally, it would lead
+ * to a cascade of failures. Print a message, skip the first
+ * byte, and return.
+ *
+ * Revision History:
+ * Refactored. The line number or offset (if selected) and the
+ * indent are printed in the output_token() routine, which
+ * calls this one.
+ * Add Error Detection
+ *
+ *
+ **************************************************************************** */
+
+static void output_token_name(void)
{
- if (linenumbers) {
- printf("%6d: ",linenumbers==1?linenum:get_streampos());
- linenum++;
+ char *tname;
+
+ /* Run error detection only if last_defined_token was assigned */
+ if ( (fcode > last_defined_token) && (last_defined_token > 0) )
+ {
+ char temp_buf[80];
+ int buf_pos;
+ u8 top_byte = fcode >> 8;
+ printf ("Invalid token: [0x%03x]\n", fcode);
+ sprintf(temp_buf, "Backing up over first byte, which is ");
+ buf_pos = strlen(temp_buf);
+ if ( top_byte < 10 )
+ {
+ sprintf(&temp_buf[buf_pos], " %02x", top_byte);
+ }else{
+ sprintf( &temp_buf[buf_pos], "0x%02x ( =dec %d)",
+ top_byte, top_byte);
}
+ printremark(temp_buf);
+ set_streampos(token_streampos+1);
+ return;
}
-static void output_token(void)
-{
- u8 *tname=lookup_token(fcode);
+ tname = lookup_token(fcode);
printf ("%s ", tname);
- /* The fcode number is interesting if
- * a) detok is in verbose mode
- * b) the token has no name.
+ /* The fcode number is interesting
+ * if either
+ * a) the token has no name
+ * or
+ * b) detok is in verbose mode.
*/
- if (verbose || tname == unnamed)
+ if ( tname == unnamed )
+ {
printf("[0x%03x] ", fcode);
+ } else {
+ if ( verbose )
+ {
+ /* If the token is named,
+ * show its fcode number in
+ * the syntax of a FORTH Comment
+ */
+ printf("( 0x%03x ) ", fcode);
+ }
+ }
}
+/* **************************************************************************
+ *
+ * Function name: output_token
+ * Synopsis: Print the full line for the token just retrieved:
+ * line number, indentation and name.
+ *
+ * Revision History:
+ * Updated Mon, 11 Jul 2005 by David L. Paktor
+ * Separate out output_token_name() for specific uses.
+ * Incorporate calls to decode_lines() and decode_indent()
+ * to allow better control of indentation.
+ *
+ **************************************************************************** */
+
+static void output_token(void)
+{
+ decode_lines();
+ decode_indent();
+ output_token_name();
+}
+
+
+/* **************************************************************************
+ *
+ * Function name: decode_offset
+ * Synopsis: Gather and display an FCode-offset associated with
+ * a branch or suchlike function.
+ *
+ * Inputs:
+ * Parameters: NONE
+ * Global/Static Variables:
+ * show_offsets Whether to show offsets in full detail
+ * offs16 Whether 16- (or 8-) -bit offsets
+ * stream_max Maximum valid destimation
+ * Local Static Variables:
+ *
+ * Outputs:
+ * Returned Value: The offset, converted to signed 16-bit #
+ * Global/Static Variables:
+ * stream-position Reset if invalid destination; otherwise,
+ * advanced in the normal manner.
+ * Printout:
+ * The offset and destination, if display of offsets was specified
+ * or if the destination is invalid
+ *
+ * Error Detection:
+ * Crude and rudimentary:
+ * If the target-destination is outside the theoretical limits,
+ * it's obviously wrong.
+ * Notification remark is printed and the stream-position reset
+ * to the location of the offset, to allow it to be processed
+ * in the manner of normal tokens.
+ * If the offset is zero, that's obviously wrong, but don't reset
+ * the stream-position: zero gets processed as end0 and that
+ * is also wrong...
+ *
+ * Still to be done:
+ * More sophisticated error-checking for invalid offsets. Look
+ * at the type of branch, and what should be expected in the
+ * vicinity of the destination. (This might be best served
+ * by a separate routine).
+ * This might also help with handling the indent-level correctly...
+ * Also, if indentation were to be handled in this routine,
+ * there would be no need to return the value of the offset.
+ *
+ **************************************************************************** */
+
static s16 decode_offset(void)
{
s16 offs;
+ int dest;
+ bool invalid_dest;
+ int streampos = get_streampos();
+ output_token();
offs=get_offset();
- output_token();
- printf("0x%x\n",offs);
+
+ /* The target-destination is the source-byte offset
+ * at which the FCode-offset is found, plus
+ * the FCode-offset.
+ */
+ dest = streampos + offs;
+
+ /* A destination of zero is invalid because there must be a
+ * token -- such as b(<mark) or b(do) -- preceding
+ * the target of a backward branch.
+ * A destination at the end of the stream is unlikely but
+ * theoretically possible, so we'll treat it as valid.
+ * An offset of zero is also, of course, invalid.
+ */
+ invalid_dest = BOOLVAL ( (dest <= 0)
+ || (dest > stream_max)
+ || (offs == 0) );
+
+ /* Show the offset in hex and again as a signed decimal number. */
+ if ( offs16 )
+ {
+ printf("0x%04x (", (u16)(offs & 0xffff) );
+ }else{
+ printf("0x%02x (", (u8)(offs & 0x00ff) );
+ }
+ if ( (offs < 0) || (offs > 9) ) printf(" =dec %d", offs);
+ /* If we're showing source-byte offsets, show targets of offsets */
+ if ( show_offsets || invalid_dest )
+ {
+ printf(" dest = %d ",dest);
+ }
+ printf(")\n");
+
+ if ( invalid_dest )
+ {
+ if (offs == 0)
+ {
+ printremark("Error: Unresolved offset.");
+ }else{
+ printremark("Error: Invalid offset. Ignoring...");
+ set_streampos( streampos);
+ }
+ }
return offs;
}
@@ -127,59 +353,39 @@
{
u16 token;
output_token();
- token=get_token();
+ token = next_token();
printf("0x%03x\n",token);
- add_token(token, unnamed);
+ add_token(token, (char *)unnamed);
}
static void named_token(void)
{
u16 token;
+ u8 len;
u8* string;
output_token();
/* get forth string ( [len] [char0] ... [charn] ) */
- string=get_string();
- token=get_token();
-
- printf("%s 0x%03x\n", string+1, token);
-
- add_token(token,string+1);
+ string=get_name(&len);
+ token = next_token();
+ printf("%s 0x%03x\n", string, token);
+ add_token(token,string);
}
-static void external_token(void)
+static void bquote(void)
{
- u16 token;
- u8* string;
-
output_token();
/* get forth string ( [len] [char0] ... [charn] ) */
- string=get_string();
- token=get_token();
-
- printf("%s 0x%03x\n", string+1, token);
-
- add_token(token,string+1);
-}
-
-static void bquote(void)
-{
- u8 *string;
-
- /* get forth string ( [len] [char0] ... [charn] ) */
- string=get_string();
- output_token();
- pretty_string(string);
+ pretty_print_string();
printf("\n");
- free(string);
}
static void blit(void)
{
u32 lit;
+ output_token();
lit=get_num32();
- output_token();
printf("0x%x\n",lit);
}
@@ -204,56 +410,81 @@
u16 token;
output_token();
- token=get_token();
- decode_default();
+ token = next_token();
+ output_token_name();
+ printf ("\n");
}
+/* **************************************************************************
+ *
+ * Function name: decode_start
+ * Synopsis: Display the (known valid) FCode block Header
+ *
+ * Outputs:
+ * Global/Static Variables:
+ * fclen Length of the FCode block as shown in its Header
+ *
+ **************************************************************************** */
+
static void decode_start(void)
{
u8 fcformat;
u16 fcchecksum, checksum=0;
- long pos;
- u32 i;
- decode_default();
+ output_token();
+ printf(" ( %d-bit offsets)\n", offs16 ? 16 : 8 );
+ token_streampos = get_streampos();
decode_lines();
fcformat=get_num8();
printf(" format: 0x%02x\n", fcformat);
- decode_lines();
- fcchecksum=get_num16();
- /* missing: check for checksum correctness. */
-
- fclen=get_num32(); /* skip len */
- pos=get_streampos();
- for (i=0; i<fclen-pos; i++)
- checksum+=get_num8();
+ /* Check for checksum correctness. */
- set_streampos(pos-4);
+ token_streampos = get_streampos();
+ decode_lines();
+ fcchecksum=get_num16(); /* Read the stored checksum */
+ checksum = calc_checksum(); /* Calculate the actual checksum */
- printf(" checksum: 0x%04x (%sOk)\n", fcchecksum,
- fcchecksum==checksum?"":"not ");
+ if ( fcchecksum==checksum )
+ {
+ printf(" checksum: 0x%04x (Ok)\n", fcchecksum);
+ } else {
+ printf(" checksum should be: 0x%04x, but is 0x%04x\n",
+ checksum,fcchecksum);
+ }
+ token_streampos = get_streampos();
decode_lines();
fclen=get_num32();
- printf(" len: 0x%x (%d bytes)\n", fclen, fclen);
+ printf(" len: 0x%04x ( %d bytes)\n", fclen, fclen);
}
-void decode_token(u16 token)
+/* **************************************************************************
+ *
+ * Function name: decode_token
+ * Synopsis: Display detokenization for one token.
+ * Handle complicated cases and dispatch simple ones.
+ *
+ * Revision History:
+ * Detect FCode-Starters in the middle of an FCode block.
+ * Some tuning of adjustment of indent, particularly wrt branches...
+ *
+ **************************************************************************** */
+
+static void decode_token(u16 token)
{
+ bool handy_flag = TRUE;
switch (token) {
case 0x0b5:
new_token();
break;
- case 0x0b6:
+ case 0x0b6: /* Named Token */
+ case 0x0ca: /* External Token */
named_token();
break;
- case 0x0ca:
- external_token();
- break;
case 0x012:
bquote();
break;
@@ -276,14 +507,14 @@
case 0x0c2: /* b(;) */
case 0x0b2: /* b(>resolve) */
case 0x0c5: /* b(endcase) */
+ indent--;
decode_default();
- indent--;
break;
case 0x015: /* b(loop) */
case 0x016: /* b(+loop) */
case 0x0c6: /* b(endof) */
+ indent--;
decode_offset();
- indent--;
break;
case 0x017: /* b(do) */
case 0x018: /* b/?do) */
@@ -295,38 +526,274 @@
case 0x0c3: /* b(to) */
decode_two();
break;
+ case 0x0fd: /* version1 */
+ handy_flag = FALSE;
case 0x0f0: /* start0 */
case 0x0f1: /* start1 */
case 0x0f2: /* start2 */
case 0x0f3: /* start4 */
+ offs16 = handy_flag;
+ printremark("Unexpected FCode-Block Starter.");
decode_start();
+ printremark(" Ignoring length field.");
break;
+ case 0: /* end0 */
+ case 0xff: /* end1 */
+ end_found=TRUE;
+ decode_default();
+ break;
+ default:
+ decode_default();
+ }
+}
+
+
+/* **************************************************************************
+ *
+ * Function name: decode_fcode_header
+ * Synopsis: Detokenize the FCode Header.
+ * Check for file corruption
+ *
+ * Inputs:
+ * Parameters: NONE
+ * Global/Static Variables:
+ * stream_max Length of input stream
+ *
+ * Outputs:
+ * Returned Value: NONE
+ * Global/Static Variables:
+ * offs16 FALSE if Starter was version1, else TRUE
+ * fclen On error, gets set to reach end of input stream
+ * Otherwise, gets set by decode_start()
+ * Printout:
+ *
+ * Error Detection:
+ * First byte not a valid FCode Start: Print message, restore
+ * input pointer to initial value, set fclen to [(end of
+ * input stream) - (input pointer)], return FALSE.
+ *
+ * Process Explanation:
+ * This routine error-checks and dispatches to the routine that
+ * does the actual printing.
+ * Refrain from showing offset until correctness of starter-byte
+ * has been confirmed.
+ *
+ **************************************************************************** */
+
+static void decode_fcode_header(void)
+{
+ long err_pos;
+ u16 token;
+
+ err_pos = get_streampos();
+ indent = 0;
+ token = next_token();
+ offs16=TRUE;
+ switch (token)
+ {
case 0x0fd: /* version1 */
- decode_start();
offs16=FALSE;
+ case 0x0f0: /* start0 */
+ case 0x0f1: /* start1 */
+ case 0x0f2: /* start2 */
+ case 0x0f3: /* start4 */
+ decode_start();
break;
default:
- decode_default();
+ {
+ char temp_bufr[128] =
+ "Invalid FCode Start Byte. Ignoring FCode header." ;
+ set_streampos( err_pos );
+ fclen = max - pc;
+ printf("\n");
+ if (show_linenumbers)
+ {
+ sprintf( &(temp_bufr[strlen(temp_bufr)]),
+ " Remaining len = 0x%04x ( %d bytes)", fclen, fclen);
+ }
+ printremark( temp_bufr );
}
}
+}
-int detokenize(void)
+/* **************************************************************************
+ *
+ * Function name: decode_fcode_block
+ * Synopsis: Detokenize one FCode block.
+ *
+ * Inputs:
+ * Parameters: NONE
+ * Global/Static Variables:
+ * fclen Length of the FCode block as shown in its Header
+ * end_found Whether the END0 code was seen
+ * decode_all TRUE = continue even after END0
+ *
+ * Outputs:
+ * Returned Value: NONE
+ * Global/Static Variables:
+ * end_found Whether the END0 code was seen
+ * Printout:
+ * A summary message at the end of FCode detokenization
+ *
+ * Error Detection:
+ * If the end of the FCode block, as calculated by its FCode length,
+ * was reached without encountering END0, print a message.
+ * Detect END0 that occurs before end of FCode block,
+ * even if decode_all is in effect.
+ *
+ * Process Explanation:
+ * This routine dispatches to the routines that do the actual
+ * printing of the detokenization.
+ * The end_found flag is not a direct input, but more of an
+ * intermediate input, so to speak... Clear it at the start.
+ * Detection of FCode-Starters in the middle of an FCode block
+ * is handled by decode_token() routine.
+ *
+ **************************************************************************** */
+
+static void decode_fcode_block(void)
{
u16 token;
+ unsigned int fc_block_start;
+ unsigned int fc_block_end;
- if (linenumbers)
- linenum=1;
+ end_found = FALSE;
+ fc_block_start = get_streampos();
- do {
- decode_lines();
- decode_indent();
- token=get_token();
+ decode_fcode_header();
+
+ fc_block_end = fc_block_start + fclen;
+
+ while ( ( !end_found || decode_all )
+ && ( get_streampos() < fc_block_end ) )
+ {
+ token = next_token();
decode_token(token);
- } while ((token||decode_all) && ((get_streampos()-1)<=fclen));
+ }
+ if ( !end_found )
+ {
+ printremark("FCode-ender not found");
+ }
+ {
+ char temp_bufr[80];
+ /* Don't use fclen here, in case it got corrupted
+ * by an "Unexpected FCode-Block Starter"
+ */
+ if ( get_streampos() == fc_block_end )
+ {
+ sprintf( temp_bufr,
+ "Detokenization finished normally after %d bytes.",
+ fc_block_end - fc_block_start );
+ }else{
+ sprintf( temp_bufr,
+ "Detokenization finished prematurely after %d of %d bytes.",
+ get_streampos() - fc_block_start,
+ fc_block_end - fc_block_start );
+ ended_okay = FALSE;
+ }
+ printremark( temp_bufr );
+ }
+}
- decode_lines();
- printf ("\\ detokenizing finished after %d of %d bytes.\n",
- get_streampos(), fclen );
+/* **************************************************************************
+ *
+ * Function name: another_fcode_block
+ * Synopsis: Indicate whether there is a follow-on FCode block
+ * within the current PCI image.
+ *
+ * Inputs:
+ * Parameters: NONE
+ * Global/Static Variables:
+ * token_streampos Streampos() of token just gotten
+ * Next token in Input Stream
+ *
+ * Outputs:
+ * Returned Value: TRUE if next token shows the start
+ * of a valid FCode-block
+ * Printout:
+ * Message if there is a follow-on FCode block
+ *
+ * Error Detection:
+ * If next token is neither a valid FCode-block starter nor the
+ * start of a zero-fill field, print a message.
+ *
+ * Process Explanation:
+ * Extract the next token from the Input Stream but do not
+ * consume it. Then examine the token.
+ *
+ **************************************************************************** */
- return 0;
+static bool another_fcode_block(void)
+{
+ bool retval = FALSE;
+ u16 token;
+
+ token = next_token();
+ set_streampos( token_streampos );
+
+ switch (token)
+ {
+ case 0x0fd: /* version1 */
+ case 0x0f0: /* start0 */
+ case 0x0f1: /* start1 */
+ case 0x0f2: /* start2 */
+ case 0x0f3: /* start4 */
+ retval = TRUE;
+ printremark("Subsequent FCode Block detected. Detokenizing.");
+ break;
+ case 0: /* Start of a zero-fill field */
+ /* retval already = FALSE . Nothing else to be done. */
+ break;
+ default:
+ {
+ char temp_bufr[80];
+ sprintf( temp_bufr,
+ "Unexpected token, 0x%02x, after end of FCode block.",
+ token);
+ printremark( temp_bufr);
+ }
+ }
+ return ( retval );
}
+
+/* **************************************************************************
+ *
+ * Function name: detokenize
+ * Synopsis: Detokenize one input file
+ *
+ *
+ *
+ **************************************************************************** */
+
+void detokenize(void)
+{
+ fclen = stream_max;
+
+ if ( setjmp(eof_exception) == 0 )
+ {
+ while ( more_to_go() )
+ {
+ if ( ended_okay )
+ {
+ init_fcode_block();
+ }
+ ended_okay = TRUE;
+
+ adjust_for_pci_header();
+
+ /* Allow for multiple FCode Blocks within the PCI image.
+ * The first one had better be a valid block, but the
+ * next may or may not be...
+ */
+ do
+ {
+ decode_fcode_block();
+ } while ( another_fcode_block() );
+
+ adjust_for_pci_filler();
+
+ }
+ }
+
+
+}
Modified: fcode-utils/detok/detok.c
===================================================================
--- fcode-utils/detok/detok.c 2006-08-18 09:45:11 UTC (rev 75)
+++ fcode-utils/detok/detok.c 2006-08-18 12:47:12 UTC (rev 76)
@@ -24,58 +24,76 @@
*
*/
+/* **************************************************************************
+ * Modifications made in 2005 by IBM Corporation
+ * (C) Copyright 2005 IBM Corporation. All Rights Reserved.
+ * Modifications Author: David L. Paktor dlpaktor(a)us.ibm.com
+ **************************************************************************** */
+
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
+
#ifdef __GLIBC__
#define _GNU_SOURCE
#include <getopt.h>
-#else
-/* Some systems seem to have an incomplete unistd.h.
- * We need to define getopt() and optind for them.
- */
-extern int optind;
-int getopt(int argc, char * const argv[], const char *optstring);
#endif
#include "detok.h"
#include "stream.h"
+#include "addfcodes.h"
#define DETOK_VERSION "0.6.1"
-/* prototypes for dictionary handling */
-void init_dictionary(void);
-void decode_token(u16 token);
-/* prototype for detokenizer function */
-int detokenize(void);
+#define IBM_COPYR "(C) Copyright 2005 IBM Corporation. All Rights Reserved."
-extern unsigned int decode_all, verbose, linenumbers;
+bool verbose = FALSE ;
+bool decode_all = FALSE ;
+bool show_linenumbers = FALSE ;
+bool show_offsets = FALSE ;
-void print_copyright(void)
+/* Param is FALSE when beginning to detokenize,
+ * TRUE preceding error-exit */
+static void print_copyright(bool is_error)
{
- printf( "Welcome to the OpenBIOS detokenizer v%s\ndetok Copyright"
+ typedef void (*vfunct)(); /* Pointer to function returning void */
+ vfunct pfunct ;
+ char buffr[512];
+
+ sprintf( buffr,
+ "Welcome to the OpenBIOS detokenizer v%s\ndetok Copyright"
"(c) 2001-2005 by Stefan Reinauer.\nWritten by Stefan "
"Reinauer, <stepan(a)openbios.org>\n" "This program is "
"free software; you may redistribute it under the terms of\n"
"the GNU General Public License. This program has absolutely"
" no warranty.\n\n" ,DETOK_VERSION);
+
+ pfunct = ( is_error ? (vfunct)printf : printremark );
+
+ (*pfunct) ( buffr );
+
+ (*pfunct) ( IBM_COPYR "\n" );
}
-void usage(char *name)
+static void usage(char *name)
{
printf( "usage: %s [OPTION]... [FCODE-FILE]...\n\n"
" -v, --verbose print fcode numbers\n"
" -a, --all don't stop at end0\n"
" -n, --linenumbers print line numbers\n"
" -o, --offsets print byte offsets\n"
+ " -f, --fcodes add FCodes from list-file\n"
" -h, --help print this help text\n\n", name);
}
int main(int argc, char **argv)
{
int c;
- const char *optstring="vhano?";
+ const char *optstring="vhanof:?";
+ int linenumbers = 0;
+ bool add_vfcodes = FALSE;
+ char *vfc_filnam = NULL;
while (1) {
#ifdef __GLIBC__
@@ -86,6 +104,7 @@
{ "all", 0, 0, 'a' },
{ "linenumbers", 0, 0, 'n' },
{ "offsets", 0, 0, 'o' },
+ { "fcodes", 1, 0, 'f' },
{ 0, 0, 0, 0 }
};
@@ -99,24 +118,31 @@
switch (c) {
case 'v':
- verbose=1;
+ verbose=TRUE;
break;
case 'a':
- decode_all=1;
+ decode_all=TRUE;
break;
case 'n':
linenumbers|=1;
+ show_linenumbers = TRUE;
break;
case 'o':
linenumbers|=2;
+ show_linenumbers = TRUE;
+ show_offsets = TRUE;
break;
+ case 'f':
+ add_vfcodes = TRUE;
+ vfc_filnam = optarg;
+ break;
case 'h':
case '?':
- print_copyright();
+ print_copyright(TRUE);
usage(argv[0]);
return 0;
default:
- print_copyright();
+ print_copyright(TRUE);
printf ("%s: unknown option.\n",argv[0]);
usage(argv[0]);
return 1;
@@ -124,13 +150,14 @@
}
if (verbose)
- print_copyright();
+ print_copyright(FALSE);
if (linenumbers>2)
- printf("Line numbers will be disabled in favour of offsets.\n");
+ printremark(
+ "Line numbers will be disabled in favour of offsets.\n");
if (optind >= argc) {
- print_copyright();
+ print_copyright(TRUE);
printf ("%s: filename missing.\n",argv[0]);
usage(argv[0]);
return 1;
@@ -138,6 +165,14 @@
init_dictionary();
+ if ( add_vfcodes )
+ {
+ if ( add_fcodes_from_list( vfc_filnam) )
+ {
+ freeze_dictionary();
+ }
+ }
+
while (optind < argc) {
if (init_stream(argv[optind])) {
Modified: fcode-utils/detok/detok.h
===================================================================
--- fcode-utils/detok/detok.h 2006-08-18 09:45:11 UTC (rev 75)
+++ fcode-utils/detok/detok.h 2006-08-18 12:47:12 UTC (rev 76)
@@ -1,3 +1,6 @@
+#ifndef _UTILS_DETOK_DETOK_H
+#define _UTILS_DETOK_DETOK_H
+
/*
* OpenBIOS - free your system!
* ( detokenizer )
@@ -24,10 +27,49 @@
*
*/
-#define u8 unsigned char
-#define u16 unsigned short
-#define u32 unsigned int
-#define s16 short
-#define bool int
-#define TRUE (-1)
-#define FALSE (0)
+/* **************************************************************************
+ * Modifications made in 2005 by IBM Corporation
+ * (C) Copyright 2005 IBM Corporation. All Rights Reserved.
+ * Modifications Author: David L. Paktor dlpaktor(a)us.ibm.com
+ **************************************************************************** */
+
+#include "types.h"
+
+/* Prototypes for functions exported from
+ * detok.c decode.c printformats.c pcihdr.c and dictionary.c
+ */
+
+void add_token(u16 number, char *name);
+void init_dictionary(void);
+void reset_dictionary(void);
+void freeze_dictionary(void);
+char *lookup_token(u16 number);
+
+void detokenize(void);
+
+void printremark(char *str);
+
+int handle_pci_header ( u8 *data_ptr );
+void handle_pci_filler(u8 *filler_ptr);
+
+
+/* External declarations for variables defined in or used by
+ * detok.c decode.c printformats.c pcihdr.c and dictionary.c
+ */
+extern bool verbose;
+extern bool decode_all;
+extern bool show_linenumbers;
+extern bool show_offsets;
+
+extern bool check_tok_seq;
+
+extern u16 fcode;
+extern bool offs16;
+extern bool end_found;
+extern unsigned int linenum;
+
+extern u8 *pci_image_end;
+extern unsigned int token_streampos;
+extern u16 last_defined_token;
+
+#endif /* _UTILS_DETOK_DETOK_H */
Modified: fcode-utils/detok/dictionary.c
===================================================================
--- fcode-utils/detok/dictionary.c 2006-08-18 09:45:11 UTC (rev 75)
+++ fcode-utils/detok/dictionary.c 2006-08-18 12:47:12 UTC (rev 76)
@@ -24,20 +24,29 @@
*
*/
+/* **************************************************************************
+ * Modifications made in 2005 by IBM Corporation
+ * (C) Copyright 2005 IBM Corporation. All Rights Reserved.
+ * Modifications Author: David L. Paktor dlpaktor(a)us.ibm.com
+ **************************************************************************** */
+
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include "detok.h"
+bool check_tok_seq = TRUE;
+
typedef struct token {
- u8 *name;
+ char *name;
u16 fcode;
struct token *next;
} token_t;
+#define TOKEN_ENTRY(num, name) { name, (u16)num, (token_t *)NULL }
+static token_t *dictionary; /* Initialize dynamically to accommodate AIX */
static char *fcerror="ferror";
-token_t *dictionary=NULL;
char *lookup_token(u16 number)
{
@@ -53,7 +62,51 @@
return fcerror;
}
-int add_token(u16 number, char *name)
+/* **************************************************************************
+ *
+ * Function name: add_token
+ * Synopsis: Add an entry to the FCode-Tokens vocabulary.
+ *
+ * Inputs:
+ * Parameters:
+ * number Numeric value of the FCode token
+ * name Name of the function to display
+ * Global/Static Variables:
+ * dictionary Pointer to the "tail" of the
+ * FCode-Tokens vocabulary.
+ * check_tok_seq TRUE = "Check Token Sequence"
+ * A retro-fit to accommodate
+ * adding Vendor FCodes
+ *
+ * Outputs:
+ * Returned Value: NONE
+ * Global/Static Variables:
+ * dictionary Updated to point to the new entry.
+ * last_defined_token Updated to the given FCode token
+ * Memory Allocated
+ * For the new entry.
+ * When Freed?
+ * Never. Retained for duration of the program.
+ *
+ * Error Detection:
+ * Failure to allocate memory is a fatal error.
+ * If the given FCode token is not exactly one larger than the
+ * previous last_defined_token , then there's something
+ * odd going on; print a remark to alert the user. The
+ * value of last_defined_token will be used elsewhere
+ * for additional error-checking.
+ *
+ * Process Explanation:
+ * The name field pointer is presumed to already point to a stable
+ * memory-space.
+ * Memory will be allocated for the entry itself; its fields will
+ * be entered and the pointer-to-the-tail-of-the-vocabulary
+ * will be updated to point to the new entry.
+ * Error-check and update last_defined_token
+ *
+ **************************************************************************** */
+
+void add_token(u16 number, char *name)
{
token_t *curr;
@@ -68,393 +121,451 @@
curr->name=name;
dictionary=curr;
- return 0;
+
+ if ( check_tok_seq )
+ {
+ /* Error-check, but not for first time. */
+ if ( (number == last_defined_token + 1)
+ || (last_defined_token == 0) )
+ {
+ last_defined_token = number;
+ }else{
+ if ( number <= last_defined_token )
+ {
+ printremark("Warning: New token # might overlap "
+ "previously assigned token #(s).");
+ }else{
+ printremark("Warning: New token # out of sequence with "
+ "previously assigned token #(s).");
+ /* It's increasing; update it. */
+ last_defined_token = number;
+ }
}
+ }
+}
+
+token_t detok_table[] = {
+
+ TOKEN_ENTRY( 0x000, "end0" ),
+ TOKEN_ENTRY( 0x010, "b(lit)" ),
+ TOKEN_ENTRY( 0x011, "b(')" ),
+ TOKEN_ENTRY( 0x012, "b(\")" ),
+ TOKEN_ENTRY( 0x013, "bbranch" ),
+ TOKEN_ENTRY( 0x014, "b?branch" ),
+ TOKEN_ENTRY( 0x015, "b(loop)" ),
+ TOKEN_ENTRY( 0x016, "b(+loop)" ),
+ TOKEN_ENTRY( 0x017, "b(do)" ),
+ TOKEN_ENTRY( 0x018, "b(?do)" ),
+ TOKEN_ENTRY( 0x019, "i" ),
+ TOKEN_ENTRY( 0x01a, "j" ),
+ TOKEN_ENTRY( 0x01b, "b(leave)" ),
+ TOKEN_ENTRY( 0x01c, "b(of)" ),
+ TOKEN_ENTRY( 0x01d, "execute" ),
+ TOKEN_ENTRY( 0x01e, "+" ),
+ TOKEN_ENTRY( 0x01f, "-" ),
+ TOKEN_ENTRY( 0x020, "*" ),
+ TOKEN_ENTRY( 0x021, "/" ),
+ TOKEN_ENTRY( 0x022, "mod" ),
+ TOKEN_ENTRY( 0x023, "and" ),
+ TOKEN_ENTRY( 0x024, "or" ),
+ TOKEN_ENTRY( 0x025, "xor" ),
+ TOKEN_ENTRY( 0x026, "invert" ),
+ TOKEN_ENTRY( 0x027, "lshift" ),
+ TOKEN_ENTRY( 0x028, "rshift" ),
+ TOKEN_ENTRY( 0x029, ">>a" ),
+ TOKEN_ENTRY( 0x02a, "/mod" ),
+ TOKEN_ENTRY( 0x02b, "u/mod" ),
+ TOKEN_ENTRY( 0x02c, "negate" ),
+ TOKEN_ENTRY( 0x02d, "abs" ),
+ TOKEN_ENTRY( 0x02e, "min" ),
+ TOKEN_ENTRY( 0x02f, "max" ),
+ TOKEN_ENTRY( 0x030, ">r" ),
+ TOKEN_ENTRY( 0x031, "r>" ),
+ TOKEN_ENTRY( 0x032, "r@" ),
+ TOKEN_ENTRY( 0x033, "exit" ),
+ TOKEN_ENTRY( 0x034, "0=" ),
+ TOKEN_ENTRY( 0x035, "0<>" ),
+ TOKEN_ENTRY( 0x036, "0<" ),
+ TOKEN_ENTRY( 0x037, "0<=" ),
+ TOKEN_ENTRY( 0x038, "0>" ),
+ TOKEN_ENTRY( 0x039, "0>=" ),
+ TOKEN_ENTRY( 0x03a, "<" ),
+ TOKEN_ENTRY( 0x03b, ">" ),
+ TOKEN_ENTRY( 0x03c, "=" ),
+ TOKEN_ENTRY( 0x03d, "<>" ),
+ TOKEN_ENTRY( 0x03e, "u>" ),
+ TOKEN_ENTRY( 0x03f, "u<=" ),
+ TOKEN_ENTRY( 0x040, "u<" ),
+ TOKEN_ENTRY( 0x041, "u>=" ),
+ TOKEN_ENTRY( 0x042, ">=" ),
+ TOKEN_ENTRY( 0x043, "<=" ),
+ TOKEN_ENTRY( 0x044, "between" ),
+ TOKEN_ENTRY( 0x045, "within" ),
+ TOKEN_ENTRY( 0x046, "drop" ),
+ TOKEN_ENTRY( 0x047, "dup" ),
+ TOKEN_ENTRY( 0x048, "over" ),
+ TOKEN_ENTRY( 0x049, "swap" ),
+ TOKEN_ENTRY( 0x04A, "rot" ),
+ TOKEN_ENTRY( 0x04b, "-rot" ),
+ TOKEN_ENTRY( 0x04c, "tuck" ),
+ TOKEN_ENTRY( 0x04d, "nip" ),
+ TOKEN_ENTRY( 0x04e, "pick" ),
+ TOKEN_ENTRY( 0x04f, "roll" ),
+ TOKEN_ENTRY( 0x050, "?dup" ),
+ TOKEN_ENTRY( 0x051, "depth" ),
+ TOKEN_ENTRY( 0x052, "2drop" ),
+ TOKEN_ENTRY( 0x053, "2dup" ),
+ TOKEN_ENTRY( 0x054, "2over" ),
+ TOKEN_ENTRY( 0x055, "2swap" ),
+ TOKEN_ENTRY( 0x056, "2rot" ),
+ TOKEN_ENTRY( 0x057, "2/" ),
+ TOKEN_ENTRY( 0x058, "u2/" ),
+ TOKEN_ENTRY( 0x059, "2*" ),
+ TOKEN_ENTRY( 0x05a, "/c" ),
+ TOKEN_ENTRY( 0x05b, "/w" ),
+ TOKEN_ENTRY( 0x05c, "/l" ),
+ TOKEN_ENTRY( 0x05d, "/n" ),
+ TOKEN_ENTRY( 0x05e, "ca+" ),
+ TOKEN_ENTRY( 0x05f, "wa+" ),
+ TOKEN_ENTRY( 0x060, "la+" ),
+ TOKEN_ENTRY( 0x061, "na+" ),
+ TOKEN_ENTRY( 0x062, "char+" ),
+ TOKEN_ENTRY( 0x063, "wa1+" ),
+ TOKEN_ENTRY( 0x064, "la1+" ),
+ TOKEN_ENTRY( 0x065, "cell+" ),
+ TOKEN_ENTRY( 0x066, "chars" ),
+ TOKEN_ENTRY( 0x067, "/w*" ),
+ TOKEN_ENTRY( 0x068, "/l*" ),
+ TOKEN_ENTRY( 0x069, "cells" ),
+ TOKEN_ENTRY( 0x06a, "on" ),
+ TOKEN_ENTRY( 0x06b, "off" ),
+ TOKEN_ENTRY( 0x06c, "+!" ),
+ TOKEN_ENTRY( 0x06d, "@" ),
+ TOKEN_ENTRY( 0x06e, "l@" ),
+ TOKEN_ENTRY( 0x06f, "w@" ),
+ TOKEN_ENTRY( 0x070, "<w@" ),
+ TOKEN_ENTRY( 0x071, "c@" ),
+ TOKEN_ENTRY( 0x072, "!" ),
+ TOKEN_ENTRY( 0x073, "l!" ),
+ TOKEN_ENTRY( 0x074, "w!" ),
+ TOKEN_ENTRY( 0x075, "c!" ),
+ TOKEN_ENTRY( 0x076, "2@" ),
+ TOKEN_ENTRY( 0x077, "2!" ),
+ TOKEN_ENTRY( 0x078, "move" ),
+ TOKEN_ENTRY( 0x079, "fill" ),
+ TOKEN_ENTRY( 0x07a, "comp" ),
+ TOKEN_ENTRY( 0x07b, "noop" ),
+ TOKEN_ENTRY( 0x07c, "lwsplit" ),
+ TOKEN_ENTRY( 0x07d, "wljoin" ),
+ TOKEN_ENTRY( 0x07e, "lbsplit" ),
+ TOKEN_ENTRY( 0x07f, "bljoin" ),
+ TOKEN_ENTRY( 0x080, "wbflip" ),
+ TOKEN_ENTRY( 0x081, "upc" ),
+ TOKEN_ENTRY( 0x082, "lcc" ),
+ TOKEN_ENTRY( 0x083, "pack" ),
+ TOKEN_ENTRY( 0x084, "count" ),
+ TOKEN_ENTRY( 0x085, "body>" ),
+ TOKEN_ENTRY( 0x086, ">body" ),
+ TOKEN_ENTRY( 0x087, "fcode-revision" ),
+ TOKEN_ENTRY( 0x088, "span" ),
+ TOKEN_ENTRY( 0x089, "unloop" ),
+ TOKEN_ENTRY( 0x08a, "expect" ),
+ TOKEN_ENTRY( 0x08b, "alloc-mem" ),
+ TOKEN_ENTRY( 0x08c, "free-mem" ),
+ TOKEN_ENTRY( 0x08d, "key?" ),
+ TOKEN_ENTRY( 0x08e, "key" ),
+ TOKEN_ENTRY( 0x08f, "emit" ),
+ TOKEN_ENTRY( 0x090, "type" ),
+ TOKEN_ENTRY( 0x091, "(cr" ),
+ TOKEN_ENTRY( 0x092, "cr" ),
+ TOKEN_ENTRY( 0x093, "#out" ),
+ TOKEN_ENTRY( 0x094, "#line" ),
+ TOKEN_ENTRY( 0x095, "hold" ),
+ TOKEN_ENTRY( 0x096, "<#" ),
+ TOKEN_ENTRY( 0x097, "u#>" ),
+ TOKEN_ENTRY( 0x098, "sign" ),
+ TOKEN_ENTRY( 0x099, "u#" ),
+ TOKEN_ENTRY( 0x09a, "u#s" ),
+ TOKEN_ENTRY( 0x09b, "u." ),
+ TOKEN_ENTRY( 0x09c, "u.r" ),
+ TOKEN_ENTRY( 0x09d, "." ),
+ TOKEN_ENTRY( 0x09e, ".r" ),
+ TOKEN_ENTRY( 0x09f, ".s" ),
+ TOKEN_ENTRY( 0x0a0, "base" ),
+ TOKEN_ENTRY( 0x0a1, "convert" ),
+ TOKEN_ENTRY( 0x0a2, "$number" ),
+ TOKEN_ENTRY( 0x0a3, "digit" ),
+ TOKEN_ENTRY( 0x0a4, "-1" ),
+ TOKEN_ENTRY( 0x0a5, "0" ),
+ TOKEN_ENTRY( 0x0a6, "1" ),
+ TOKEN_ENTRY( 0x0a7, "2" ),
+ TOKEN_ENTRY( 0x0a8, "3" ),
+ TOKEN_ENTRY( 0x0a9, "bl" ),
+ TOKEN_ENTRY( 0x0aa, "bs" ),
+ TOKEN_ENTRY( 0x0ab, "bell" ),
+ TOKEN_ENTRY( 0x0ac, "bounds" ),
+ TOKEN_ENTRY( 0x0ad, "here" ),
+ TOKEN_ENTRY( 0x0ae, "aligned" ),
+ TOKEN_ENTRY( 0x0af, "wbsplit" ),
+ TOKEN_ENTRY( 0x0b0, "bwjoin" ),
+ TOKEN_ENTRY( 0x0b1, "b(<mark)" ),
+ TOKEN_ENTRY( 0x0b2, "b(>resolve)" ),
+ TOKEN_ENTRY( 0x0b3, "set-token-table" ),
+ TOKEN_ENTRY( 0x0b4, "set-table" ),
+ TOKEN_ENTRY( 0x0b5, "new-token" ),
+ TOKEN_ENTRY( 0x0b6, "named-token" ),
+ TOKEN_ENTRY( 0x0b7, "b(:)" ),
+ TOKEN_ENTRY( 0x0b8, "b(value)" ),
+ TOKEN_ENTRY( 0x0b9, "b(variable)" ),
+ TOKEN_ENTRY( 0x0ba, "b(constant)" ),
+ TOKEN_ENTRY( 0x0bb, "b(create)" ),
+ TOKEN_ENTRY( 0x0bc, "b(defer)" ),
+ TOKEN_ENTRY( 0x0bd, "b(buffer:)" ),
+ TOKEN_ENTRY( 0x0be, "b(field)" ),
+ TOKEN_ENTRY( 0x0bf, "b(code)" ),
+ TOKEN_ENTRY( 0x0c0, "instance" ),
+ TOKEN_ENTRY( 0x0c2, "b(;)" ),
+ TOKEN_ENTRY( 0x0c3, "b(to)" ),
+ TOKEN_ENTRY( 0x0c4, "b(case)" ),
+ TOKEN_ENTRY( 0x0c5, "b(endcase)" ),
+ TOKEN_ENTRY( 0x0c6, "b(endof)" ),
+ TOKEN_ENTRY( 0x0c7, "#" ),
+ TOKEN_ENTRY( 0x0c8, "#s" ),
+ TOKEN_ENTRY( 0x0c9, "#>" ),
+ TOKEN_ENTRY( 0x0ca, "external-token" ),
+ TOKEN_ENTRY( 0x0cb, "$find" ),
+ TOKEN_ENTRY( 0x0cc, "offset16" ),
+ TOKEN_ENTRY( 0x0cd, "evaluate" ),
+ TOKEN_ENTRY( 0x0d0, "c," ),
+ TOKEN_ENTRY( 0x0d1, "w," ),
+ TOKEN_ENTRY( 0x0d2, "l," ),
+ TOKEN_ENTRY( 0x0d3, "," ),
+ TOKEN_ENTRY( 0x0d4, "um*" ),
+ TOKEN_ENTRY( 0x0d5, "um/mod" ),
+ TOKEN_ENTRY( 0x0d8, "d+" ),
+ TOKEN_ENTRY( 0x0d9, "d-" ),
+ TOKEN_ENTRY( 0x0da, "get-token" ),
+ TOKEN_ENTRY( 0x0db, "set-token" ),
+ TOKEN_ENTRY( 0x0dc, "state" ),
+ TOKEN_ENTRY( 0x0dd, "compile" ),
+ TOKEN_ENTRY( 0x0de, "behavior" ),
+ TOKEN_ENTRY( 0x0f0, "start0" ),
+ TOKEN_ENTRY( 0x0f1, "start1" ),
+ TOKEN_ENTRY( 0x0f2, "start2" ),
+ TOKEN_ENTRY( 0x0f3, "start4" ),
+ TOKEN_ENTRY( 0x0fc, "ferror" ),
+ TOKEN_ENTRY( 0x0fd, "version1" ),
+ TOKEN_ENTRY( 0x0fe, "4-byte-id" ),
+ TOKEN_ENTRY( 0x0ff, "end1" ),
+ TOKEN_ENTRY( 0x101, "dma-alloc" ),
+ TOKEN_ENTRY( 0x102, "my-address" ),
+ TOKEN_ENTRY( 0x103, "my-space" ),
+ TOKEN_ENTRY( 0x104, "memmap" ),
+ TOKEN_ENTRY( 0x105, "free-virtual" ),
+ TOKEN_ENTRY( 0x106, ">physical" ),
+ TOKEN_ENTRY( 0x10f, "my-params" ),
+ TOKEN_ENTRY( 0x110, "property" ),
+ TOKEN_ENTRY( 0x111, "encode-int" ),
+ TOKEN_ENTRY( 0x112, "encode+" ),
+ TOKEN_ENTRY( 0x113, "encode-phys" ),
+ TOKEN_ENTRY( 0x114, "encode-string" ),
+ TOKEN_ENTRY( 0x115, "encode-bytes" ),
+ TOKEN_ENTRY( 0x116, "reg" ),
+ TOKEN_ENTRY( 0x117, "intr" ),
+ TOKEN_ENTRY( 0x118, "driver" ),
+ TOKEN_ENTRY( 0x119, "model" ),
+ TOKEN_ENTRY( 0x11a, "device-type" ),
+ TOKEN_ENTRY( 0x11b, "parse-2int" ),
+ TOKEN_ENTRY( 0x11c, "is-install" ),
+ TOKEN_ENTRY( 0x11d, "is-remove" ),
+ TOKEN_ENTRY( 0x11e, "is-selftest" ),
+ TOKEN_ENTRY( 0x11f, "new-device" ),
+ TOKEN_ENTRY( 0x120, "diagnostic-mode?" ),
+ TOKEN_ENTRY( 0x121, "display-status" ),
+ TOKEN_ENTRY( 0x122, "memory-test-issue" ),
+ TOKEN_ENTRY( 0x123, "group-code" ),
+ TOKEN_ENTRY( 0x124, "mask" ),
+ TOKEN_ENTRY( 0x125, "get-msecs" ),
+ TOKEN_ENTRY( 0x126, "ms" ),
+ TOKEN_ENTRY( 0x127, "finish-device" ),
+ TOKEN_ENTRY( 0x128, "decode-phys" ),
+ TOKEN_ENTRY( 0x12b, "interpose" ),
+ TOKEN_ENTRY( 0x130, "map-low" ),
+ TOKEN_ENTRY( 0x131, "sbus-intr>cpu" ),
+ TOKEN_ENTRY( 0x150, "#lines" ),
+ TOKEN_ENTRY( 0x151, "#columns" ),
+ TOKEN_ENTRY( 0x152, "line#" ),
+ TOKEN_ENTRY( 0x153, "column#" ),
+ TOKEN_ENTRY( 0x154, "inverse?" ),
+ TOKEN_ENTRY( 0x155, "inverse-screen?" ),
+ TOKEN_ENTRY( 0x156, "frame-buffer-busy?" ),
+ TOKEN_ENTRY( 0x157, "draw-character" ),
+ TOKEN_ENTRY( 0x158, "reset-screen" ),
+ TOKEN_ENTRY( 0x159, "toggle-cursor" ),
+ TOKEN_ENTRY( 0x15a, "erase-screen" ),
+ TOKEN_ENTRY( 0x15b, "blink-screen" ),
+ TOKEN_ENTRY( 0x15c, "invert-screen" ),
+ TOKEN_ENTRY( 0x15d, "insert-characters" ),
+ TOKEN_ENTRY( 0x15e, "delete-characters" ),
+ TOKEN_ENTRY( 0x15f, "insert-lines" ),
+ TOKEN_ENTRY( 0x160, "delete-lines" ),
+ TOKEN_ENTRY( 0x161, "draw-logo" ),
+ TOKEN_ENTRY( 0x162, "frame-buffer-adr" ),
+ TOKEN_ENTRY( 0x163, "screen-height" ),
+ TOKEN_ENTRY( 0x164, "screen-width" ),
+ TOKEN_ENTRY( 0x165, "window-top" ),
+ TOKEN_ENTRY( 0x166, "window-left" ),
+ TOKEN_ENTRY( 0x16a, "default-font" ),
+ TOKEN_ENTRY( 0x16b, "set-font" ),
+ TOKEN_ENTRY( 0x16c, "char-height" ),
+ TOKEN_ENTRY( 0x16d, "char-width" ),
+ TOKEN_ENTRY( 0x16e, ">font" ),
+ TOKEN_ENTRY( 0x16f, "fontbytes" ),
+ TOKEN_ENTRY( 0x170, "fb1-draw-character" ),
+ TOKEN_ENTRY( 0x171, "fb1-reset-screen" ),
+ TOKEN_ENTRY( 0x172, "fb1-toggle-cursor" ),
+ TOKEN_ENTRY( 0x173, "fb1-erase-screen" ),
+ TOKEN_ENTRY( 0x174, "fb1-blink-screen" ),
+ TOKEN_ENTRY( 0x175, "fb1-invert-screen" ),
+ TOKEN_ENTRY( 0x176, "fb1-insert-characters" ),
+ TOKEN_ENTRY( 0x177, "fb1-delete-characters" ),
+ TOKEN_ENTRY( 0x178, "fb1-insert-lines" ),
+ TOKEN_ENTRY( 0x179, "fb1-delete-lines" ),
+ TOKEN_ENTRY( 0x17a, "fb1-draw-logo" ),
+ TOKEN_ENTRY( 0x17b, "fb1-install" ),
+ TOKEN_ENTRY( 0x17c, "fb1-slide-up" ),
+ TOKEN_ENTRY( 0x180, "fb8-draw-character" ),
+ TOKEN_ENTRY( 0x181, "fb8-reset-screen" ),
+ TOKEN_ENTRY( 0x182, "fb8-toggle-cursor" ),
+ TOKEN_ENTRY( 0x183, "fb8-erase-screen" ),
+ TOKEN_ENTRY( 0x184, "fb8-blink-screen" ),
+ TOKEN_ENTRY( 0x185, "fb8-invert-screen" ),
+ TOKEN_ENTRY( 0x186, "fb8-insert-characters" ),
+ TOKEN_ENTRY( 0x187, "fb8-delete-characters" ),
+ TOKEN_ENTRY( 0x188, "fb8-insert-lines" ),
+ TOKEN_ENTRY( 0x189, "fb8-delete-lines" ),
+ TOKEN_ENTRY( 0x18a, "fb8-draw-logo" ),
+ TOKEN_ENTRY( 0x18b, "fb8-install" ),
+ TOKEN_ENTRY( 0x1a0, "return-buffer" ),
+ TOKEN_ENTRY( 0x1a1, "xmit-packet" ),
+ TOKEN_ENTRY( 0x1a2, "poll-packet" ),
+ TOKEN_ENTRY( 0x1a4, "mac-address" ),
+ TOKEN_ENTRY( 0x201, "device-name" ),
+ TOKEN_ENTRY( 0x202, "my-args" ),
+ TOKEN_ENTRY( 0x203, "my-self" ),
+ TOKEN_ENTRY( 0x204, "find-package" ),
+ TOKEN_ENTRY( 0x205, "open-package" ),
+ TOKEN_ENTRY( 0x206, "close-package" ),
+ TOKEN_ENTRY( 0x207, "find-method" ),
+ TOKEN_ENTRY( 0x208, "call-package" ),
+ TOKEN_ENTRY( 0x209, "$call-parent" ),
+ TOKEN_ENTRY( 0x20a, "my-parent" ),
+ TOKEN_ENTRY( 0x20b, "ihandle>phandle" ),
+ TOKEN_ENTRY( 0x20d, "my-unit" ),
+ TOKEN_ENTRY( 0x20e, "$call-method" ),
+ TOKEN_ENTRY( 0x20f, "$open-package" ),
+ TOKEN_ENTRY( 0x210, "processor-type" ),
+ TOKEN_ENTRY( 0x211, "firmware-version" ),
+ TOKEN_ENTRY( 0x212, "fcode-version" ),
+ TOKEN_ENTRY( 0x213, "alarm" ),
+ TOKEN_ENTRY( 0x214, "(is-user-word)" ),
+ TOKEN_ENTRY( 0x215, "suspend-fcode" ),
+ TOKEN_ENTRY( 0x216, "abort" ),
+ TOKEN_ENTRY( 0x217, "catch" ),
+ TOKEN_ENTRY( 0x218, "throw" ),
+ TOKEN_ENTRY( 0x219, "user-abort" ),
+ TOKEN_ENTRY( 0x21a, "get-my-property" ),
+ TOKEN_ENTRY( 0x21b, "decode-int" ),
+ TOKEN_ENTRY( 0x21c, "decode-string" ),
+ TOKEN_ENTRY( 0x21d, "get-inherited-property" ),
+ TOKEN_ENTRY( 0x21e, "delete-property" ),
+ TOKEN_ENTRY( 0x21f, "get-package-property" ),
+ TOKEN_ENTRY( 0x220, "cpeek" ),
+ TOKEN_ENTRY( 0x221, "wpeek" ),
+ TOKEN_ENTRY( 0x222, "lpeek" ),
+ TOKEN_ENTRY( 0x223, "cpoke" ),
+ TOKEN_ENTRY( 0x224, "wpoke" ),
+ TOKEN_ENTRY( 0x225, "lpoke" ),
+ TOKEN_ENTRY( 0x226, "lwflip" ),
+ TOKEN_ENTRY( 0x227, "lbflip" ),
+ TOKEN_ENTRY( 0x228, "lbflips" ),
+ TOKEN_ENTRY( 0x229, "adr-mask" ),
+ TOKEN_ENTRY( 0x230, "rb@" ),
+ TOKEN_ENTRY( 0x231, "rb!" ),
+ TOKEN_ENTRY( 0x232, "rw@" ),
+ TOKEN_ENTRY( 0x233, "rw!" ),
+ TOKEN_ENTRY( 0x234, "rl@" ),
+ TOKEN_ENTRY( 0x235, "rl!" ),
+ TOKEN_ENTRY( 0x236, "wbflips" ),
+ TOKEN_ENTRY( 0x237, "lwflips" ),
+ TOKEN_ENTRY( 0x238, "probe" ),
+ TOKEN_ENTRY( 0x239, "probe-virtual" ),
+ TOKEN_ENTRY( 0x23b, "child" ),
+ TOKEN_ENTRY( 0x23c, "peer" ),
+ TOKEN_ENTRY( 0x23d, "next-property" ),
+ TOKEN_ENTRY( 0x23e, "byte-load" ),
+ TOKEN_ENTRY( 0x23f, "set-args" ),
+ TOKEN_ENTRY( 0x240, "left-parse-string" ),
+
+ /* FCodes from 64bit extension addendum */
+ TOKEN_ENTRY( 0x22e, "rx@" ),
+ TOKEN_ENTRY( 0x22f, "rx!" ),
+ TOKEN_ENTRY( 0x241, "bxjoin" ),
+ TOKEN_ENTRY( 0x242, "<l@" ),
+ TOKEN_ENTRY( 0x243, "lxjoin" ),
+ TOKEN_ENTRY( 0x244, "wxjoin" ),
+ TOKEN_ENTRY( 0x245, "x," ),
+ TOKEN_ENTRY( 0x246, "x@" ),
+ TOKEN_ENTRY( 0x247, "x!" ),
+ TOKEN_ENTRY( 0x248, "/x" ),
+ TOKEN_ENTRY( 0x249, "/x*" ),
+ TOKEN_ENTRY( 0x24a, "xa+" ),
+ TOKEN_ENTRY( 0x24b, "xa1+" ),
+ TOKEN_ENTRY( 0x24c, "xbflip" ),
+ TOKEN_ENTRY( 0x24d, "xbflips" ),
+ TOKEN_ENTRY( 0x24e, "xbsplit" ),
+ TOKEN_ENTRY( 0x24f, "xlflip" ),
+ TOKEN_ENTRY( 0x250, "xlflips" ),
+ TOKEN_ENTRY( 0x251, "xlsplit" ),
+ TOKEN_ENTRY( 0x252, "xwflip" ),
+ TOKEN_ENTRY( 0x253, "xwflips" ),
+ TOKEN_ENTRY( 0x254, "xwsplit" ),
+};
+
+static const int dictionary_indx_max = (sizeof(detok_table)/sizeof(token_t)) ;
+
+static token_t *dictionary_reset_position;
+
void init_dictionary(void)
{
- add_token( 0x000, "end0" );
- add_token( 0x010, "b(lit)" );
- add_token( 0x011, "b(')" );
- add_token( 0x012, "b(\")" );
- add_token( 0x013, "bbranch" );
- add_token( 0x014, "b?branch" );
- add_token( 0x015, "b(loop)" );
- add_token( 0x016, "b(+loop)" );
- add_token( 0x017, "b(do)" );
- add_token( 0x018, "b(?do)" );
- add_token( 0x019, "i" );
- add_token( 0x01a, "j" );
- add_token( 0x01b, "b(leave)" );
- add_token( 0x01c, "b(of)" );
- add_token( 0x01d, "execute" );
- add_token( 0x01e, "+" );
- add_token( 0x01f, "-" );
- add_token( 0x020, "*" );
- add_token( 0x021, "/" );
- add_token( 0x022, "mod" );
- add_token( 0x023, "and" );
- add_token( 0x024, "or" );
- add_token( 0x025, "xor" );
- add_token( 0x026, "invert" );
- add_token( 0x027, "lshift" );
- add_token( 0x028, "rshift" );
- add_token( 0x029, ">>a" );
- add_token( 0x02a, "/mod" );
- add_token( 0x02b, "u/mod" );
- add_token( 0x02c, "negate" );
- add_token( 0x02d, "abs" );
- add_token( 0x02e, "min" );
- add_token( 0x02f, "max" );
- add_token( 0x030, ">r" );
- add_token( 0x031, "r>" );
- add_token( 0x032, "r@" );
- add_token( 0x033, "exit" );
- add_token( 0x034, "0=" );
- add_token( 0x035, "0<>" );
- add_token( 0x036, "0<" );
- add_token( 0x037, "0<=" );
- add_token( 0x038, "0>" );
- add_token( 0x039, "0>=" );
- add_token( 0x03a, "<" );
- add_token( 0x03b, ">" );
- add_token( 0x03c, "=" );
- add_token( 0x03d, "<>" );
- add_token( 0x03e, "u>" );
- add_token( 0x03f, "u<=" );
- add_token( 0x040, "u<" );
- add_token( 0x041, "u>=" );
- add_token( 0x042, ">=" );
- add_token( 0x043, "<=" );
- add_token( 0x044, "between" );
- add_token( 0x045, "within" );
- add_token( 0x046, "drop" );
- add_token( 0x047, "dup" );
- add_token( 0x048, "over" );
- add_token( 0x049, "swap" );
- add_token( 0x04A, "rot" );
- add_token( 0x04b, "-rot" );
- add_token( 0x04c, "tuck" );
- add_token( 0x04d, "nip" );
- add_token( 0x04e, "pick" );
- add_token( 0x04f, "roll" );
- add_token( 0x050, "?dup" );
- add_token( 0x051, "depth" );
- add_token( 0x052, "2drop" );
- add_token( 0x053, "2dup" );
- add_token( 0x054, "2over" );
- add_token( 0x055, "2swap" );
- add_token( 0x056, "2rot" );
- add_token( 0x057, "2/" );
- add_token( 0x058, "u2/" );
- add_token( 0x059, "2*" );
- add_token( 0x05a, "/c" );
- add_token( 0x05b, "/w" );
- add_token( 0x05c, "/l" );
- add_token( 0x05d, "/n" );
- add_token( 0x05e, "ca+" );
- add_token( 0x05f, "wa+" );
- add_token( 0x060, "la+" );
- add_token( 0x061, "na+" );
- add_token( 0x062, "char+" );
- add_token( 0x063, "wa1+" );
- add_token( 0x064, "la1+" );
- add_token( 0x065, "cell+" );
- add_token( 0x066, "chars" );
- add_token( 0x067, "/w*" );
- add_token( 0x068, "/l*" );
- add_token( 0x069, "cells" );
- add_token( 0x06a, "on" );
- add_token( 0x06b, "off" );
- add_token( 0x06c, "+!" );
- add_token( 0x06d, "@" );
- add_token( 0x06e, "l@" );
- add_token( 0x06f, "w@" );
- add_token( 0x070, "<w@" );
- add_token( 0x071, "c@" );
- add_token( 0x072, "!" );
- add_token( 0x073, "l!" );
- add_token( 0x074, "w!" );
- add_token( 0x075, "c!" );
- add_token( 0x076, "2@" );
- add_token( 0x077, "2!" );
- add_token( 0x078, "move" );
- add_token( 0x079, "fill" );
- add_token( 0x07a, "comp" );
- add_token( 0x07b, "noop" );
- add_token( 0x07c, "lwsplit" );
- add_token( 0x07d, "wljoin" );
- add_token( 0x07e, "lbsplit" );
- add_token( 0x07f, "bljoin" );
- add_token( 0x080, "wbflip" );
- add_token( 0x081, "upc" );
- add_token( 0x082, "lcc" );
- add_token( 0x083, "pack" );
- add_token( 0x084, "count" );
- add_token( 0x085, "body>" );
- add_token( 0x086, ">body" );
- add_token( 0x087, "fcode-revision" );
- add_token( 0x088, "span" );
- add_token( 0x089, "unloop" );
- add_token( 0x08a, "expect" );
- add_token( 0x08b, "alloc-mem" );
- add_token( 0x08c, "free-mem" );
- add_token( 0x08d, "key?" );
- add_token( 0x08e, "key" );
- add_token( 0x08f, "emit" );
- add_token( 0x090, "type" );
- add_token( 0x091, "(cr" );
- add_token( 0x092, "cr" );
- add_token( 0x093, "#out" );
- add_token( 0x094, "#line" );
- add_token( 0x095, "hold" );
- add_token( 0x096, "<#" );
- add_token( 0x097, "u#>" );
- add_token( 0x098, "sign" );
- add_token( 0x099, "u#" );
- add_token( 0x09a, "u#s" );
- add_token( 0x09b, "u." );
- add_token( 0x09c, "u.r" );
- add_token( 0x09d, "." );
- add_token( 0x09e, ".r" );
- add_token( 0x09f, ".s" );
- add_token( 0x0a0, "base" );
- add_token( 0x0a1, "convert" );
- add_token( 0x0a2, "$number" );
- add_token( 0x0a3, "digit" );
- add_token( 0x0a4, "-1" );
- add_token( 0x0a5, "0" );
- add_token( 0x0a6, "1" );
- add_token( 0x0a7, "2" );
- add_token( 0x0a8, "3" );
- add_token( 0x0a9, "bl" );
- add_token( 0x0aa, "bs" );
- add_token( 0x0ab, "bell" );
- add_token( 0x0ac, "bounds" );
- add_token( 0x0ad, "here" );
- add_token( 0x0ae, "aligned" );
- add_token( 0x0af, "wbsplit" );
- add_token( 0x0b0, "bwjoin" );
- add_token( 0x0b1, "b(<mark)" );
- add_token( 0x0b2, "b(>resolve)" );
- add_token( 0x0b3, "set-token-table" );
- add_token( 0x0b4, "set-table" );
- add_token( 0x0b5, "new-token" );
- add_token( 0x0b6, "named-token" );
- add_token( 0x0b7, "b(:)" );
- add_token( 0x0b8, "b(value)" );
- add_token( 0x0b9, "b(variable)" );
- add_token( 0x0ba, "b(constant)" );
- add_token( 0x0bb, "b(create)" );
- add_token( 0x0bc, "b(defer)" );
- add_token( 0x0bd, "b(buffer:)" );
- add_token( 0x0be, "b(field)" );
- add_token( 0x0bf, "b(code)" );
- add_token( 0x0c0, "instance" );
- add_token( 0x0c2, "b(;)" );
- add_token( 0x0c3, "b(to)" );
- add_token( 0x0c4, "b(case)" );
- add_token( 0x0c5, "b(endcase)" );
- add_token( 0x0c6, "b(endof)" );
- add_token( 0x0c7, "#" );
- add_token( 0x0c8, "#s" );
- add_token( 0x0c9, "#>" );
- add_token( 0x0ca, "external-token" );
- add_token( 0x0cb, "$find" );
- add_token( 0x0cc, "offset16" );
- add_token( 0x0cd, "evaluate" );
- add_token( 0x0d0, "c," );
- add_token( 0x0d1, "w," );
- add_token( 0x0d2, "l," );
- add_token( 0x0d3, "," );
- add_token( 0x0d4, "um*" );
- add_token( 0x0d5, "um/mod" );
- add_token( 0x0d8, "d+" );
- add_token( 0x0d9, "d-" );
- add_token( 0x0da, "get-token" );
- add_token( 0x0db, "set-token" );
- add_token( 0x0dc, "state" );
- add_token( 0x0dd, "compile" );
- add_token( 0x0de, "behavior" );
- add_token( 0x0f0, "start0" );
- add_token( 0x0f1, "start1" );
- add_token( 0x0f2, "start2" );
- add_token( 0x0f3, "start4" );
- add_token( 0x0fc, "ferror" );
- add_token( 0x0fd, "version1" );
- add_token( 0x0fe, "4-byte-id" );
- add_token( 0x0ff, "end1" );
- add_token( 0x101, "dma-alloc" );
- add_token( 0x102, "my-address" );
- add_token( 0x103, "my-space" );
- add_token( 0x104, "memmap" );
- add_token( 0x105, "free-virtual" );
- add_token( 0x106, ">physical" );
- add_token( 0x10f, "my-params" );
- add_token( 0x110, "property" );
- add_token( 0x111, "encode-int" );
- add_token( 0x112, "encode+" );
- add_token( 0x113, "encode-phys" );
- add_token( 0x114, "encode-string" );
- add_token( 0x115, "encode-bytes" );
- add_token( 0x116, "reg" );
- add_token( 0x117, "intr" );
- add_token( 0x118, "driver" );
- add_token( 0x119, "model" );
- add_token( 0x11a, "device-type" );
- add_token( 0x11b, "parse-2int" );
- add_token( 0x11c, "is-install" );
- add_token( 0x11d, "is-remove" );
- add_token( 0x11e, "is-selftest" );
- add_token( 0x11f, "new-device" );
- add_token( 0x120, "diagnostic-mode?" );
- add_token( 0x121, "display-status" );
- add_token( 0x122, "memory-test-issue" );
- add_token( 0x123, "group-code" );
- add_token( 0x124, "mask" );
- add_token( 0x125, "get-msecs" );
- add_token( 0x126, "ms" );
- add_token( 0x127, "finish-device" );
- add_token( 0x128, "decode-phys" );
- add_token( 0x12b, "interpose" );
- add_token( 0x130, "map-low" );
- add_token( 0x131, "sbus-intr>cpu" );
- add_token( 0x150, "#lines" );
- add_token( 0x151, "#columns" );
- add_token( 0x152, "line#" );
- add_token( 0x153, "column#" );
- add_token( 0x154, "inverse?" );
- add_token( 0x155, "inverse-screen?" );
- add_token( 0x156, "frame-buffer-busy?" );
- add_token( 0x157, "draw-character" );
- add_token( 0x158, "reset-screen" );
- add_token( 0x159, "toggle-cursor" );
- add_token( 0x15a, "erase-screen" );
- add_token( 0x15b, "blink-screen" );
- add_token( 0x15c, "invert-screen" );
- add_token( 0x15d, "insert-characters" );
- add_token( 0x15e, "delete-characters" );
- add_token( 0x15f, "insert-lines" );
- add_token( 0x160, "delete-lines" );
- add_token( 0x161, "draw-logo" );
- add_token( 0x162, "frame-buffer-adr" );
- add_token( 0x163, "screen-height" );
- add_token( 0x164, "screen-width" );
- add_token( 0x165, "window-top" );
- add_token( 0x166, "window-left" );
- add_token( 0x16a, "default-font" );
- add_token( 0x16b, "set-font" );
- add_token( 0x16c, "char-height" );
- add_token( 0x16d, "char-width" );
- add_token( 0x16e, ">font" );
- add_token( 0x16f, "fontbytes" );
- add_token( 0x170, "fb1-draw-character" );
- add_token( 0x171, "fb1-reset-screen" );
- add_token( 0x172, "fb1-toggle-cursor" );
- add_token( 0x173, "fb1-erase-screen" );
- add_token( 0x174, "fb1-blink-screen" );
- add_token( 0x175, "fb1-invert-screen" );
- add_token( 0x176, "fb1-insert-characters" );
- add_token( 0x177, "fb1-delete-characters" );
- add_token( 0x178, "fb1-insert-lines" );
- add_token( 0x179, "fb1-delete-lines" );
- add_token( 0x17a, "fb1-draw-logo" );
- add_token( 0x17b, "fb1-install" );
- add_token( 0x17c, "fb1-slide-up" );
- add_token( 0x180, "fb8-draw-character" );
- add_token( 0x181, "fb8-reset-screen" );
- add_token( 0x182, "fb8-toggle-cursor" );
- add_token( 0x183, "fb8-erase-screen" );
- add_token( 0x184, "fb8-blink-screen" );
- add_token( 0x185, "fb8-invert-screen" );
- add_token( 0x186, "fb8-insert-characters" );
- add_token( 0x187, "fb8-delete-characters" );
- add_token( 0x188, "fb8-insert-lines" );
- add_token( 0x189, "fb8-delete-lines" );
- add_token( 0x18a, "fb8-draw-logo" );
- add_token( 0x18b, "fb8-install" );
- add_token( 0x1a0, "return-buffer" );
- add_token( 0x1a1, "xmit-packet" );
- add_token( 0x1a2, "poll-packet" );
- add_token( 0x1a4, "mac-address" );
- add_token( 0x201, "device-name" );
- add_token( 0x202, "my-args" );
- add_token( 0x203, "my-self" );
- add_token( 0x204, "find-package" );
- add_token( 0x205, "open-package" );
- add_token( 0x206, "close-package" );
- add_token( 0x207, "find-method" );
- add_token( 0x208, "call-package" );
- add_token( 0x209, "$call-parent" );
- add_token( 0x20a, "my-package" );
- add_token( 0x20b, "ihandle>phandle" );
- add_token( 0x20d, "my-unit" );
- add_token( 0x20e, "$call-method" );
- add_token( 0x20f, "$open-package" );
- add_token( 0x210, "processor-type" );
- add_token( 0x211, "firmware-version" );
- add_token( 0x212, "fcode-version" );
- add_token( 0x213, "alarm" );
- add_token( 0x214, "(is-user-word)" );
- add_token( 0x215, "suspend-fcode" );
- add_token( 0x216, "abort" );
- add_token( 0x217, "catch" );
- add_token( 0x218, "throw" );
- add_token( 0x219, "user-abort" );
- add_token( 0x21a, "get-my-property" );
- add_token( 0x21b, "decode-int" );
- add_token( 0x21c, "decode-string" );
- add_token( 0x21d, "get-inherited-property" );
- add_token( 0x21e, "delete-property" );
- add_token( 0x21f, "get-package-property" );
- add_token( 0x220, "cpeek" );
- add_token( 0x221, "wpeek" );
- add_token( 0x222, "lpeek" );
- add_token( 0x223, "cpoke" );
- add_token( 0x224, "wpoke" );
- add_token( 0x225, "lpoke" );
- add_token( 0x226, "lwflip" );
- add_token( 0x227, "lbflip" );
- add_token( 0x228, "lbflips" );
- add_token( 0x229, "adr-mask" );
- add_token( 0x230, "rb@" );
- add_token( 0x231, "rb!" );
- add_token( 0x232, "rw@" );
- add_token( 0x233, "rw!" );
- add_token( 0x234, "rl@" );
- add_token( 0x235, "rl!" );
- add_token( 0x236, "wbflips" );
- add_token( 0x237, "lwflips" );
- add_token( 0x238, "probe" );
- add_token( 0x239, "probe-virtual" );
- add_token( 0x23b, "child" );
- add_token( 0x23c, "peer" );
- add_token( 0x23d, "next-property" );
- add_token( 0x23e, "byte-load" );
- add_token( 0x23f, "set-args" );
- add_token( 0x240, "left-parse-string" );
+ int indx;
- /* FCodes from 64bit extension addendum */
- add_token( 0x22e, "rx@" );
- add_token( 0x22f, "rx!" );
- add_token( 0x241, "bxjoin" );
- add_token( 0x242, "<l@" );
- add_token( 0x243, "lxjoin" );
- add_token( 0x244, "wxjoin" );
- add_token( 0x245, "x," );
- add_token( 0x246, "x@" );
- add_token( 0x247, "x!" );
- add_token( 0x248, "/x" );
- add_token( 0x249, "/x*" );
- add_token( 0x24a, "xa+" );
- add_token( 0x24b, "xa1+" );
- add_token( 0x24c, "xbflip" );
- add_token( 0x24d, "xbflips" );
- add_token( 0x24e, "xbsplit" );
- add_token( 0x24f, "xlflip" );
- add_token( 0x250, "xlflips" );
- add_token( 0x251, "xlsplit" );
- add_token( 0x252, "xwflip" );
- add_token( 0x253, "xwflips" );
- add_token( 0x254, "xwsplit" );
+ dictionary = &detok_table[dictionary_indx_max-1];
+ dictionary_reset_position = dictionary;
+
+ for (indx = 1; indx < dictionary_indx_max ; indx++ )
+ {
+ detok_table[indx].next = &detok_table[indx-1];
+ }
}
+
+void reset_dictionary(void)
+{
+ token_t *next_t;
+
+ next_t = dictionary;
+ while ( next_t != dictionary_reset_position )
+ {
+ next_t = dictionary->next ;
+ free( dictionary->name );
+ free( dictionary );
+ dictionary = next_t ;
+ }
+}
+
+/* If FCodes have been added by User, we need to update reset-position */
+void freeze_dictionary(void)
+{
+ dictionary_reset_position = dictionary;
+}
Added: fcode-utils/detok/pcihdr.c
===================================================================
--- fcode-utils/detok/pcihdr.c (rev 0)
+++ fcode-utils/detok/pcihdr.c 2006-08-18 12:47:12 UTC (rev 76)
@@ -0,0 +1,478 @@
+/*
+ * OpenBIOS - free your system!
+ * ( FCode tokenizer )
+ *
+ * This program is part of a free implementation of the IEEE 1275-1994
+ * Standard for Boot (Initialization Configuration) Firmware.
+ *
+ * Copyright (C) 2001-2005 Stefan Reinauer, <stepan(a)openbios.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA, 02110-1301 USA
+ *
+ */
+
+/* **************************************************************************
+ *
+ * Support function for de-tokenizer.
+ *
+ * Identify and process PCI header at beginning of FCode binary file.
+ * "Processing" consists of recognizing the PCI Header and Data Structure,
+ * optionally printing a description thereof, and (mainly) allowing
+ * the given pointer to be bumped to the start of the actual FCode.
+ *
+ *
+ * (C) Copyright 2005 IBM Corporation. All Rights Reserved.
+ * Module Author: David L. Paktor dlpaktor(a)us.ibm.com
+ *
+ * Revision History:
+ *
+ * Updated Mon, 23 May 2005 by David L. Paktor
+ * Identify "Not Last" header.
+ * Updated Thu, 24 Feb 2005 by David L. Paktor
+ * Per notes after Code Review.
+ * Updated Fri, 04 Feb 2005 by David L. Paktor
+ * Updated Wed, 08 Jun 2005 by David L. Paktor
+ * Added support for multiple-PCI-image files.
+ *
+ *
+ **************************************************************************** */
+
+/* **************************************************************************
+ *
+ * Functions Eported:
+ * handle_pci_header
+ * Handle all activities connected with presence of
+ * PCI Header/Data at beginning of FCode file, and
+ * facilitate "skipping" over to actual FCode data.
+ *
+ * handle_pci_filler
+ * Skip past "filler" between blocks in multi-PCI-image files.
+ *
+ *
+ **************************************************************************** */
+
+
+/* **************************************************************************
+ *
+ * Still to be done:
+ * Print (as remarks) full descriptions of headers' fields
+ * Error check for wrong "Format"
+ * Skip past non-FCode blocks, thru multiple data-blocks
+ * Recognize PCI header in unexpected place or out-of-place
+ *
+ **************************************************************************** */
+
+#include "pcihdr.h"
+#include <stdio.h>
+
+#include "detok.h"
+
+
+/* **************************************************************************
+ *
+ * Global Variables Exported
+ * pci_image_end Pointer to just after end of current PCI image
+ *
+ **************************************************************************** */
+
+u8 *pci_image_end = NULL;
+
+/* **************************************************************************
+ *
+ * Internal Static Variables
+ * pci_image_len Length (in bytes) of current PCI image
+ *
+ **************************************************************************** */
+
+static int pci_image_len = 0;
+
+
+/* **************************************************************************
+ *
+ * Function name: is_pci_header ( rom_header_t *pci_rom_hdr )
+ * Synopsis: Indicate whether given pointer is pointing to
+ * something that might be a valid PCI header
+ *
+ * Inputs:
+ * Parameters:
+ * pci_rom_hdr pointer to start of data-stream to examine.
+ * Treat as pointer to rom_header_t
+ *
+ * Outputs:
+ * Returned Value: An integer.
+ * 0 Definitely *NOT* a PCI header
+ * Positive Number Appears to be a valid PCI header;
+ * value is offset to PCI Data Structure.
+ * Negative Number Appears to be a PCI header, but
+ * with errors. (Not Implemented Yet.
+ * See under "Still to be done".)
+ *
+ * Error Detection:
+ * (See under "Still to be done".)
+ *
+ * Process Explanation:
+ * Examine "signature" location for known value 0x55aa
+ * If a match, return value of "dptr" (Data-pointer offset) field.
+ *
+ * Revision History:
+ * Created Tue, 01 Feb 2005 by David L. Paktor
+ *
+ * Still to be done:
+ * Error-check; look for inconsistencies:
+ * Return a Negative Number if data-stream appears to be a PCI
+ * header, but has erroneous or inconsistent sub-field contents.
+ * Value and meaning of the Negative Number yet to be defined.
+ *
+ **************************************************************************** */
+
+static int is_pci_header ( rom_header_t *pci_rom_hdr )
+{
+ const u16 pci_header_signature = 0x55aa;
+ int retval ;
+
+ retval = 0;
+
+ if ( BIG_ENDIAN_WORD_FETCH(pci_rom_hdr->signature) == pci_header_signature )
+ {
+ retval = LITTLE_ENDIAN_WORD_FETCH(pci_rom_hdr->data_ptr);
+ }
+ return(retval);
+}
+
+/* **************************************************************************
+ *
+ * Function name: is_pci_data_struct ( pci_data_t *pci_data_ptr )
+ * Synopsis: Indicate whether given pointer is pointing to
+ * a valid PCI Data Structure
+ *
+ * Inputs:
+ * Parameters:
+ * pci_data_ptr pointer to start of data-stream to examine.
+ * Treat as pointer to pci_data_t
+ *
+ * Outputs:
+ * Returned Value: An integer.
+ * 0 Definitely *NOT* a PCI Data Structure
+ * Positive Number Appears to be valid PCI Data Structure;
+ * value is length of PCI Data Structure,
+ * (presumably, offset to start of FCode).
+ * Negative Number Appears to be a PCI Data Structure,
+ * but with errors. (Not Implemented Yet.
+ * See under "Still to be done".)
+ *
+ * Global/Static Variables:
+ * Does not alter the poiner passed-in;
+ * does not alter any Global/Static Variables
+ * Printout: NONE
+ *
+ * Error Detection: (Condition) (Action)
+ * (See under "Still to be done".)
+ *
+ * Process Explanation:
+ * Examine "signature" location for known value "PCIR"
+ * If a match, return value of "dlen" (Data Structure Length) field.
+ *
+ * Revision History:
+ * Created Tue, 01 Feb 2005 by David L. Paktor
+ *
+ * Still to be done:
+ * Error-check; look for wrong "Code Type" or other inconsistencies:
+ * Return a Negative Number if data-stream appears to be a
+ * valid PCI Data Structure, but has erroneous or inconsistent
+ * sub-field contents.
+ * Value and meaning of the Negative Number yet to be defined.
+ * Skip past non-FCode data-blocks, even multiple blocks
+ *
+ **************************************************************************** */
+
+static int is_pci_data_struct ( pci_data_t *pci_data_ptr )
+{
+ int retval ;
+
+ retval = 0;
+
+ if (BIG_ENDIAN_LONG_FETCH(pci_data_ptr->signature) == PCI_DATA_HDR)
+ {
+ retval = LITTLE_ENDIAN_WORD_FETCH(pci_data_ptr->dlen);
+ }
+ return(retval);
+}
+
+
+/* **************************************************************************
+ *
+ * Function name: announce_pci_hdr ( rom_header_t *pci_rom_hdr )
+ * Synopsis: Print indication that the PCI header was found,
+ * and other details, formatted as FORTH remarks.
+ *
+ * Inputs:
+ * Parameters:
+ * pci_rom_hdr Pointer to start of PCI header.
+ *
+ * Outputs:
+ * Returned Value: NONE
+ * Printout: Announcement. Size of data_ptr field.
+ *
+ **************************************************************************** */
+
+static void announce_pci_hdr ( rom_header_t *pci_rom_hdr )
+{
+ char temp_buf[80];
+ u32 temp;
+
+ printremark ( "PCI Header identified");
+ temp=(u32)LITTLE_ENDIAN_WORD_FETCH(pci_rom_hdr->data_ptr);
+ sprintf(temp_buf, " Offset to Data Structure = 0x%04x (%d)\n",
+ temp, temp);
+ printremark ( temp_buf );
+}
+
+/* **************************************************************************
+ *
+ * Function name: announce_pci_data_struct ( pci_data_t *pci_data_ptr )
+ * Synopsis: Print indication that the PCI Data Structure
+ * was found, and some additional details.
+ * Format as FORTH remarks.
+ *
+ * Inputs:
+ * Parameters:
+ * pci_data_ptr Pointer to start of PCI Data Structure.
+ *
+ * Outputs:
+ * Returned Value: NONE
+ * Global/Static Variables:
+ * pci_image_len Updated to byte-length of current PCI image
+ * Printout: (See Synopsis)
+ *
+ * Process Explanation:
+ * Extract some details, format and print them,
+ * using the syntax of FORTH remarks.
+ *
+ * Revision History:
+ * Created Tue, 01 Feb 2005 by David L. Paktor
+ * Updated Wed, 25 May 2005 by David L. Paktor
+ * Added printout of several fields...
+ *
+ **************************************************************************** */
+
+static void announce_pci_data_struct ( pci_data_t *pci_data_ptr )
+{
+ char temp_buf[80];
+ u32 temp;
+
+ printremark ( "PCI Data Structure identified");
+
+ temp=(u32)LITTLE_ENDIAN_WORD_FETCH(pci_data_ptr->dlen);
+ sprintf(temp_buf, " Data Structure Length = 0x%04x (%d)\n", temp, temp);
+ printremark ( temp_buf );
+
+ sprintf(temp_buf, " Vendor ID: 0x%04x\n",
+ LITTLE_ENDIAN_WORD_FETCH(pci_data_ptr->vendor));
+ printremark ( temp_buf );
+
+ sprintf(temp_buf, " Device ID: 0x%04x\n",
+ LITTLE_ENDIAN_WORD_FETCH(pci_data_ptr->device));
+ printremark ( temp_buf );
+
+ temp=(u32)CLASS_CODE_FETCH(pci_data_ptr->class_code);
+ sprintf(temp_buf, " Class Code: 0x%06x (%s)",
+ temp, pci_device_class_name(temp));
+ printremark ( temp_buf );
+
+ temp=(u32)LITTLE_ENDIAN_WORD_FETCH(pci_data_ptr->vpd);
+ if ( temp != 0 )
+ {
+ sprintf(temp_buf, " Vital Prod Data: 0x%02x\n", temp);
+ printremark ( temp_buf );
+ }
+
+ temp=(u32)LITTLE_ENDIAN_WORD_FETCH(pci_data_ptr->irevision);
+ if ( temp != 0 )
+ {
+ sprintf(temp_buf, " Image Revision: 0x%02x\n", temp);
+ printremark ( temp_buf );
+ }
+
+ sprintf(temp_buf, " Code Type: 0x%02x (%s)\n", pci_data_ptr->code_type,
+ pci_code_type_name(pci_data_ptr->code_type) );
+ printremark ( temp_buf );
+
+ temp=(u32)LITTLE_ENDIAN_WORD_FETCH(pci_data_ptr->ilen);
+ pci_image_len = temp*512;
+ sprintf(temp_buf, " Image Length: 0x%04x blocks (%d bytes)\n",
+ temp, pci_image_len);
+ printremark ( temp_buf );
+
+ sprintf(temp_buf, " %sast PCI Image.\n",
+ pci_data_ptr->last_image_flag&&0x80 != 0 ? "L" : "Not l");
+ printremark ( temp_buf );
+
+}
+
+
+/* **************************************************************************
+ *
+ * Function name: handle_pci_header
+ * Synopsis: Handle PCI Header/Data at beginning of FCode file;
+ * facilitate "skipping" over to actual FCode data.
+ *
+ * Inputs:
+ * Parameters:
+ * data_ptr Pointer to start of data-stream to examine.
+ * Global/Static Variables:
+ * pci_image_len Length (in bytes) of current PCI image
+ *
+ * Outputs:
+ * Returned Value:
+ * Positive Number. Offset to start of FCode.
+ * Zero If no PCI header; may be treated as
+ * a valid offset.
+ * Negative Number PCI header or PCI Data Structure test
+ * returned error indication.
+ * (Not Implemented Yet. See
+ * under "Still to be done".)
+ * Global/Static Variables:
+ * pci_image_end Pointer to just after the end of
+ * the current PCI image
+ * Printout: As FORTH remarks, print indications that the
+ * PCI header was found, and maybe later more data.
+ *
+ * Error Detection: (Condition) (Action)
+ * (See under "Still to be done".)
+ *
+ * Process Explanation:
+ * Use the various support routines defined below.
+ *
+ *
+ * Revision History:
+ *
+ * Updated Wed, 09 Feb 2005 by David L. Paktor
+ * Extracted assignments from within if( ) statements.
+ *
+ * Created Tue, 01 Feb 2005 by David L. Paktor
+ *
+ * Still to be done:
+ * Handle error cases. At present, neither is_pci_header()
+ * nor is_pci_data_struct() returns a negative number,
+ * but when they are modified to do so, we must handle it.
+ *
+ **************************************************************************** */
+
+int handle_pci_header ( u8 *data_ptr )
+{
+ int hdrlen;
+ int data_struc_len;
+ /* int retval; */ /* Not needed until we handle error cases... */
+
+ data_struc_len = 0;
+
+ hdrlen = is_pci_header( (rom_header_t *)data_ptr );
+ /* retval = hdrlen; */ /* Not needed yet... */
+ if ( hdrlen < 0 )
+ {
+ /* Handle error case... */
+ /* Leave null for now... */
+ /* It might need to do a premature EXIT here... */
+ } else {
+ /* if hdrlen == 0 then we don't need to check a Data Structure */
+ if ( hdrlen > 0 )
+ {
+ announce_pci_hdr ( (rom_header_t *)data_ptr );
+ data_struc_len = is_pci_data_struct(
+ (pci_data_t *) &data_ptr[hdrlen] );
+ /*
+ * A Data Structure Length of Zero would be an error
+ * that could be detected by is_pci_data_struct()
+ */
+ if ( data_struc_len <= 0 )
+ {
+ /* Handle error case... */
+ /* Leave null for now... */
+ /* It might need to do a premature EXIT here... */
+ /* retval = -1; */ /* Not needed yet... */
+ } else {
+ announce_pci_data_struct ( (pci_data_t *) &data_ptr[hdrlen] );
+ pci_image_end = data_ptr + pci_image_len;
+ /* retval = hdrlen+data_struc_len; */ /* Not needed yet... */
+ }
+ }
+ }
+ return (hdrlen+data_struc_len);
+}
+
+
+/* **************************************************************************
+ *
+ * Function name: handle_pci_filler
+ * Synopsis: Examine and report on the "filler" padding after the
+ * end of an FCode-block but still within a PCI-image
+ *
+ * Inputs:
+ * Parameters:
+ * filler_ptr Pointer to start of PCI-filler in data-stream
+ * Global/Static Variables:
+ * pci_image_end Pointer to just after the end of
+ * the current PCI image
+ *
+ * Outputs:
+ * Returned Value: NONE
+ * Printout:
+ * Descriptive message.
+ *
+ * Error Detection:
+ * Non-zero filler field. Different message.
+ *
+ * Process Explanation:
+ * The calling routine has checked that there was, indeed, a PCI
+ * header present, so we know that pci_image_end is valid.
+ * If the entire filler is zero-bytes, print a simple message and
+ * we're out'a here!
+ * If there are non-zero bytes, identify loc'n of first non-zero.
+ *
+ * Still to be done:
+ * Come up with something more elegant for non-zero filler.
+ *
+ **************************************************************************** */
+
+void handle_pci_filler(u8 *filler_ptr)
+{
+ u8 *scan_ptr;
+ int filler_len;
+ char temp_buf[80];
+ bool all_zero = TRUE;
+ u8 filler_byte = *filler_ptr;
+
+ filler_len = pci_image_end - filler_ptr;
+
+ for ( scan_ptr = filler_ptr;
+ scan_ptr < pci_image_end;
+ filler_byte = *(++scan_ptr) )
+ {
+ if ( filler_byte != 0 )
+ {
+ all_zero = FALSE;
+ break;
+ }
+ }
+
+ if ( all_zero )
+ {
+ sprintf(temp_buf, "PCI Image padded with %d bytes of zero", filler_len);
+ }else{
+ sprintf(temp_buf, "PCI Image padding-field of %d bytes "
+ "had first non-zero byte at offset %ld",
+ filler_len, scan_ptr - filler_ptr );
+ }
+ printremark ( temp_buf );
+}
Added: fcode-utils/detok/printformats.c
===================================================================
--- fcode-utils/detok/printformats.c (rev 0)
+++ fcode-utils/detok/printformats.c 2006-08-18 12:47:12 UTC (rev 76)
@@ -0,0 +1,140 @@
+/*
+ * OpenBIOS - free your system!
+ * ( FCode tokenizer )
+ *
+ * This program is part of a free implementation of the IEEE 1275-1994
+ * Standard for Boot (Initialization Configuration) Firmware.
+ *
+ * Copyright (C) 2001-2005 Stefan Reinauer, <stepan(a)openbios.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA, 02110-1301 USA
+ *
+ */
+
+/* **************************************************************************
+ *
+ * Print, in various controlled formats, for the detokenizer.
+ *
+ * (C) Copyright 2005 IBM Corporation. All Rights Reserved.
+ * Module Author: David L. Paktor dlpaktor(a)us.ibm.com
+ *
+ **************************************************************************** */
+
+/* **************************************************************************
+ *
+ * Ultimately, our goal is to produce output that can be run back
+ * through the tokenizer and produce the same binary. So, any
+ * extra text will have to be in a form that the tokenizer will
+ * treat as comments.
+ *
+ **************************************************************************** */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "detok.h"
+
+
+/* **************************************************************************
+ *
+ * Function name: printremark ( string )
+ * Synopsis: Print the given string as a series of "Remark" lines,
+ * (i.e., preceded by backslash-space)
+ *
+ * Inputs:
+ * Parameters:
+ * str Pointer to the start of the string,
+ * however long it may be. The string
+ * may have any number of embedded new-lines.
+ *
+ * Outputs:
+ * Returned Value: *** NONE***
+ * Printout: Each line of the string will be preceded by
+ * a backslash and two spaces. Backslash-space
+ * is the standard delimiter for a "remark", i.e.
+ * the entire line is ignored as a comment. The
+ * second space is "just" for aesthetics.
+ *
+ * Process Explanation:
+ * Parse the input string for new-lines. Print each separately.
+ * Do not alter the input string.
+ *
+ *
+ * Still to be done:
+ * Define a routine, call it PrintComment , to print the given
+ * string surrounded by open-paren-space ... space-close-paren
+ * Define a single central routine, call it safe_malloc ,
+ * to do the test for null and print "No Memory" and exit.
+ * Define a single central routine, call it PrintError , to:
+ * Print the given error message
+ * Show the input file and line number
+ * Collect error-flags for failure-exit at end of operation.
+ *
+ **************************************************************************** */
+
+void printremark ( char *str)
+{
+ char *strtmp ; /* Temporary pointer to current substring */
+ int substrlen ; /* Length of current substring */
+ char *substrend ; /* Pointer to end of current substring */
+ char *strend ; /* Pointer to end of given string */
+
+ char *strbfr ; /* Temporary substring buffer */
+
+ /* Guarantee that the malloc will be big enough. */
+ strbfr = (char *)malloc(strlen((char *)str)+1);
+ if ( !strbfr )
+ {
+ printf ("No memory.\n");
+ exit(-1);
+ }
+
+
+ strtmp = str;
+ strend = &str[strlen(str)];
+
+ /* ******************************************************************
+ *
+ * Isolate the current substring; allow that the given
+ * string might not be terminated with a new-line.
+ *
+ * The strend pointer provides a convenient means to
+ * test for when we've reached the end.
+ *
+ ******************************************************************** */
+
+ while ( strtmp < strend )
+ {
+ substrend = strchr(strtmp , '\n');
+ substrlen = ( substrend ? (substrend-strtmp) : strlen(strtmp) );
+
+ strncpy (strbfr, strtmp, substrlen);
+ /* **********************************************************
+ *
+ * strncpy() does not append a terminating null character,
+ * so we have to.
+ *
+ ************************************************************ */
+ strbfr[substrlen] = (char)0;
+
+ printf("\\ %s\n",strbfr);
+
+ strtmp = &strtmp[ substrlen + ( substrend ? 1 : 0 ) ] ;
+
+ }
+
+ free(strbfr) ;
+}
+
Modified: fcode-utils/detok/stream.c
===================================================================
--- fcode-utils/detok/stream.c 2006-08-18 09:45:11 UTC (rev 75)
+++ fcode-utils/detok/stream.c 2006-08-18 12:47:12 UTC (rev 76)
@@ -24,20 +24,60 @@
*
*/
+/* **************************************************************************
+ * Modifications made in 2005 by IBM Corporation
+ * (C) Copyright 2005 IBM Corporation. All Rights Reserved.
+ * Modifications Author: David L. Paktor dlpaktor(a)us.ibm.com
+ **************************************************************************** */
+
#include <stdio.h>
#include <stdlib.h>
+#include <string.h>
#include <sys/stat.h>
+#include <setjmp.h>
+#include "stream.h"
#include "detok.h"
+#include "pcihdr.h"
-extern bool offs16;
-extern u32 fcpos;
+extern jmp_buf eof_exception;
+/* **************************************************************************
+ *
+ * Global Variables Exported:
+ * Name Value
+ * fcode The FCode-token last read. Not necessarily the byte
+ * last read, if its function has in-line parameters
+ * stream_max The maximum position -- length -- of the input stream
+ * pc Pointer to "Current byte" in the input-data image.
+ * max Just after the end of the input-data image.
+ * This is *NOT* a byte-count.
+ *
+ **************************************************************************** */
+
u16 fcode;
-u8 inbyte;
+unsigned int stream_max;
+u8 *pc;
+u8 *max;
-static u8 *indata, *pc, *max;
+/* **************************************************************************
+ *
+ * Local/Static Variables:
+ * Name Pointer to:
+ * indata Start of input-data image taken from input file.
+ * This memory was "malloc"ed; keep it around
+ * for when we "free" that memory.
+ * fc_start Start of the FCode. This might not be the same
+ * as the start of the input file data, especially
+ * if the input file data starts with a PCI header.
+ * pci_image_found TRUE iff a valid PCI header was found
+ *
+ **************************************************************************** */
+u8 *indata;
+static u8 *fc_start;
+static bool pci_image_found = FALSE;
+
int init_stream(char *name)
{
FILE *infile;
@@ -62,119 +102,455 @@
fclose(infile);
pc=indata;
+ fc_start = indata;
max=pc+finfo.st_size;
+ stream_max = finfo.st_size;
+
return 0;
}
-int close_stream(void)
+/* **************************************************************************
+ *
+ * Function name: init_fcode_block
+ * Synopsis: Initialize all pointers and variables, etcetera,
+ * for an FCode-block.
+ *
+ **************************************************************************** */
+
+void init_fcode_block(void)
{
+ fc_start = pc;
+ linenum = 1 ;
+}
+
+
+void close_stream(void)
+{
free(indata);
- return 0;
+ stream_max = 0;
}
int get_streampos(void)
{
- return (int)((long)pc-(long)indata);
+ return (int)( pc - fc_start );
}
-void set_streampos(long pos)
+void set_streampos(int pos)
{
- pc=indata+pos;
+ pc = fc_start + pos;
}
-static int get_byte(void)
+
+/* **************************************************************************
+ *
+ * Function name: throw_eof
+ * Synopsis: Analyze and print the cause of the end-of-file
+ * and throw an exception.
+ *
+ * Inputs:
+ * Parameters:
+ * premature TRUE iff end-of-file was out-of-sync
+ * Global/Static Variables:
+ * end_found Indicates if normal end of fcode was read.
+ * eof_exception Long-Jump environment to which to jump.
+ *
+ * Outputs: Does a Long-Jump
+ * Returned Value: NONE
+ * Printout:
+ * "End-of-file" message, along with a descriptor, if applicable:
+ * Premature, Unexpected.
+ * The calling routine notifies us if the number of bytes requested
+ * overflowed the input buffer, by passing us a TRUE for the
+ * input parameter. That is a "Premature" end-of-file.
+ * If end_found is FALSE, it means the normal end of FCode
+ * wasn't seen. That is an "Unexpected" end-of-file.
+ *
+ **************************************************************************** */
+
+static void throw_eof(bool premature)
{
- inbyte=*pc;
- pc++;
+ char yoo = 'U';
+ char eee = 'E';
+ if ( premature)
+ {
+ printf("Premature ");
+ yoo = 'u';
+ eee = 'e';
+ }
+ if ( ! end_found )
+ {
+ printf("%cnexpected ",yoo);
+ eee = 'e';
+ }
+ printf("%cnd of file.\n",eee);
+ longjmp(eof_exception, -1);
+}
- if (pc>max) {
- printf ("\nUnexpected end of file.\n");
- return 0;
+/* **************************************************************************
+ *
+ * Function name: get_bytes
+ * Synopsis: Return the next string of bytes, as requested, from
+ * the FCode input-stream. Detect end-of-file
+ *
+ * Inputs:
+ * Parameters:
+ * nbytes The number of bytes requested
+ * Global/Static Variables:
+ * pc Pointer to "where we are" in the FCode
+ * max Pointer to just after end of input file data.
+ *
+ * Outputs:
+ * Returned Value:
+ * Pointer to the requested bytes in the FCode input-stream.
+ * Global/Static Variables:
+ * pc Incremented by the number of bytes requested
+ *
+ * Exception:
+ * When end-of-file is reached, or is about to be exceeded,
+ * throw an end-of-file exception.
+ *
+ * Process Explanation:
+ * End-of-file is not exactly an error, so its detection is more
+ * a part of normal processing.
+ * If we entered this routine with PC pointing exactly at MAX,
+ * we are probably at the end the way we expect to be, so we
+ * call our EOF-handling routine with a "non-premature" flag.
+ * If the requested number of bytes puts us just even with MAX,
+ * we have neither reached nor over-run the input stream, so
+ * there's no call to our EOF-handling routine needed at all.
+ * Only if the requested number of bytes puts us past MAX have we
+ * over-run our input stream with a "premature" condition.
+ *
+ * Extraneous Remarks:
+ * This is another one where it was easier to write the code
+ * than the explanation ... ;-}
+ *
+ **************************************************************************** */
+
+static u8 *get_bytes(int nbytes)
+{
+ u8 *retval = pc;
+ if ( pc == max )
+ {
+ throw_eof(FALSE);
+ }
+ if ( pc + nbytes > max )
+ {
+ throw_eof(TRUE);
+ }
+ pc += nbytes;
+ return( retval);
}
- return 1;
+
+/* **************************************************************************
+ *
+ * Function name: more_to_go
+ * Synopsis: Return FALSE when the last byte has been
+ * read from the input-stream.
+ *
+ **************************************************************************** */
+
+bool more_to_go(void)
+{
+ bool retval;
+ retval = INVERSE( pc == max );
+ return( retval);
}
-u16 get_token(void)
+
+/* **************************************************************************
+ *
+ * Function name: next_token
+ * Synopsis: Retrieve the next FCode-token from the input-stream.
+ *
+ * Inputs:
+ * Parameters: NONE
+ *
+ * Outputs:
+ * Returned Value: The next FCode-token
+ * Global/Static Variables:
+ * fcode The FCode-token last read.
+ * token_streampos Streampos() of token just gotten
+ *
+ **************************************************************************** */
+
+u16 next_token(void)
{
u16 tok;
- get_byte();
- tok=inbyte;
- if (tok != 0x00 && tok < 0x10) {
- get_byte();
+ token_streampos = get_streampos();
+ tok = *(get_bytes(1));
+ if ( tok != 0x00 && tok < 0x10)
+ {
tok<<=8;
- tok|=inbyte;
+ tok |= *(get_bytes(1));
}
fcode=tok;
- return tok;
+ return(tok);
}
u32 get_num32(void)
{
- u32 ret;
+ u32 retval;
+ u8 *num_str;
- get_byte();
- ret=inbyte<<24;
- get_byte();
- ret|=(inbyte<<16);
- get_byte();
- ret|=(inbyte<<8);
- get_byte();
- ret|=inbyte;
+ num_str = get_bytes(4);
+ retval = BIG_ENDIAN_LONG_FETCH(num_str);
- return ret;
+ return ( retval);
}
u16 get_num16(void)
{
- u16 ret;
+ u16 retval;
+ u8 *num_str;
- get_byte();
- ret=inbyte<<8;
- get_byte();
- ret|=inbyte;
+ num_str = get_bytes(2);
+ retval = BIG_ENDIAN_WORD_FETCH(num_str);
- return ret;
+ return ( retval);
}
u8 get_num8(void)
{
- get_byte();
+ u8 inbyte;
+
+ inbyte = *(get_bytes(1));
return(inbyte);
}
-u16 get_offset(void)
+s16 get_offset(void)
{
+ s16 retval;
if (offs16)
- return (get_num16());
+ {
+ retval = (s16)get_num16();
+ }else{
+ retval = (s16)get_num8();
+ /* Make sure it's sign-extended */
+ retval |= ( retval & 0x80 ) ? 0xff00 : 0 ;
+ }
- return (get_num8());
+ return (retval);
}
+/* **************************************************************************
+ *
+ * Function name: get_string
+ * Synopsis: Return a pointer to a Forth-Style string within the
+ * input stream. Note: this cannot be used to create
+ * a new token-name; use get_name() for that.
+ *
+ * Inputs:
+ * Parameters:
+ * *len Pointer to where the length will go
+ *
+ * Outputs:
+ * Returned Value:
+ * Pointer to the string within the input stream.
+ * Supplied Pointers:
+ * *len Length of the string
+ *
+ * Process Explanation:
+ * Get one byte representing the length of the FORTH-style string.
+ * Get as many bytes as the length indicates.
+ * That's the string. The pointer returned by get_bytes() is
+ * our return value.
+ *
+ **************************************************************************** */
-int scnt=0;
-u8 *get_string(void)
+u8 *get_string(u8 *len)
{
- u8 *data;
- u8 size;
- unsigned int i;
+ char *retval;
+
+ *len = get_num8();
+ retval = get_bytes((int)*len);
- get_byte();
- size=inbyte;
+ return (retval);
+}
- scnt++;
- data=malloc(size+2);
- if (!data) printf ("No more memory.\n");
- data[0]=size;
+/* **************************************************************************
+ *
+ * Function name: get_name
+ * Synopsis: Retrieve a copy of the next string in the input-stream
+ * when it is expected to be a new function-name.
+ *
+ * Inputs:
+ * Parameters:
+ * *len Pointer to where the length will go
+ * Global/Static Variables:
+ * pc "Where we are" in the file-stream
+ *
+ * Outputs:
+ * Returned Value:
+ * Pointer to allocated memory containing a copy of the string
+ * Supplied Pointers:
+ * *len Length of the name
+ * Memory Allocated
+ * Memory for the copy of the string is allocated by strdup()
+ * When Freed?
+ * Never. Retained for duration of the program.
+ *
+ * Process Explanation:
+ * Get the FORTH-style string.
+ * At this point, PC points to the byte that follows the string;
+ * we are going to save that byte and replace it with a zero,
+ * thus creating a C-style string.
+ * We will pass that C-style string as an argument to strdup() ,
+ * which will give us our return value.
+ * Then, of course, we restore the byte we so rudely zeroed, and
+ * proceed merrily on our way.
+ *
+ **************************************************************************** */
+
+char *get_name(u8 *len)
+{
+ char *str_start;
+ char *retval;
+ u8 sav_byt;
- for (i=1; i<size+1; i++) {
- get_byte();
- data[i]=inbyte;
+ str_start = get_string( len );
+
+ sav_byt = *pc;
+ *pc = 0;
+
+ retval = strdup(str_start);
+ *pc = sav_byt;
+
+ return (retval);
}
- data[i]=0;
- return data;
+/* **************************************************************************
+ *
+ * Function name: calc_checksum
+ * Synopsis: Calculate the checksum.
+ * Leave the input position unchanged.
+ *
+ * Inputs:
+ * Parameters: NONE
+ * Global/Static Variables:
+ * pc Pointer to "where we are" in the file-stream
+ *
+ * Outputs:
+ * Returned Value: Calculated checksum.
+ * Global/Static Variables:
+ * pc Reset to value upon entry
+ *
+ * Process Explanation:
+ * When this routine is entered, the PC is presumed to be pointing
+ * just after the stored checksum, and just before the length
+ * field in the FCode header. This is the point at which we
+ * will preserve the PC
+ * Extract the length from the FCode header. It includes the eight
+ * bytes of the FCode header, so we will need to adjust for that.
+ * The first byte after the FCode header is where the checksum
+ * calculation begins.
+ *
+ **************************************************************************** */
+
+u16 calc_checksum(void)
+{
+ u16 retval = 0;
+ u8 *cksmptr;
+ u8 *save_pc;
+ u32 fc_blk_len;
+ int indx;
+
+ save_pc = pc;
+
+ fc_blk_len = get_num32(); /* Read len */
+ cksmptr = get_bytes(fc_blk_len-8); /* Make sure we have all our data */
+
+ for ( indx = 8; indx < fc_blk_len; indx++)
+ {
+ retval += *cksmptr++;
}
+ pc = save_pc;
+ return( retval);
+}
+
+
+/* **************************************************************************
+ *
+ * Function name: adjust_for_pci_header
+ * Synopsis: Skip the PCI Header. Adjust the pointer to
+ * the start of FCode in the file-stream,
+ * and our pointer to "where we are" in the FCode,
+ * by the size of the PCI header.
+ *
+ * Inputs:
+ * Parameters: NONE
+ * Global/Static Variables: (Pointer to:)
+ * pc "where we are" in the file-stream
+ * fc_start start of FCode in the file-stream
+ *
+ * Outputs:
+ * Returned Value: NONE
+ * Global/Static Variables:
+ * pc Advanced past PCI header
+ * fc_start Likewise.
+ * pci_image_found Set or cleared as appropriate.
+ * last_defined_token Re-initialized
+ *
+ * Process Explanation:
+ * Call handle_pci_header to get the size of the PCI header,
+ * if any, and increment pc and fc_start by the number
+ * of bytes it returns; also, set pci_image_found based
+ * on whether the "size of the PCI header" was non-zero.
+ * (Re-)Initialize overlap detection here. Images with multiple
+ * PCI blocks can safely re-cycle FCode numbers; this is
+ * not necessarily true of multiple FCode blocks within
+ * the same PCI block...
+ *
+ **************************************************************************** */
+
+void adjust_for_pci_header(void)
+{
+ int pci_header_size;
+
+ pci_header_size = handle_pci_header(pc);
+ pci_image_found = pci_header_size > 0 ? TRUE : FALSE;
+ pc += pci_header_size;
+ fc_start += pci_header_size;
+ last_defined_token = 0;
+}
+
+/* **************************************************************************
+ *
+ * Function name: adjust_for_pci_filler
+ * Synopsis: Dispatch call to pci-filler-handler
+ *
+ * Inputs:
+ * Parameters: NONE
+ * Global/Static Variables:
+ * pci_image_found Whether to proceed...
+ * pci_image_end Pointer to just after the end of
+ * the current PCI image
+ *
+ * Outputs:
+ * Returned Value: NONE
+ * Global/Static Variables:
+ * pci_image_found Reset to FALSE
+ *
+ * Error Detection:
+ * Confirm that the data-stream has the complete filler,
+ * via a call to get_bytes()
+ *
+ **************************************************************************** */
+
+void adjust_for_pci_filler(void)
+{
+ if ( pci_image_found )
+ {
+ int pci_filler_len;
+ u8 *pci_filler_ptr;
+
+ pci_filler_len = pci_image_end - pc;
+ pci_filler_ptr = get_bytes(pci_filler_len);
+ handle_pci_filler( pci_filler_ptr );
+ pci_image_found = FALSE;
+ }
+}
Modified: fcode-utils/detok/stream.h
===================================================================
--- fcode-utils/detok/stream.h 2006-08-18 09:45:11 UTC (rev 75)
+++ fcode-utils/detok/stream.h 2006-08-18 12:47:12 UTC (rev 76)
@@ -1,3 +1,6 @@
+#ifndef _UTILS_DETOK_STREAM_H
+#define _UTILS_DETOK_STREAM_H
+
/*
* OpenBIOS - free your system!
* ( detokenizer )
@@ -24,16 +27,42 @@
*
*/
+/* **************************************************************************
+ * Modifications made in 2005 by IBM Corporation
+ * (C) Copyright 2005 IBM Corporation. All Rights Reserved.
+ * Modifications Author: David L. Paktor dlpaktor(a)us.ibm.com
+ **************************************************************************** */
+
+#include "types.h"
+
+/* Prototypes for functions exported from stream.c */
+
+
int init_stream(char *name);
-int close_stream(void);
+void close_stream(void);
+bool more_to_go(void);
+void adjust_for_pci_header(void);
+void adjust_for_pci_filler(void);
+void init_fcode_block(void);
+
int get_streampos(void);
-void set_streampos(long pos);
+void set_streampos(int pos);
-u16 get_token(void);
+u16 next_token(void);
u8 get_num8(void);
u16 get_num16(void);
u32 get_num32(void);
-u16 get_offset(void);
-u8 *get_string(void);
+s16 get_offset(void);
+u8 *get_string(u8 *len);
+char *get_name(u8 *len);
+u16 calc_checksum(void);
+/* External declarations for variables defined in stream.c */
+
+extern unsigned int stream_max;
+extern u8 *indata;
+extern u8 *pc;
+extern u8 *max;
+
+#endif /* _UTILS_DETOK_STREAM_H */
Modified: fcode-utils/romheaders/Makefile
===================================================================
--- fcode-utils/romheaders/Makefile 2006-08-18 09:45:11 UTC (rev 75)
+++ fcode-utils/romheaders/Makefile 2006-08-18 12:47:12 UTC (rev 76)
@@ -21,20 +21,21 @@
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA, 02110-1301 USA
#
-
CC = gcc
-CFLAGS= -O2 -Wall -W -ansi
+CFLAGS= -O2 -Wall -W -ansi -I../shared
-.SUFFIXES: .c .o
+SOURCES = romheaders.c ../shared/classcodes.c
+.SUFFIXES: .c
+
all: romheaders
-romheaders: romheaders.o
- $(CC) $(CFLAGS) romheaders.o -o romheaders
+romheaders: $(SOURCES)
+ $(CC) $(CFLAGS) $(SOURCES) -o $@
strip romheaders
clean:
- rm -f *.o
+ rm -f *~
distclean: clean
rm -f romheaders
Modified: fcode-utils/romheaders/romheaders.c
===================================================================
--- fcode-utils/romheaders/romheaders.c 2006-08-18 09:45:11 UTC (rev 75)
+++ fcode-utils/romheaders/romheaders.c 2006-08-18 12:47:12 UTC (rev 76)
@@ -23,6 +23,11 @@
*
*/
+/* **************************************************************************
+ * Modifications made in 2005 by IBM Corporation
+ * (C) Copyright 2005 IBM Corporation. All Rights Reserved.
+ * Modifications Author: David L. Paktor dlpaktor(a)us.ibm.com
+ **************************************************************************** */
#include <stdio.h>
#include <stdlib.h>
@@ -30,60 +35,32 @@
#include <sys/stat.h>
#include <unistd.h>
-#define u8 unsigned char
-#define u16 unsigned short
-#define u32 unsigned int
+#include "pcihdr.h"
-#define PCI_DATA_HDR (u32) ( ('R' << 24) | ('I' << 16) | ('C' << 8) | 'P' )
-
-typedef struct {
- u16 signature;
- u8 reserved[0x16];
- u16 dptr;
-} rom_header_t;
-
-typedef struct {
- u32 signature;
- u16 vendor;
- u16 device;
- u16 reserved_1;
- u16 dlen;
- u8 drevision;
- u8 class_hi;
- u16 class_lo;
- u16 ilen;
- u16 irevision;
- u8 type;
- u8 indicator;
- u16 reserved_2;
-} pci_data_t;
-
char *rom=NULL;
size_t romlen=0;
-/* make this endian safe without fancy system headers */
-static u16 little_word(u16 val)
-{
- u8 *ptr=(u8 *)&val;
- return (ptr[0]|(ptr[1]<<8));
-}
+/* Prototypes for functions exported from shared/classcodes.c */
-static u16 little_dword(u16 val)
-{
- u8 *ptr=(u8 *)&val;
- return (ptr[0]|(ptr[1]<<8)|(ptr[2]<<16)|(ptr[3]<<24));
-}
+char *pci_device_class_name(u32 code);
+char *pci_code_type_name(unsigned char code);
-/* dump the rom headers */
+/* Functions local to this file:
+ int dump_rom_header(rom_header_t *data);
+ int dump_pci_data(pci_data_t *data);
+ void dump_platform_extensions(u8 type, rom_header_t *data);
+ */
+
static int dump_rom_header(rom_header_t *data)
-{
- u16 sig=little_word(data->signature);
+{ /* Return TRUE for "no problem" */
+ const u16 pci_header_signature = 0x55aa;
+ u16 sig=BIG_ENDIAN_WORD_FETCH(data->signature);
int i;
printf ("PCI Expansion ROM Header:\n");
- printf (" Signature: 0x%02x%02x (%s)\n",
- sig&0xff,sig>>8,sig==0xaa55?"Ok":"Not Ok");
+ printf (" Signature: 0x%04x (%s)\n",
+ sig, sig == pci_header_signature ? "Ok":"Not Ok");
printf (" CPU unique data:");
for (i=0;i<16;i++) {
@@ -92,97 +69,41 @@
}
printf ("\n Pointer to PCI Data Structure: 0x%04x\n\n",
- little_word(data->dptr));
+ LITTLE_ENDIAN_WORD_FETCH(data->data_ptr));
- return (sig==0xaa55);
+ return (sig == pci_header_signature);
}
static int dump_pci_data(pci_data_t *data)
-{
- u32 sig=little_dword(data->signature);
- u32 classcode=(data->class_hi<<16)|(little_word(data->class_lo));
+{ /* Return TRUE for "no problem" */
+ const u32 pci_data_hdr = PCI_DATA_HDR ;
+
+ u32 sig = BIG_ENDIAN_LONG_FETCH(data->signature);
+ u32 classcode= CLASS_CODE_FETCH(data->class_code);
+ u32 dlen = (u32)LITTLE_ENDIAN_WORD_FETCH(data->dlen);
+ u32 ilen = (u32)LITTLE_ENDIAN_WORD_FETCH(data->ilen);
printf("PCI Data Structure:\n");
- printf(" Signature: '%c%c%c%c' (%s)\n", sig&0xff,(sig>>8)&0xff,
- (sig>>16)&0xff, sig>>24, sig==PCI_DATA_HDR?"Ok":"Not Ok");
- printf(" Vendor ID: 0x%04x\n", little_word(data->vendor));
- printf(" Device ID: 0x%04x\n", little_word(data->device));
- printf(" Reserved: 0x%04x\n", little_word(data->reserved_1));
- printf(" PCI Data Structure Length: 0x%04x (%d bytes)\n",
- little_word(data->dlen), little_word(data->dlen));
+ printf(" Signature: 0x%04x '%c%c%c%c' ", sig,
+ sig>>24,(sig>>16)&0xff, (sig>>8)&0xff, sig&0xff);
+ printf("(%s)\n", sig == pci_data_hdr ?"Ok":"Not Ok");
+
+ printf(" Vendor ID: 0x%04x\n", LITTLE_ENDIAN_WORD_FETCH(data->vendor));
+ printf(" Device ID: 0x%04x\n", LITTLE_ENDIAN_WORD_FETCH(data->device));
+ printf(" Vital Product Data: 0x%04x\n",
+ LITTLE_ENDIAN_WORD_FETCH(data->vpd));
+ printf(" PCI Data Structure Length: 0x%04x (%d bytes)\n", dlen, dlen);
printf(" PCI Data Structure Revision: 0x%02x\n", data->drevision);
- printf(" Class Code: 0x%06x (",classcode);
- switch (classcode) {
- case 0x0100:
- printf("SCSI Storage");
- break;
- case 0x0101:
- printf("IDE Storage");
- break;
- case 0x0103:
- printf("IPI Storage");
- break;
- case 0x0104:
- printf("RAID Storage");
- break;
- case 0x0180:
- printf("Storage");
- break;
-
- case 0x0200:
- printf("Ethernet");
- break;
- case 0x0201:
- printf("Token Ring");
- break;
- case 0x0202:
- printf("FDDI");
- break;
- case 0x0203:
- printf("ATM");
- break;
- case 0x0280:
- printf("Network");
-
- case 0x0300:
- printf("VGA Display");
- break;
- case 0x0301:
- printf("XGA Display");
- break;
- case 0x0302:
- printf("3D Display");
- break;
- case 0x0380:
- printf("Display");
- break;
-
- default:
- printf("unkown");
- }
- printf(")\n Image Length: 0x%04x blocks (%d bytes)\n",
- little_word(data->ilen), little_word(data->ilen)*512);
+ printf(" Class Code: 0x%06x (%s)\n",classcode,
+ pci_device_class_name(classcode));
+ printf(" Image Length: 0x%04x blocks (%d bytes)\n", ilen, ilen*512);
printf(" Revision Level of Code/Data: 0x%04x\n",
- little_word(data->irevision));
- printf(" Code Type: 0x%02x (", data->type);
- switch (data->type) {
- case 0:
- printf("Intel x86");
- break;
- case 1:
- printf("Open Firmware");
- break;
- case 2:
- printf("HP PA Risc");
- break;
- case 3:
- printf("Intel EFI (unofficial)");
- break;
- default:
- printf("unknown as of PCI specs 2.2");
- }
- printf(")\n Indicator: 0x%02x %s\n", data->indicator,
- data->indicator&0x80?"(last image in rom)":"");
+ (u32)LITTLE_ENDIAN_WORD_FETCH(data->irevision));
+ printf(" Code Type: 0x%02x (%s)\n", data->code_type,
+ pci_code_type_name(data->code_type) );
+ printf(" Last-Image Flag: 0x%02x (%slast image in rom)\n",
+ data->last_image_flag,
+ data->last_image_flag&0x80?"":"not ");
printf(" Reserved: 0x%04x\n\n", little_word(data->reserved_2));
return (sig==PCI_DATA_HDR);
@@ -225,7 +146,7 @@
printf( " Entry point for INIT function:"
" 0x%x\n\n",entry);
} else
- printf( " Unable to determin entry point for INIT"
+ printf( " Unable to determine entry point for INIT"
" function. Please report.\n\n");
break;
@@ -252,9 +173,9 @@
if (argc!=2) {
printf ("\nUsage: %s <romimage.img>\n",argv[0]);
- printf ("\nromheaders dumps pci option rom headers "
+ printf ("\n romheaders dumps pci option rom headers "
"according to PCI \n"
- "specs 2.2 in human readable form\n\n");
+ " specs 2.2 in human readable form\n\n");
return -1;
}
@@ -290,23 +211,25 @@
do {
printf("\nImage %d:\n",i);
if (!dump_rom_header(rom_header)) {
- printf("Error occured. Bailing out.\n");
+ printf("Rom Header error occured. Bailing out.\n");
break;
}
- pci_data=(pci_data_t *)(rom+little_word(rom_header->dptr));
+ pci_data = (pci_data_t *)((char *)rom_header +
+ LITTLE_ENDIAN_WORD_FETCH(rom_header->data_ptr));
if (!dump_pci_data(pci_data)) {
- printf("Error occured. Bailing out.\n");
+ printf("PCI Data error occured. Bailing out.\n");
break;
}
- dump_platform_extensions(pci_data->type, rom_header);
+ dump_platform_extensions(pci_data->code_type, rom_header);
- rom_header+=little_word(pci_data->ilen)*512;
+ rom_header = (rom_header_t *)((char *)rom_header +
+ LITTLE_ENDIAN_WORD_FETCH(pci_data->ilen)*512);
i++;
- } while ((pci_data->indicator&0x80)!=0x80 &&
- romlen<(unsigned long)rom_header-(unsigned long)romlen);
+ } while ((pci_data->last_image_flag&0x80)!=0x80 &&
+ (char *)rom_header < rom+(int)romlen );
return 0;
}
Modified: fcode-utils/toke/Makefile
===================================================================
--- fcode-utils/toke/Makefile 2006-08-18 09:45:11 UTC (rev 75)
+++ fcode-utils/toke/Makefile 2006-08-18 12:47:12 UTC (rev 76)
@@ -1,11 +1,12 @@
#
-# OpenBIOS - free your system!
-# ( FCode tokenizer )
-#
-# This program is part of a free implementation of the IEEE 1275-1994
+# OpenBIOS - free your system!
+# ( Utilities )
+#
+# This program is part of a free implementation of the IEEE 1275-1994
# Standard for Boot (Initialization Configuration) Firmware.
#
-# Copyright (C) 2001-2005 Stefan Reinauer, <stepan(a)openbios.org>
+# Copyright (C) 2001-2006 Stefan Reinauer <stepan(a)openbios.org>
+# Copyright (C) 2006 coresystems GmbH <info(a)coresystems.de>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
@@ -21,52 +22,39 @@
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA, 02110-1301 USA
#
-ARCH := $(shell uname -m | sed -e s/i.86/x86/ -e s/sun4u/sparc64/ -e s/arm.*/arm/ -e s/sa110/arm/ -e s/x86_64/amd64/)
-TOPDIR := $(shell /bin/pwd)
-BUILDDIR ?= $(TOPDIR)/obj-$(ARCH)
-VPATH := $(BUILDDIR)
+PROGRAM = toke
-include $(TOPDIR)/Rules.make
+CC = gcc
+STRIP = strip
+INCLUDES = -I../shared
+#CFLAGS = -O2 -g -Wall
+CFLAGS = -Os -Wall -Wno-pointer-sign -DSYS_IS_GNU_Linux
+LDFLAGS =
-CC = gcc
-CFLAGS = -O2 -Wall -W -ansi -pedantic
-# CFLAGS = -O -g -Wall -ansi -pedantic
+OBJS = clflags.o conditl.o devnode.o dictionary.o emit.o errhandler.o \
+ flowcontrol.o macros.o nextfcode.o parselocals.o scanner.o stack.o \
+ stream.o strsubvocab.o ticvocab.o toke.o tokzesc.o tracesyms.o \
+ usersymbols.o ../shared/classcodes.o
-# CFLAGS := $(CFLAGS) -DDEBUG_SCANNER
-# CFLAGS := $(CFLAGS) -DDEBUG_DSTACK
+all: .dependencies $(PROGRAM)
-OBJECTS= toke.o stack.o stream.o dictionary.o macros.o scanner.o emit.o
+$(PROGRAM): $(OBJS)
+ $(CC) -o $(PROGRAM) $(OBJS) $(LDFLAGS)
+ $(STRIP) -s $(PROGRAM)
-.SUFFIXES: .c .o
+clean:
+ rm -f $(OBJS) *~
-all: main toke
- @cd $(BUILDDIR) && strip toke
- @echo -e "\nOpenBIOS tokenizer toke build finished\n"
+distclean: clean
+ rm -f $(PROGRAM) .dependencies
+
+.dependencies: *.c
+ @$(CC) $(CFLAGS) $(INCLUDES) -MM *.c > .dependencies
-# main should go to rules.make
-main:
- @echo -e "\nWelcome to toke, the OpenBIOS fcode tokenizer.."
- @test -r $(BUILDDIR) || ( mkdir -p $(BUILDDIR); \
- echo -e "\nCreating build directory $(BUILDDIR)" )
+.PHONY: all clean distclean
-toke: $(OBJECTS)
- @echo -n " linking tokenizer executable... "
- @cd $(BUILDDIR) && $(CC) $(CFLAGS) -o $@ $^
- @echo -e "\tok"
-
-clean:
- @test ! -d $(BUILDDIR) && \
- echo "Architecture $(ARCH) is already clean." || \
- ( \
- echo "Cleaning up architecture $(ARCH)"; \
- rm -rf $(BUILDDIR) \
- rm forth.dict.core \
- )
+-include .dependencies
-toke.o: toke.c toke.h stack.h stream.h emit.h
-dictionary.o: dictionary.c toke.h dictionary.h
-emit.o: emit.c toke.h stack.h
-macros.o: macros.c toke.h
-scanner.o: scanner.c toke.h stack.h stream.h dictionary.h
-stack.o: stack.c toke.h stack.h
-stream.o: stream.c toke.h
+.c.o:
+ $(CC) -c $(CFLAGS) $(INCLUDES) $< -o $@
+
Deleted: fcode-utils/toke/Rules.make
===================================================================
--- fcode-utils/toke/Rules.make 2006-08-18 09:45:11 UTC (rev 75)
+++ fcode-utils/toke/Rules.make 2006-08-18 12:47:12 UTC (rev 76)
@@ -1,17 +0,0 @@
-# tag: Makefile rules
-
-VPATH := $(VPATH):.
-
-.S.o:
- echo -n " assembling $<... "
- $(CC) -c -nostdlib $(INCLUDES) $(CFLAGS) $< -o $(BUILDDIR)/$@ && \
- echo -e " \t\tok" || \
- echo -e " \t\tfailed"
-
-.c.o:
- @echo -n " compiling $<... "
- @$(CC) -c $(CFLAGS) $(INCLUDES) $< -o $(BUILDDIR)/$@ && \
- echo -e " \t\tok" || \
- echo -e " \t\failed"
-
-
Added: fcode-utils/toke/clflags.c
===================================================================
--- fcode-utils/toke/clflags.c (rev 0)
+++ fcode-utils/toke/clflags.c 2006-08-18 12:47:12 UTC (rev 76)
@@ -0,0 +1,729 @@
+/*
+ * OpenBIOS - free your system!
+ * ( FCode tokenizer )
+ *
+ * This program is part of a free implementation of the IEEE 1275-1994
+ * Standard for Boot (Initialization Configuration) Firmware.
+ *
+ * Copyright (C) 2001-2005 Stefan Reinauer, <stepan(a)openbios.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA, 02110-1301 USA
+ *
+ */
+
+/* **************************************************************************
+ *
+ * Command-Line Flags are used to control certain non-Standard
+ * variant behaviors of the Tokenizer.
+ * Support Functions for setting, clearing, displaying, etc.
+ * Call them "Special-Feature Flags" in messages to the User
+ *
+ * (C) Copyright 2005 IBM Corporation. All Rights Reserved.
+ * Module Author: David L. Paktor dlpaktor(a)us.ibm.com
+ *
+ **************************************************************************** */
+
+/* **************************************************************************
+ *
+ * For a given CLFlag name, the user may enter either:
+ *
+ * -f CLFlagName
+ * or
+ * -f noCLFlagName
+ *
+ * to either enable or disable the associated function
+ *
+ **************************************************************************** */
+
+/* **************************************************************************
+ *
+ * Functions Exported:
+ * set_cl_flag Set (or clear) a CL Flag Variable
+ * show_all_cl_flag_settings Show CL Flags' settings unconditionally.
+ * list_cl_flag_settings Display CL Flags' settings if changed.
+ * list_cl_flag_names Display just the names of the CL Flags.
+ * cl_flags_help Help Message for CL Flags
+ *
+ **************************************************************************** */
+
+/* **************************************************************************
+ *
+ * Revision History:
+ * Updated Mon, 08 Aug 2005 by David L. Paktor
+ * They're not just for setting from the Command-Line anymore,
+ * but let's still keep these names for internal use....
+ *
+ **************************************************************************** */
+
+/* **************************************************************************
+ *
+ * The CL_FLAGS data structure has a field for the CLFlagName,
+ * one for a text explanation of the function it controls, and
+ * one for the address of the boolean variable ("flag")
+ *
+ **************************************************************************** */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "clflags.h"
+#include "errhandler.h"
+
+
+/* **************************************************************************
+ *
+ * Global Variables Exported
+ * (The "flags" controlled by this means)
+ *
+ **************************************************************************** */
+
+bool ibm_locals = FALSE ;
+bool ibm_locals_legacy_separator = TRUE ;
+bool ibm_legacy_separator_message = TRUE ;
+bool enable_abort_quote = TRUE ;
+bool sun_style_abort_quote = TRUE ;
+bool abort_quote_throw = TRUE ;
+bool string_remark_escape = TRUE ;
+bool hex_remark_escape = TRUE ;
+bool c_style_string_escape = TRUE ;
+bool always_headers = FALSE ;
+bool always_external = FALSE ;
+bool verbose_dup_warning = TRUE ;
+bool obso_fcode_warning = TRUE ;
+bool trace_conditionals = FALSE ;
+bool big_end_pci_image_rev = FALSE ;
+
+/* And one to trigger a "help" message */
+bool clflag_help = FALSE;
+
+/* **************************************************************************
+ *
+ * The addition of the "upper/lower-case-tokens" flags introduces
+ * some complications. These are the variables we will actually
+ * be exporting:
+ *
+ **************************************************************************** */
+
+bool force_tokens_case = FALSE ;
+bool force_lower_case_tokens = FALSE ;
+
+/* **************************************************************************
+ *
+ * but we will be entering two static variables into the table,
+ * and keep two more to detect when a change is made...
+ *
+ **************************************************************************** */
+static bool upper_case_tokens = FALSE ;
+static bool lower_case_tokens = FALSE ;
+static bool was_upper_case_tk = FALSE ;
+static bool was_lower_case_tk = FALSE ;
+
+/* **************************************************************************
+ *
+ * Internal Static Variables
+ * cl_flag_change A change was made to any of the CL Flags
+ * Internal Static Constants
+ * cl_flags_list List of CL Flags and their data.
+ *
+ **************************************************************************** */
+
+static bool cl_flag_change = FALSE;
+
+static const cl_flag_t cl_flags_list[] = {
+ /* The clflag_tabs field takes at least one tab.
+ * If the name has fewer than 16 characters,
+ * stick in an extra tab, and yet another tab
+ * if the name is shorter than 8 characters
+ * to make the formatting of the "explanation"
+ * come out prettier.
+ */
+ { "Local-Values",
+ &ibm_locals,
+ "\t\t",
+ "Support IBM-style Local Values (\"LV\"s)" } ,
+
+ { "LV-Legacy-Separator",
+ &ibm_locals_legacy_separator,
+ "\t",
+ "Allow Semicolon for Local Values Separator (\"Legacy\")" } ,
+
+ { "LV-Legacy-Message",
+ &ibm_legacy_separator_message,
+ "\t",
+ "Display a Message when Semicolon is used as the "
+ "Local Values Separator" } ,
+
+ { "ABORT-Quote",
+ &enable_abort_quote,
+ "\t\t",
+ "Allow ABORT\" macro" } ,
+
+ { "Sun-ABORT-Quote",
+ &sun_style_abort_quote,
+ "\t\t",
+ "ABORT\" with implicit IF ... THEN" } ,
+
+ { "ABORT-Quote-Throw",
+ &abort_quote_throw,
+ "\t",
+ "Use -2 THROW in an Abort\" phrase, rather than ABORT" } ,
+
+ { "String-remark-escape",
+ &string_remark_escape,
+ "\t",
+ "Allow \"\\ (Quote-Backslash) to interrupt string parsing" } ,
+
+ { "Hex-remark-escape",
+ &hex_remark_escape,
+ "\t",
+ "Allow \\ (Backslash) to interrupt "
+ "hex-sequence parsing within a string" } ,
+
+ { "C-Style-string-escape",
+ &c_style_string_escape ,
+ "\t",
+ "Allow \\n \\t and \\xx\\ for special chars in string parsing" } ,
+
+ { "Always-Headers",
+ &always_headers ,
+ "\t\t",
+ "Override \"headerless\" and force to \"headers\"" } ,
+
+ { "Always-External",
+ &always_external ,
+ "\t\t",
+ "Override \"headerless\" and \"headers\" and "
+ "force to \"external\"" } ,
+
+ { "Warn-if-Duplicate",
+ &verbose_dup_warning ,
+ "\t",
+ "Display a WARNING message when a duplicate definition is made" } ,
+
+ { "Obsolete-FCode-Warning",
+ &obso_fcode_warning ,
+ "\t",
+ "Display a WARNING message when an \"obsolete\" "
+ "(per the Standard) FCode is used" } ,
+
+ { "Trace-Conditionals",
+ &trace_conditionals,
+ "\t",
+ "Display ADVISORY messages about the state of "
+ "Conditional Tokenization" } ,
+
+ { "Upper-Case-Token-Names",
+ &upper_case_tokens,
+ "\t",
+ "Convert Token-Names to UPPER-Case" } ,
+
+
+ { "Lower-Case-Token-Names",
+ &lower_case_tokens,
+ "\t",
+ "Convert Token-Names to lower-Case" } ,
+
+
+ { "Big-End-PCI-Rev-Level",
+ &big_end_pci_image_rev,
+ "\t",
+ "Save the Vendor's Rev Level field of the PCI Header"
+ " in Big-Endian format" } ,
+
+
+ /* Keep the "help" pseudo-flag last in the list */
+ { "help",
+ &clflag_help,
+ /* Two extra tabs if the name is shorter than 8 chars */
+ "\t\t\t",
+ "Print this \"Help\" message for the Special-Feature Flags" }
+
+};
+
+static const int number_of_cl_flags =
+ sizeof(cl_flags_list)/sizeof(cl_flag_t);
+
+
+/* **************************************************************************
+ *
+ * CL Flags whose settings are changed in the source file should
+ * not stay in effect for the duration of the entire batch of
+ * tokenizations (i.e., if multiple input files are named on
+ * the command line) the way command-line settings should.
+ * To accomplish this we will collect the state of the flags into
+ * a bit-mapped variable after the command line has been parsed
+ * and restore them to their collected saved state before an
+ * input file is processed.
+ *
+ **************************************************************************** */
+
+static long int cl_flags_bit_map;
+/* If the number of CL Flags ever exceeds the number of bits in a long
+ * (presently 32), we will need to change both this variable and
+ * the routines that use it. Of course, if the number of CL Flags
+ * ever gets that high, it will be *seriously* unwieldy... ;-}
+ */
+
+/* **************************************************************************
+ *
+ * Function name: adjust_case_flags
+ * Synopsis: If the last CL Flag Variable setting changed one of
+ * the "upper/lower-case-tokens" flags, make the
+ * appropriate adjustments.
+ *
+ * Inputs:
+ * Parameters: NONE
+ * Local Static Variables:
+ * was_upper_case_tk State of "upper-case-tokens" flag before
+ * last CL Flag Variable was processed
+ * was_lower_case_tk State of "lower-case-tokens" flag, before
+ * upper_case_tokens State of "upper-case-tokens" flag after
+ * last CL Flag V'ble was processed
+ * lower_case_tokens State of "lower-case-tokens" flag, after
+ * Global Variables:
+ *
+ * Outputs:
+ * Returned Value: NONE
+ * Global Variables:
+ * force_tokens_case TRUE if "upper/lower-case-tokens"
+ * flag is in effect
+ * force_lower_case_tokens If force_tokens_case is TRUE, then
+ * this switches between "upper"
+ * or "lower" case
+ *
+ * Process Explanation:
+ * We cannot come out of this with both upper_case_tokens and
+ * lower_case_tokens being TRUE, though they may both be FALSE.
+ * If neither has changed state, we need not do anything here.
+ * If one has gone to TRUE, we must force the other to FALSE and
+ * we will set force_tokens_case to TRUE.
+ * If one has gone to FALSE, turn force_tokens_case to FALSE.
+ * If force_tokens_case is TRUE after all this, we must adjust
+ * force_lower_case_tokens according to lower_case_tokens
+ *
+ **************************************************************************** */
+
+static void adjust_case_flags( void)
+{
+ static bool *case_tokens[2] = { &upper_case_tokens, &lower_case_tokens };
+ static bool *was_case_tk[2] = { &was_upper_case_tk, &was_lower_case_tk };
+ int the_one = 0;
+ int the_other = 1;
+
+ for ( ; the_one < 2 ; the_one++ , the_other-- )
+ {
+ /* If one has changed state */
+ if ( *(case_tokens[the_one]) != *(was_case_tk[the_one]) )
+ {
+ if ( *(case_tokens[the_one]) )
+ {
+ /* If it has gone to TRUE, force the other to FALSE. */
+ *(case_tokens[the_other]) = FALSE;
+ /* and set force_tokens_case to TRUE */
+ force_tokens_case = TRUE;
+ }else{
+ /* If it has gone to FALSE turn force_tokens_case FALSE */
+ force_tokens_case = FALSE;
+ }
+ if ( force_tokens_case )
+ {
+ force_lower_case_tokens = lower_case_tokens;
+ }
+ break; /* Only one can have changed state. */
+ }
+ }
+}
+
+
+
+
+/* **************************************************************************
+ *
+ * Function name: set_cl_flag
+ * Synopsis: Set (or clear) the named CL Flag Variable
+ *
+ * Inputs:
+ * Parameters:
+ * flag_name The name as supplied by the user
+ * from_src TRUE if called from source-input file
+ * Static Constants:
+ * cl_flags_list
+ * number_of_cl_flags
+ *
+ * Outputs:
+ * Returned Value: TRUE if supplied name is not valid
+ * Global Variables:
+ * The CL Flag Variable associated with the supplied name will
+ * be set or cleared according to the leading "no"
+ * Local Static Variables:
+ * cl_flag_change TRUE if associated variable has changed
+ * Printout:
+ * If from_src is TRUE, print "En" or "Dis" abling:
+ * followed by the explanation
+ *
+ * Error Detection:
+ * If the supplied name is not a valid CL Flag name, or if
+ * it's too short to be a valid CL Flag name, return TRUE.
+ * Print a message; either a simple print if this function was
+ * called from a command-line argument, or an ERROR if it
+ * was called from a line in the from source-input file.
+ *
+ * Process Explanation:
+ * Save the current state of the "upper/lower-case-tokens" flags
+ * If the given name has a leading "no", make note of that fact
+ * and remove the leading "no" from the comparison.
+ * Compare with the list of valid CL Flag names.
+ * If no match was found, Error. See under Error Detection.
+ * If a match:
+ * Change the associated variable according to the leading "no"
+ * Set cl_flag_change to TRUE unless the variable is the one
+ * associated with the "help" flag; this permits the
+ * "Default" vs "Setting" part of cl_flags_help() to
+ * work properly...
+ * Do the conditional Printout (see above)
+ * Adjust the "upper/lower-case-tokens" flags if one has changed.
+ *
+ **************************************************************************** */
+static bool first_err_msg = TRUE; /* Need extra carr-ret for first err msg */
+bool set_cl_flag(char *flag_name, bool from_src)
+{
+ bool retval = TRUE;
+
+ was_upper_case_tk = upper_case_tokens;
+ was_lower_case_tk = lower_case_tokens;
+
+ if ( strlen(flag_name) > 3 )
+ {
+ int indx;
+ bool flagval = TRUE;
+ char *compar = flag_name;
+
+ if ( strncasecmp( flag_name, "no", 2) == 0 )
+ {
+ flagval = FALSE;
+ compar += 2;
+ }
+ for ( indx = 0 ; indx < number_of_cl_flags ; indx++ )
+ {
+ if ( strcasecmp( compar, cl_flags_list[indx].clflag_name ) == 0 )
+ {
+ retval = FALSE;
+ *(cl_flags_list[indx].flag_var) = flagval;
+
+ /* The "help" flag is the last one in the list */
+ if ( indx != number_of_cl_flags - 1 )
+ {
+ cl_flag_change = TRUE;
+ }
+ if ( from_src )
+ {
+ tokenization_error(INFO,
+ "%sabling: %s\n",
+ flagval ? "En" : "Dis", cl_flags_list[indx].clflag_expln);
+ }
+ break;
+ }
+ }
+ }
+
+ if ( retval )
+ {
+ const char* msg_txt = "Unknown Special-Feature Flag: %s\n" ;
+ if ( from_src )
+ {
+ tokenization_error( TKERROR, (char *)msg_txt, flag_name);
+ }else{
+ if ( first_err_msg )
+ {
+ printf( "\n");
+ first_err_msg = FALSE;
+ }
+ printf( msg_txt, flag_name);
+ }
+ }
+
+ adjust_case_flags();
+
+ return ( retval );
+}
+
+/* **************************************************************************
+ *
+ * Function name: show_all_cl_flag_settings
+ * Synopsis: Display the settings of the CL Flags, (except "help")
+ * regardless of whether they have been changed.
+ *
+ * Associated Tokenizer directive(s): [FLAGS]
+ * #FLAGS
+ * [#FLAGS]
+ * SHOW-FLAGS
+ * This routine may also be invoked by a combination of
+ * options on the command-line.
+ *
+ * Inputs:
+ * Parameters:
+ * from_src TRUE if called from source-input file
+ * Macro:
+ * ERRMSG_DESTINATION Error message destination;
+ * (Development-time switch)
+ * Static Constants:
+ * cl_flags_list
+ * number_of_cl_flags
+ *
+ * Outputs:
+ * Returned Value: NONE
+ * Printout: Directed to stdout or to stderr
+ * (see definition of ERRMSG_DESTINATION)
+ * A header line, followed by the names of the CL Flags,
+ * with "No" preceding name if value is FALSE, one to a line.
+ *
+ * Process Explanation:
+ * If from_src is TRUE, print the header line as a Message, and
+ * then direct output to ERRMSG_DESTINATION .
+ * Don't print the "help" trigger (the last flag in the array).
+ *
+ **************************************************************************** */
+
+void show_all_cl_flag_settings(bool from_src)
+{
+ const char* hdr_txt = "Special-Feature Flag settings:" ;
+ int indx;
+
+ if ( from_src )
+ {
+ tokenization_error(MESSAGE, (char *)hdr_txt);
+ }else{
+ printf("\n%s\n", hdr_txt);
+ }
+
+ for ( indx = 0 ; indx < (number_of_cl_flags - 1) ; indx++ )
+ {
+ fprintf( from_src ? ERRMSG_DESTINATION : stdout ,
+ "\t%s%s\n",
+ *(cl_flags_list[indx].flag_var) ? " " : "No" ,
+ cl_flags_list[indx].clflag_name );
+ }
+ if ( from_src ) fprintf( ERRMSG_DESTINATION, "\n");
+}
+
+/* **************************************************************************
+ *
+ * Function name: list_cl_flag_settings
+ * Synopsis: Display the settings of the CL Flags, (except "help")
+ * if any of them have been changed
+ *
+ * Inputs:
+ * Parameters: NONE
+ * Local Static Variables:
+ * cl_flag_change TRUE if a Flag setting has been changed.
+ *
+ * Outputs:
+ * Returned Value: NONE
+ * Printout:
+ * Settings of the CL Flags. See show_all_cl_flag_settings()
+ *
+ * Process Explanation:
+ * Don't print anything if cl_flag_change is not TRUE
+ *
+ **************************************************************************** */
+
+void list_cl_flag_settings(void)
+{
+
+ if ( cl_flag_change )
+ {
+ show_all_cl_flag_settings( FALSE);
+ }
+}
+
+
+/* **************************************************************************
+ *
+ * Function name: list_cl_flag_names
+ * Synopsis: Display just the names of the CL Flags
+ * for the Usage message
+ *
+ * Inputs:
+ * Parameters: NONE
+ * Static Constants:
+ * cl_flags_list
+ * number_of_cl_flags
+ *
+ * Outputs:
+ * Returned Value: NONE
+ * Printout:
+ * A header line, followed by the names of the CL Flags,
+ *
+ **************************************************************************** */
+
+void list_cl_flag_names(void)
+{
+ int indx;
+
+ printf("Valid Special-Feature Flags are:\n");
+ for ( indx = 0 ; indx < number_of_cl_flags ; indx++ )
+ {
+ printf("\t%s\n", cl_flags_list[indx].clflag_name );
+ }
+}
+
+/* **************************************************************************
+ *
+ * Function name: cl_flags_help
+ * Synopsis: Display Usage of the CL Flags and their defaults
+ *
+ *
+ * Inputs:
+ * Parameters:: NONE
+ * Static Constants:
+ * cl_flags_list
+ * number_of_cl_flags
+ * Local Static Variables:
+ * cl_flag_change TRUE if setting has been changed.
+ *
+ * Outputs:
+ * Returned Value: NONE
+ * Printout:
+ * A few lines of header, followed by the default, the name
+ * and the "explanation" of each of the CL Flags, one to a line.
+ *
+ * Extraneous Remarks:
+ * We take advantage of the facts that this routine is called
+ * (1) only from the command-line, before any settings
+ * have been changed, and (2) via changing the flag for
+ * "help" to TRUE. (Technically, I suppose, the default
+ * for the "help" feature is "no", but showing will, I
+ * think be more confusing than enlightening to the user.)
+ * Also, I suppose a perverse user could change setting(s) on
+ * the same command-line with a "-f help" request; we cannot
+ * stop users from aiming at their boot and pulling the
+ * trigger. As my buddies in Customer Support would say:
+ * "KMAC YOYO" (Approximately, "You're On Your Own, Clown")...
+ *
+ * Revision History:
+ * Oh, all right. If the user changed setting(s), we can do
+ * them the minor courtesy of printing "Setting" instead
+ * of "Default".
+ *
+ *
+ **************************************************************************** */
+
+void cl_flags_help(void )
+{
+ int indx;
+
+ printf("\n"
+ "Special-Feature Flags usage:\n"
+ " -f FlagName to enable the feature associated with FlagName,\n"
+ "or\n"
+ " -f noFlagName to disable the feature.\n\n"
+ "%s Flag-Name\t\t Feature:\n\n",
+ cl_flag_change ? "Setting" : "Default" );
+
+ for ( indx = 0 ; indx < number_of_cl_flags ; indx++ )
+ {
+ printf(" %s %s%s%s\n",
+ *(cl_flags_list[indx].flag_var) ? " " : "no" ,
+ cl_flags_list[indx].clflag_name,
+ cl_flags_list[indx].clflag_tabs,
+ cl_flags_list[indx].clflag_expln);
+ }
+
+}
+
+
+
+/* **************************************************************************
+ *
+ * Function name: save_cl_flags
+ * Synopsis: Collect the state of the CL Flags
+ *
+ * Inputs:
+ * Parameters: NONE
+ * Local Static Variables:
+ * cl_flags_list
+ * Static Constants:
+ * number_of_cl_flags
+ *
+ * Outputs:
+ * Returned Value: NONE
+ * Local Static Variables:
+ * cl_flags_bit_map Will be set to reflect the state
+ * of the CL Flags in the list.
+ *
+ * Process Explanation:
+ * The correspondence of bits to the list is that the first item
+ * in the list corresponds to the low-order bit, and so on
+ * moving toward the high-order with each successive item.
+ * Do not save the "help" flag (last item on the list).
+ * This routine is called after the command line has been parsed.
+ *
+ **************************************************************************** */
+
+void save_cl_flags(void)
+{
+ int indx;
+ long int moving_bit = 1;
+
+ cl_flags_bit_map = 0;
+ for ( indx = 0 ; indx < (number_of_cl_flags - 1) ; indx++ )
+ {
+ if ( *(cl_flags_list[indx].flag_var) )
+ {
+ cl_flags_bit_map |= moving_bit; /* The moving finger writes, */
+ }
+ moving_bit <<= 1; /* and having writ, moves on. */
+ }
+}
+
+/* **************************************************************************
+ *
+ * Function name: reset_cl_flags
+ * Synopsis: Restore the CL Flags to the state that was saved.
+ *
+ * Inputs:
+ * Parameters: NONE
+ * Local Static Variables:
+ * cl_flags_bit_map Reflects the state of the CL Flags
+ * Static Constants:
+ * number_of_cl_flags
+ *
+ * Outputs:
+ * Returned Value: NONE
+ * Local Static Variables:
+ * cl_flags_list
+ * Global Variables:
+ * The CL Flag Variables will be set or cleared
+ * to their saved state
+ *
+ * Process Explanation:
+ * This routine is called before starting a new input file.
+ * Any changes made in the source file will not stay
+ * in effect for the next tokenization.
+ *
+ **************************************************************************** */
+
+void reset_cl_flags(void)
+{
+ int indx;
+ long int moving_bit = 1;
+
+ for ( indx = 0 ; indx < (number_of_cl_flags - 1) ; indx++ )
+ {
+ *(cl_flags_list[indx].flag_var) =
+ BOOLVAL( cl_flags_bit_map & moving_bit) ;
+ moving_bit <<= 1;
+ }
+}
Added: fcode-utils/toke/clflags.h
===================================================================
--- fcode-utils/toke/clflags.h (rev 0)
+++ fcode-utils/toke/clflags.h 2006-08-18 12:47:12 UTC (rev 76)
@@ -0,0 +1,144 @@
+#ifndef _TOKE_CLFLAGS_H
+#define _TOKE_CLFLAGS_H
+
+/*
+ * OpenBIOS - free your system!
+ * ( FCode tokenizer )
+ *
+ * This program is part of a free implementation of the IEEE 1275-1994
+ * Standard for Boot (Initialization Configuration) Firmware.
+ *
+ * Copyright (C) 2001-2005 Stefan Reinauer, <stepan(a)openbios.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA, 02110-1301 USA
+ *
+ */
+
+/* **************************************************************************
+ *
+ * Function Prototypes and External declarations
+ * for Command-Line Flags Support
+ *
+ * (C) Copyright 2005 IBM Corporation. All Rights Reserved.
+ * Module Author: David L. Paktor dlpaktor(a)us.ibm.com
+ *
+ **************************************************************************** */
+
+/* **************************************************************************
+ *
+ * Structure-Types:
+ * cl_flag_t Data for recognizing and setting Command-Line
+ * Flags, and for displaying the help message
+ *
+ * Function Prototypes / Functions Exported:
+ * set_cl_flag
+ * list_cl_flag_settings
+ * list_cl_flag_names Display just the names of the CL Flags
+ * cl_flags_help
+ *
+ * Global Variables Exported
+ * (These flags, which are set by the set_cl_flag() routine,
+ * are used throughout the Tokenizer to control certain
+ * non-Standard variant behaviors.)
+ * ibm_locals
+ * ibm_locals_legacy_separator
+ * ibm_legacy_separator_message
+ * enable_abort_quote
+ * sun_style_abort_quote
+ * string_remark_escape
+ * hex_remark_escape
+ * c_style_string_escape
+ * always_headers
+ * always_external
+ * verbose_dup_warning
+ * obso_fcode_warning
+ * trace_conditionals
+ * force_tokens_case
+ * force_lower_case_tokens
+ * big_end_pci_image_rev
+ * clflag_help
+ *
+ **************************************************************************** */
+
+/* **************************************************************************
+ * Structure-Type Name: cl_flag_t
+ * Data for recognizing and setting Command-Line Flags,
+ * and for displaying the help message
+ *
+ * Fields:
+ * clflag_name *char CL Flag name, as entered by the user
+ * flag_var *bool Address of boolean ("flag") variable
+ * clflag_tabs *char Tabs to align the explanations, in
+ * the help message display
+ * clflag_expln *char Explanation, used in help message
+ *
+ * Since this structure will be initialized by the program, and will not
+ * be added-to, we can structure it as purely an array, and have no
+ * need to treat it as a linked list, hence no link-field.
+ *
+ **************************************************************************** */
+
+#include "types.h"
+
+typedef struct cl_flag
+ {
+ char *clflag_name;
+ bool *flag_var;
+ char *clflag_tabs;
+ char *clflag_expln;
+ } cl_flag_t ;
+
+
+/* **************************************************************************
+ *
+ * Exported Global Variables
+ *
+ **************************************************************************** */
+
+extern bool ibm_locals;
+extern bool ibm_locals_legacy_separator;
+extern bool ibm_legacy_separator_message;
+extern bool enable_abort_quote;
+extern bool sun_style_abort_quote;
+extern bool abort_quote_throw;
+extern bool string_remark_escape;
+extern bool hex_remark_escape;
+extern bool c_style_string_escape;
+extern bool always_headers;
+extern bool always_external;
+extern bool verbose_dup_warning;
+extern bool obso_fcode_warning;
+extern bool trace_conditionals;
+extern bool big_end_pci_image_rev;
+
+extern bool force_tokens_case;
+extern bool force_lower_case_tokens;
+
+extern bool clflag_help;
+
+/* **************************************************************************
+ *
+ * Exported Functions
+ *
+ **************************************************************************** */
+
+bool set_cl_flag(char *flag_name, bool print_message);
+void cl_flags_help(void);
+void list_cl_flag_names(void);
+void show_all_cl_flag_settings(bool from_src);
+void list_cl_flag_settings(void);
+void save_cl_flags(void);
+void reset_cl_flags(void);
+
+#endif /* _TOKE_CLFLAGS_H */
Added: fcode-utils/toke/conditl.c
===================================================================
--- fcode-utils/toke/conditl.c (rev 0)
+++ fcode-utils/toke/conditl.c 2006-08-18 12:47:12 UTC (rev 76)
@@ -0,0 +1,772 @@
+/*
+ * OpenBIOS - free your system!
+ * ( FCode tokenizer )
+ *
+ * This program is part of a free implementation of the IEEE 1275-1994
+ * Standard for Boot (Initialization Configuration) Firmware.
+ *
+ * Copyright (C) 2001-2005 Stefan Reinauer, <stepan(a)openbios.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA, 02110-1301 USA
+ *
+ */
+
+/* **************************************************************************
+ *
+ * Conditional-Compilation support for Tokenizer
+ *
+ * (C) Copyright 2005 IBM Corporation. All Rights Reserved.
+ * Module Author: David L. Paktor dlpaktor(a)us.ibm.com
+ *
+ **************************************************************************** */
+
+/* **************************************************************************
+ *
+ * Functions Exported:
+ * init_conditionals_vocab Initialize the "Conditionals" Vocabulary.
+ * handle_conditional Confirm whether a given name is a valid
+ * Conditional, and, if so, perform its
+ * function and return an indication.
+ * create_conditional_alias Add an alias to "Conditionals" vocab
+ * reset_conditionals Reset the "Conditionals" Vocabulary
+ * to its "Built-In" position.
+ *
+ **************************************************************************** */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <string.h>
+#include <errno.h>
+
+#include "scanner.h"
+#include "errhandler.h"
+#include "ticvocab.h"
+#include "conditl.h"
+#include "stack.h"
+#include "dictionary.h"
+#include "vocabfuncts.h"
+#include "usersymbols.h"
+#include "stream.h"
+#include "clflags.h"
+
+/* **************************************************************************
+ *
+ * Global Variables Imported
+ * statbuf Start of input-source buffer
+ * pc Input-source Scanning pointer
+ * iname Current Input File name
+ * lineno Current Line Number in Input File
+ *
+ **************************************************************************** */
+
+/* **************************************************************************
+ *
+ * Local Static Variables
+ * already_ignoring Location from which to pass a parameter,
+ * called "alr_ign" to the main routine. Each
+ * "Conditional" will have an associated routine
+ * that takes the pointer to this as its argument.
+ * The pointer to this will satisfy the "param-field"
+ * requirement of a TIC_HDR-style "Vocabulary"-list.
+ * conditionals_tbl TIC_HDR-style "Vocabulary"-list table, initialized
+ * as an array.
+ * conditionals Pointer to "tail" of Conditionals Vocabulary-list
+ *
+ **************************************************************************** */
+
+/* **************************************************************************
+ *
+ * The lists of synonymous forms of the #ELSE and #THEN operators
+ * are incorporated into the "Shared Words" Vocabulary.
+ *
+ **************************************************************************** */
+
+/* **************************************************************************
+ *
+ * Function name: is_a_then / is_an_else
+ * Synopsis: Indicate whether the given name is one of the
+ * [then] / [else] synonyms
+ *
+ * Inputs:
+ * Parameters:
+ * a_word Word to test
+ *
+ * Outputs:
+ * Returned Value: TRUE if the given name is one of the synonyms
+ *
+ * Process Explanation:
+ * The functions are twins, hence bundling them like this...
+ *
+ **************************************************************************** */
+
+
+/* **************************************************************************
+ *
+ * Support function: is_a_type
+ * Synopsis: Indicate whether the given name is a "shared word"
+ * whose FWord Token matches the one given
+ *
+ * Inputs:
+ * Parameters:
+ * tname Target name to look for
+ * fw_type The FWord Token type to match
+ *
+ * Outputs:
+ * Returned Value: TRUE if it matches
+ *
+ **************************************************************************** */
+
+
+static bool is_a_type( char *tname, fwtoken fw_type)
+{
+ bool retval = FALSE;
+ tic_fwt_hdr_t *found = (tic_fwt_hdr_t *)lookup_shared_f_exec_word( tname );
+ if ( found != NULL )
+ {
+ if ( found->pfield.fw_token == fw_type ) retval = TRUE;
+ }
+ return ( retval );
+}
+
+static bool is_a_then( char *a_word)
+{
+ bool retval = is_a_type( a_word, CONDL_ENDER);
+ return ( retval );
+}
+
+static bool is_an_else( char *a_word)
+{
+ bool retval = is_a_type( a_word, CONDL_ELSE);
+ return ( retval );
+}
+
+/* **************************************************************************
+ *
+ * This is a somewhat roundabout way of passing an "already ignoring"
+ * parameter to the various Conditional Operators. Each operator's
+ * Parameter-Field Pointer points to this. The calling routine
+ * must set it (or rely on the default); the routine that handles
+ * nesting of Conditionals must save and restore a local copy.
+ *
+ **************************************************************************** */
+
+static bool already_ignoring = FALSE;
+
+/* **************************************************************************
+ *
+ * Further down, will define and initialize a word-list table with
+ * all the functions that implement the Conditional Operators,
+ * and we'll link it in with the "Global Vocabulary" pointer.
+ *
+ * We'll call the word-list the "Conditionals Vocabulary Table",
+ * and refer to its entries as the "Conditionals Vocabulary",
+ * even though it isn't really a separate vocabulary...
+ *
+ **************************************************************************** */
+
+
+/* **************************************************************************
+ *
+ * We also need a few common routines to pass as "Ignoring" functions
+ * for a few occasional words that take another word or two from
+ * the input stream as their arguments. For example, if the user
+ * were to write: alias [otherwise] [else] and that were to
+ * occur within a segment already being ignored, we need to make
+ * sure that this doesn't get processed as an occurrence of [else]
+ * Similarly with macro-definitions.
+ *
+ * Since we are using the term "ignore a word" to mean "look it up and
+ * process it in Ignoring-state", we need a different term to name
+ * this class of routine; let's use the term "skip a word" where
+ * the "word" is strictly an input token, delimited by whitespace.
+ *
+ **************************************************************************** */
+
+/* **************************************************************************
+ *
+ * Function name: skip_a_word
+ * Synopsis: Consume one input-token ("word") from the
+ * Input Stream, with no processing
+ *
+ * Inputs:
+ * Parameters:
+ * pfield "Parameter field" pointer, to satisfy
+ * the calling convention, but not used
+ *
+ * Outputs:
+ * Returned Value: NONE
+ *
+ **************************************************************************** */
+
+void skip_a_word( tic_bool_param_t pfield )
+{
+ /* signed long wlen = */ get_word();
+}
+
+/* **************************************************************************
+ *
+ * Function name: skip_a_word_in_line
+ * Synopsis: Consume one input-token ("word") on the same line
+ * as the current line of input, from the Input
+ * Stream, with no processing.
+ *
+ * Inputs:
+ * Parameters:
+ * pfield "Parameter field" pointer, to satisfy
+ * the calling convention, but not used
+ * Global Variables:
+ * statbuf The word being processed, which expects
+ * another word on the same line; used
+ * for the Error message.
+ *
+ * Outputs:
+ * Returned Value: NONE
+ *
+ * Error Detection:
+ * get_word_in_line() will check and report if no word on same line.
+ *
+ **************************************************************************** */
+void skip_a_word_in_line( tic_bool_param_t pfield )
+{
+ /* bool isokay = */ get_word_in_line( statbuf);
+}
+
+/* **************************************************************************
+ *
+ * Function name: skip_two_words_in_line
+ * Synopsis: Consume two input-tokens ("words") on the same line
+ * as the current line of input, from the Input
+ * Stream, with no processing.
+ *
+ * Inputs:
+ * Parameters:
+ * pfield "Parameter field" pointer, to satisfy
+ * the calling convention, but not used
+ * Global Variables:
+ * statbuf The word being processed, which expects
+ * two words on the same line; used for
+ * the Error message.
+ *
+ * Outputs:
+ * Returned Value: NONE
+ * Memory Allocated
+ * Copy of statbuf for Error message.
+ * When Freed?
+ * End of this routine
+ *
+ * Error Detection:
+ * get_word_in_line() will check and report
+ *
+ **************************************************************************** */
+
+void skip_two_words_in_line( tic_bool_param_t pfield )
+{
+ char *func_cpy = strupr( strdup( statbuf));
+ if ( get_word_in_line( func_cpy) )
+ {
+ /* bool isokay = */ get_word_in_line( func_cpy);
+ }
+ free( func_cpy);
+}
+
+
+/* **************************************************************************
+ *
+ * Function name: ignore_one_word
+ * Synopsis: Handle a word that needs processing while "ignoring"
+ * Ignore the rest.
+ *
+ * Inputs:
+ * Parameters:
+ * tname Target name to test
+ * Local Static Variables:
+ * already_ignoring The "Already Ignoring" flag
+ *
+ * Outputs:
+ * Returned Value: NONE
+ * Global Variables:
+ * tic_found Set to the TIC-entry that has just been
+ * found, in case it's a Macro.
+ * Local Static Variables:
+ * already_ignoring Intermediately set to TRUE, then
+ * returned to former state.
+ *
+ * Process Explanation:
+ * When we are ignoring source input, we still need to be
+ * sensitive to the nesting of Conditional Operators, to
+ * consume comments and user -message text-bodies, and to
+ * expand Macros, among other things.
+ * Rather than create special cases here for each one, we have
+ * added an "ign_funct" pointer to those words where this
+ * is relevant, including Conditional Operators.
+ * Save the state of already_ignoring and set it to TRUE
+ * Execute the "Ignoring" Function associated with the entry
+ * Restore already_ignoring to its previous state.
+ * This is necessary if the word is a Conditional Operator and
+ * is harmless otherwise.
+ *
+ **************************************************************************** */
+
+static void ignore_one_word( char *tname)
+{
+ tic_bool_hdr_t *found = (tic_bool_hdr_t *)lookup_word( tname, NULL, NULL);
+ if ( found != NULL )
+ {
+ if ( found->ign_func != NULL )
+ {
+ bool save_already_ignoring = already_ignoring;
+ already_ignoring = TRUE ;
+ tic_found = (tic_hdr_t *)found;
+
+ found->ign_func( found->pfield);
+
+ already_ignoring = save_already_ignoring;
+ }
+ }
+}
+
+/* **************************************************************************
+ *
+ * Function name: conditionally_tokenize
+ * Synopsis: Conduct tokenization while a Conditional-Tokenization
+ * operator is in effect. This is the core of the
+ * implementation of Conditional-Tokenization.
+ *
+ * Inputs:
+ * Parameters:
+ * cond The state of the Condition-Flag that the
+ * immediate Conditional Operator acquired.
+ * TRUE means "do not ignore". Its sense
+ * is reversed when [ELSE] is encountered.
+ * alr_ign TRUE means we are Already Ignoring source input,
+ * except for Conditional Operators...
+ * Global Variables:
+ * statbuf The symbol (word) just retrieved from input stream.
+ * iname Current Input File name (for Error Messages)
+ * lineno Current Line Number in Input File (ditto)
+ * trace_conditionals Whether to issue ADVISORY messages about
+ * the state of Conditional Tokenization.
+ *
+ * Outputs:
+ * Returned Value: NONE
+ * Global Variables:
+ * statbuf Will be advanced to the balancing [THEN] op'r.
+ * already_ignoring Set to TRUE if nested Conditional encountered;
+ * restored to previous state when done.
+ * Memory Allocated
+ * Duplicate of Input File name, for Error Messages
+ * When Freed?
+ * Just prior to exit from routine.
+ * Printout:
+ * ADVISORY messages, if "Trace-Conditionals" flag was selected.
+ *
+ * Global Behavior:
+ * Tokenization happens, or inputs are ignored, as necessary.
+ *
+ * Error Detection:
+ * End-of-file encountered on reading a word
+ * ERROR. Conditional Operators must be balanced within a file
+ * More than one [ELSE] encountered: ERROR if processing segment;
+ * if ignoring, WARNING.
+ *
+ * Process Explanation:
+ * Read a word at a time. Allow Macros to "pop" transparently,
+ * but not source files.
+ * If the word is a [THEN], we are done.
+ * If the word is an [ELSE], then, if we are not Already Ignoring,
+ * invert the sense of whether we are ignoring source input.
+ * If this is not the only [ELSE] in the block, report an Error
+ * and disregard it.
+ * If we are ignoring source input, for whatever reason, we still
+ * need to be sensitive to the nesting of Conditional Operators:
+ * If the word is a Conditional Operator, activate it with the
+ * "Already Ignoring" parameter set to TRUE; doing so will
+ * result in a nested call to this routine.
+ * Otherwise, i.e., if the word is not a Conditional Operator,
+ * we may still need to process it in "ignoring" mode:
+ * we need, for instance, to consume strings, comments
+ * and the text-bodies of user-messages in their entirety,
+ * in case there is a reference to an [ELSE] or suchlike.
+ * The words that need processing while "ignoring" will
+ * have a valid function-pointer in their ign_func field.
+ * If we are not ignoring source input, pass the word along to the
+ * tokenize_one_word routine and process it. If the word is
+ * a Conditional Operator, it will be handled in the context
+ * of normal (i.e., non-ignored) tokenization, and, again, a
+ * nested call to this routine will result...
+ *
+ * Revision History:
+ * Updated Thu, 23 Feb 2006 by David L. Paktor
+ * Conditional Blocks may begin with a Conditional Operator in
+ * a Macro definition and do not need to be concluded in
+ * the body of the Macro.
+ * Updated Fri, 10 Mar 2006 by David L. Paktor
+ * Recognize aliased string, comment and user-message delimiters
+ * in a segment that is being ignored; Conditional Operators
+ * within the text body of any of these are always consumed
+ * and never unintentionally processed. Macros are always
+ * processed; Conditional Operators inside a Macro body are
+ * recognized, so the Macro continues to function as intended.
+ *
+ **************************************************************************** */
+
+static void conditionally_tokenize( bool cond, bool alr_ign )
+{
+
+ signed long wlen;
+
+ /* Note: The following variables *must* remain within
+ * the scope of this routine; a distinct instance
+ * is needed each time this routine is re-entered
+ * (aka "a nested call").
+ */
+ bool ignoring;
+ bool first_else = TRUE; /* The "else" we see is the first. */
+ bool not_done = TRUE;
+ unsigned int cond_strt_lineno = lineno;
+ char *cond_strt_ifile_nam = strdup( iname);
+
+ ignoring = BOOLVAL( ( cond == FALSE ) || ( alr_ign != FALSE ) );
+
+ if ( trace_conditionals )
+ {
+ char *cond_val = cond ? "True" : "False" ;
+ char *cond_junct = alr_ign ? ", but Already " : "; ";
+ char *processg = ignoring ? "Ignoring" : "Processing" ;
+ tokenization_error( INFO,
+ "Tokenization-Condition is %s%s%s.\n",
+ cond_val, cond_junct, processg);
+ }
+
+ while ( not_done )
+ {
+ wlen = get_word();
+ if ( wlen == 0 )
+ {
+ continue;
+ }
+
+ if ( wlen < 0 )
+ {
+ tokenization_error( TKERROR,
+ "Conditional without conclusion; started");
+ just_where_started( cond_strt_ifile_nam, cond_strt_lineno);
+ not_done = FALSE ;
+ continue;
+ }
+
+ if ( is_a_then ( statbuf ) )
+ {
+ if ( trace_conditionals )
+ {
+ tokenization_error( INFO,
+ "Concluding Conditional");
+ just_started_at( cond_strt_ifile_nam, cond_strt_lineno);
+ }
+ not_done = FALSE ;
+ continue;
+ }
+
+ if ( is_an_else( statbuf ) )
+ {
+ if ( ! alr_ign )
+ {
+ if ( first_else )
+ {
+ ignoring = INVERSE( ignoring);
+ }
+ }
+
+ if ( ! first_else )
+ {
+ int severity = ignoring ? WARNING : TKERROR ;
+ char *the_scop = ignoring ? "(ignored)" : "the" ;
+ tokenization_error( severity, "Multiple %s directives "
+ "within %s scope of the Conditional",
+ strupr(statbuf), the_scop);
+ just_started_at( cond_strt_ifile_nam, cond_strt_lineno);
+ }else{
+ first_else = FALSE;
+ if ( trace_conditionals )
+ {
+ char *when_enc = alr_ign ? "While already" : "Now" ;
+ char *processg = alr_ign ? "ignoring" :
+ ignoring ? "Ignoring" : "Processing" ;
+ char *enc = alr_ign ? ", e" : ". E" ;
+
+ tokenization_error( INFO,
+ "%s %s%sncountered %s belonging to Conditional",
+ when_enc, processg, enc, strupr(statbuf) );
+ just_started_at( cond_strt_ifile_nam, cond_strt_lineno);
+ }
+ }
+
+ continue;
+ }
+
+ /* If we are ignoring source input, for whatever reason, we still
+ * need to be sensitive to the nesting of Conditional Operators
+ * and some other commands and directives, as indicated...
+ */
+ if ( ignoring )
+ {
+ ignore_one_word( statbuf );
+ }else{
+ /* And if we're not ignoring source input, process it! */
+ tokenize_one_word ( wlen );
+ }
+ }
+}
+
+/* **************************************************************************
+ *
+ * We will now define a series of fairly simple functions that
+ * will be performed by the various Conditional Operators in
+ * the "Conditionals Vocabulary".
+ *
+ * Each one takes, as an argument, the "parameter field" pointer,
+ * which, in all cases, points to the local already_ignoring
+ * flag, passed as an int to satisfy C's strong-typing. The
+ * routine will internally recast it as a bool .
+ *
+ * If it is TRUE, the routine will bypass the test for its particular
+ * type of condition, and go directly to conditionally_tokenize
+ * In most cases, testing for the condition would be harmless,
+ * but in the case where the test is for an item on the stack,
+ * it would be harmful because the sequence that put the item
+ * on the stack was also being ignored...
+ *
+ * We'll give these functions short prologs. Synonyms will simply
+ * have separate entries in the Vocabulary Table, associated
+ * with the same function.
+ *
+ **************************************************************************** */
+
+/* **************************************************************************
+ *
+ * But first, a support routine...
+ *
+ **************************************************************************** */
+
+/* **************************************************************************
+ *
+ * Function name: conditional_word_in_line
+ * Synopsis: Common code for the types of conditionals that
+ * require a word on the same line.
+ *
+ * Inputs:
+ * Parameters:
+ * alr_ign TRUE if we are already ignoring
+ * exist_test TRUE if the test is for "existence" of the word
+ * exist_funct Name of the function to call for the test
+ * Global Variables:
+ * stat_word Word for which to test
+ *
+ * Outputs:
+ * Returned Value: NONE
+ *
+ * Error Detection:
+ * The word in question must appear on the same line as the directive;
+ * the call to get_word_in_line() checks for that and reports.
+ * If the word did not appear on the same line, then the directive
+ * will be disregarded and processing will proceed as though it
+ * were absent. This may lead to a cascade of errors...
+ *
+ * Process Explanation:
+ * The supplied exist_funct() will test for the existence of
+ * the word, now read into statbuf , in the appropriate
+ * venue.
+ * We only call the exist_funct() if we are not already ignoring.
+ *
+ **************************************************************************** */
+
+static void conditional_word_in_line( bool alr_ign,
+ bool exist_test,
+ bool (*exist_funct)() )
+{
+ if ( get_word_in_line( statbuf) )
+ {
+ bool cond = FALSE;
+ if ( INVERSE( alr_ign) )
+ {
+ bool exists = exist_funct( statbuf);
+ cond = BOOLVAL( exists == exist_test);
+ }
+ conditionally_tokenize( cond, alr_ign );
+ }
+}
+
+
+/* **************************************************************************
+ *
+ * Function name: if_exists
+ * Synopsis: Test for existence of a given word, in the dictionary.
+ *
+ * Associated Tokenizer directives: [ifexist]
+ * #ifexist
+ * [#ifexist]
+ * [ifexists]
+ * #ifexists
+ * [#ifexists]
+ * (Note variants with and without final 's'
+ *
+ **************************************************************************** */
+
+static void if_exists( tic_param_t pfield )
+{
+ bool alr_ign = *pfield.bool_ptr;
+ conditional_word_in_line( alr_ign, TRUE, exists_in_current );
+}
+
+/* **************************************************************************
+ *
+ * Function name: if_not_exist
+ * Synopsis: Test for Non-existence, in the appropriate dictionary,)
+ * of the given word.
+ *
+ * Associated Tokenizer directives: [ifnexist]
+ * #ifnexist
+ * [#ifnexist]
+ * (Note: Variants with final 's' didn't make sense here.)
+ *
+ * Explanatory Notes:
+ * This is the exact inverse of if_exists
+ *
+ **************************************************************************** */
+
+static void if_not_exist( tic_bool_param_t pfield )
+{
+ bool alr_ign = *pfield.bool_ptr;
+ conditional_word_in_line( alr_ign, FALSE, exists_in_current );
+}
+
+/* **************************************************************************
+ *
+ * Function name: if_defined
+ * Synopsis: Test for existence of a user-defined symbol
+ *
+ * Associated Tokenizer directives: [ifdef]
+ * #ifdef
+ * [#ifdef]
+ *
+ **************************************************************************** */
+
+static void if_defined( tic_bool_param_t pfield )
+{
+ bool alr_ign = *pfield.bool_ptr;
+ conditional_word_in_line( alr_ign, TRUE, exists_as_user_symbol );
+}
+
+/* **************************************************************************
+ *
+ * Function name: if_not_defined
+ * Synopsis: Test for NON-existence of a user-defined symbol
+ *
+ * Associated Tokenizer directives: [ifndef]
+ * #ifndef
+ * [#ifndef]
+ *
+ **************************************************************************** */
+
+static void if_not_defined( tic_bool_param_t pfield )
+{
+ bool alr_ign = *pfield.bool_ptr;
+ conditional_word_in_line( alr_ign, FALSE, exists_as_user_symbol );
+}
+
+
+/* **************************************************************************
+ *
+ * Function name: if_from_stack
+ * Synopsis: Test the number on top of the run-time stack
+ *
+ * Associated Tokenizer directive: [if]
+ *
+ * Process Explanation:
+ * When we are ignoring source input, and we still need to be
+ * sensitive to the nesting of Conditional Operators, we
+ * will not consume the number on the stack; this function
+ * is after all, being ignored and should not perform any
+ * action other than making sure the [else]s and [then]s
+ * get properly counted.
+ *
+ **************************************************************************** */
+
+static void if_from_stack( tic_bool_param_t pfield )
+{
+ bool alr_ign = *pfield.bool_ptr;
+ bool cond = FALSE;
+
+ if ( ! alr_ign )
+ {
+ long num = dpop();
+ if (num != 0)
+ {
+ cond = TRUE;
+ }
+ }
+ conditionally_tokenize( cond, alr_ign );
+}
+
+/* For future functions, use conditl.BlankTemplate.c */
+
+/* **************************************************************************
+ *
+ * Here, at long last, we define and initialize the structure containing
+ * all the functions we support for Conditional Operators.
+ *
+ **************************************************************************** */
+
+#define ADD_CONDL(str, func ) BUILTIN_BOOL_TIC(str, func, already_ignoring )
+
+static tic_bool_hdr_t conditionals_vocab_tbl[] = {
+ ADD_CONDL ("[ifexist]" , if_exists ) ,
+ ADD_CONDL ("[ifexists]" , if_exists ) ,
+ ADD_CONDL ("#ifexist" , if_exists ) ,
+ ADD_CONDL ("#ifexists" , if_exists ) ,
+ ADD_CONDL ("[#ifexist]" , if_exists ) ,
+ ADD_CONDL ("[#ifexists]" , if_exists ) ,
+ ADD_CONDL ("[ifnexist]" , if_not_exist ) ,
+ ADD_CONDL ("#ifnexist" , if_not_exist ) ,
+ ADD_CONDL ("[#ifnexist]" , if_not_exist ) ,
+ ADD_CONDL ("[ifdef]" , if_defined ) ,
+ ADD_CONDL ("#ifdef" , if_defined ) ,
+ ADD_CONDL ("[#ifdef]" , if_defined ) ,
+ ADD_CONDL ("[ifndef]" , if_not_defined ) ,
+ ADD_CONDL ("#ifndef" , if_not_defined ) ,
+ ADD_CONDL ("[#ifndef]" , if_not_defined ) ,
+ ADD_CONDL ("[if]" , if_from_stack )
+};
+
+
+/* **************************************************************************
+ *
+ * Function name: init_conditionals_vocab
+ * Synopsis: Initialize the "Conditionals Vocabulary Table"
+ * link-pointers dynamically, and link it in
+ * with the given ("Global") Vocabulary pointer.
+ *
+ **************************************************************************** */
+
+void init_conditionals_vocab( tic_hdr_t **tic_vocab_ptr )
+{
+ static const int conditionals_vocab_max_indx =
+ sizeof(conditionals_vocab_tbl)/sizeof(tic_bool_hdr_t);
+
+ init_tic_vocab( (tic_hdr_t *)conditionals_vocab_tbl,
+ conditionals_vocab_max_indx,
+ tic_vocab_ptr );
+}
+
Added: fcode-utils/toke/conditl.h
===================================================================
--- fcode-utils/toke/conditl.h (rev 0)
+++ fcode-utils/toke/conditl.h 2006-08-18 12:47:12 UTC (rev 76)
@@ -0,0 +1,46 @@
+#ifndef _TOKE_CONDITL_H
+#define _TOKE_CONDITL_H
+
+/*
+ * OpenBIOS - free your system!
+ * ( FCode tokenizer )
+ *
+ * This program is part of a free implementation of the IEEE 1275-1994
+ * Standard for Boot (Initialization Configuration) Firmware.
+ *
+ * Copyright (C) 2001-2005 Stefan Reinauer, <stepan(a)openbios.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA, 02110-1301 USA
+ *
+ */
+
+/* **************************************************************************
+ *
+ * Function Prototypes for Conditional-Compilation support for Tokenizer
+ *
+ * (C) Copyright 2005 IBM Corporation. All Rights Reserved.
+ * Module Author: David L. Paktor dlpaktor(a)us.ibm.com
+ *
+ **************************************************************************** */
+
+#include "types.h"
+#include "ticvocab.h"
+
+void init_conditionals_vocab( tic_hdr_t **tic_vocab_ptr );
+
+void skip_a_word( tic_bool_param_t pfield );
+void skip_a_word_in_line( tic_bool_param_t pfield );
+void skip_two_words_in_line( tic_bool_param_t pfield );
+
+#endif /* _TOKE_CONDITL_H */
Added: fcode-utils/toke/devnode.c
===================================================================
--- fcode-utils/toke/devnode.c (rev 0)
+++ fcode-utils/toke/devnode.c 2006-08-18 12:47:12 UTC (rev 76)
@@ -0,0 +1,595 @@
+/*
+ * OpenBIOS - free your system!
+ * ( FCode tokenizer )
+ *
+ * This program is part of a free implementation of the IEEE 1275-1994
+ * Standard for Boot (Initialization Configuration) Firmware.
+ *
+ * Copyright (C) 2001-2005 Stefan Reinauer, <stepan(a)openbios.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA, 02110-1301 USA
+ *
+ */
+
+/* **************************************************************************
+ *
+ * Support routines for managing device-node vocabularies
+ *
+ * (C) Copyright 2005 IBM Corporation. All Rights Reserved.
+ * Module Author: David L. Paktor dlpaktor(a)us.ibm.com
+ *
+ **************************************************************************** */
+
+/* **************************************************************************
+ *
+ * The vocabulary that is created for a device-node must not remain
+ * available outside of that node. Also, nodes may be nested,
+ * child within parent.
+ * An attempt within a child-node to access directly a method defined
+ * in the parent must be flagged as an error. (Consider what would
+ * happen if the method in the parent-node used instance data, and
+ * the child-node has an instance of its own.)
+ * The correct way is to invoke the method via "$call-parent" or the like.
+ *
+ * We will, however, allow the user to specify a group of exceptions,
+ * words whose scope will be "global" within the tokenization.
+ * When "global" scope is initiated, definitions will be made to
+ * the "core" vocabulary until "device" scope is resumed.
+ * That will (mostly) all be handled in dictionary.c
+ *
+ **************************************************************************** */
+
+
+/* **************************************************************************
+ *
+ * Functions Exported:
+ * new_device_vocab Create the new device-node's data-structure
+ * delete_device_vocab Remove device-node's data-structure
+ * finish_device_vocab Remove struct and give messages when
+ * device is "finish"ed.
+ * exists_in_ancestor Issue a Message if the given word exists
+ * in an ancestor of the current dev-node.
+ *
+ **************************************************************************** */
+
+/* **************************************************************************
+ *
+ * Still to be done:
+ * Add a pair of fields to the data-structure for the Input File and
+ * Line Number where "finish-device" occurred. When a device-node
+ * is "finish"ed, do not delete it, but instead fill in those
+ * fields and the move the node to a separate linked-list.
+ * When looking whether a word exists in an ancestor-node, also
+ * check whether it was in a device-node that was finished and
+ * print both where it was started and where it was finished.
+ *
+ **************************************************************************** */
+
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+
+#include "devnode.h"
+#include "errhandler.h"
+#include "scanner.h"
+#include "vocabfuncts.h"
+#include "flowcontrol.h"
+#include "stream.h"
+#include "ticvocab.h"
+
+
+/* **************************************************************************
+ *
+ * Tokenization starts with an implicit "new-device" in effect.
+ * The top-level device-node is never removed.
+ *
+ * Initialize it here
+ *
+ **************************************************************************** */
+char default_top_dev_ifile_name[] = "Start of tokenization";
+
+static device_node_t top_level_dev_node = {
+ NULL , /* parent_node */
+ default_top_dev_ifile_name , /* ifile_name.
+ * Something to show, Just In Case
+ */
+ 0 , /* line_no */
+ NULL , /* tokens_vocab */
+};
+
+/* **************************************************************************
+ *
+ * Global Variables Exported.
+ * Pointers to:
+ * current_device_node data-structure of current device-node
+ * current_definitions vocab into which to add def'ns.
+ *
+ **************************************************************************** */
+
+device_node_t *current_device_node = &top_level_dev_node;
+tic_hdr_t **current_definitions = &(top_level_dev_node.tokens_vocab);
+
+
+/* **************************************************************************
+ *
+ * Internal Static Variables
+ * These are used to support the routines in_what_node()
+ * and show_node_start() , which are used to facilitate
+ * certain kinds of Messaging, as described later.
+ *
+ * in_what_buffr Buffer for the in_what_node() string
+ * show_where TRUE if the string needs to be followed-up
+ * show_which TRUE if follow-up should be just_where_started()
+ * rather than just_started_at()
+ * in_what_line Line Number to use in the follow-up
+ * in_what_file File Name to use in the follow-up
+ *
+ **************************************************************************** */
+
+static char in_what_buffr[50]; /* Ought to be more than enough. */
+static bool show_where = FALSE;
+static bool show_which;
+static int in_what_line;
+static char *in_what_file;
+
+
+/* **************************************************************************
+ *
+ * Function name: dev_vocab_control_struct_check
+ * Synopsis: Issue Warnings for unresolved flow-control constructs
+ * at start or end of a device-node.
+ *
+ * Inputs:
+ * Parameters: NONE
+ * Global Variables:
+ * statbuf The command being processed.
+ *
+ * Outputs:
+ * Returned Value: NONE
+ * Printout:
+ * Handled by announce_control_structs() routine
+ *
+ * Error Detection:
+ * Handled by announce_control_structs() routine
+ *
+ * Process Explanation:
+ * Set up a buffer with the error message, based on statbuf
+ * and pass it to announce_control_structs()
+ * Release it when done.
+ *
+ **************************************************************************** */
+
+static void dev_vocab_control_struct_check( void)
+{
+ char *ccs_messg;
+
+ ccs_messg = safe_malloc(strlen(statbuf) + 32,
+ "Device-Node control-structure check");
+
+ strcpy( ccs_messg, statbuf );
+ strupr( ccs_messg);
+ strcat( ccs_messg, " encountered");
+ announce_control_structs( WARNING, ccs_messg, 0 );
+ free( ccs_messg);
+}
+
+
+
+/* **************************************************************************
+ *
+ * Function name: new_device_vocab
+ * Synopsis: Create and initialize the data-structure for a
+ * new device-node when a "new-device" is created,
+ * with messages as appropriate.
+ *
+ * Inputs:
+ * Parameters: NONE
+ * Global Variables:
+ * statbuf The word that was just read.
+ * iname Current Input-File Name
+ * lineno Current line-number
+ *
+ * Outputs:
+ * Returned Value: NONE
+ * Global Variables:
+ * current_device_node Will point to the new data-structure
+ * Memory Allocated
+ * Space for the new device_node_t data-structure
+ * Space for a copy of the current input file name
+ * When Freed?
+ * By delete_device_vocab(), when the device-node is "finish"ed.
+ * Printout:
+ * Advisory message.
+ *
+ * Error Detection:
+ * In immediate-execution mode, Control Structures that have not
+ * been completed are questionable; Issue WARNINGS via the
+ * dev_vocab_control_struct_check() routine.
+ *
+ * Process Explanation:
+ * This routine is called when "new-device" is invoked, but only
+ * if we are in immediate-execution mode.
+ * Later on, in ERROR- or INFOrmative messages, we will want to
+ * be able to refer to the file and line-number in which this
+ * was encountered, so we include them in the structure.
+ *
+ **************************************************************************** */
+
+void new_device_vocab( void )
+{
+ device_node_t *new_node_data;
+
+ dev_vocab_control_struct_check();
+
+ /* Advisory message will mention previous device-node
+ * if there was one. Either way starts out the same:
+ */
+#define NEW_DEV_MSG_START "Encountered %s. Starting new device-node."
+
+ if ( current_device_node == &top_level_dev_node )
+ {
+ tokenization_error(INFO, NEW_DEV_MSG_START "\n", statbuf );
+ }else{
+ tokenization_error(INFO, NEW_DEV_MSG_START
+ " Suspending definitions of parent-device node", statbuf );
+ started_at( current_device_node->ifile_name,
+ current_device_node->line_no );
+ }
+
+ /* Now to business... */
+ new_node_data = safe_malloc( sizeof(device_node_t),
+ "creating new-device vocab data" );
+ new_node_data->parent_node = current_device_node;
+ new_node_data->ifile_name = strdup(iname);
+ new_node_data->line_no = lineno;
+ new_node_data->tokens_vocab = NULL;
+
+ current_device_node = new_node_data;
+
+ current_definitions = &(current_device_node->tokens_vocab);
+}
+
+
+/* **************************************************************************
+ *
+ * Function name: delete_device_vocab
+ * Synopsis: Remove the vocabularies of the current device-node,
+ * along with its data-structure, when the device
+ * is "finish"ed; do not print messages.
+ * Do not remove the top-level device-node data-struct.
+ *
+ * Associated FORTH words: FINISH_DEVICE (interpretive state)
+ * END0 END1
+ * Associated Tokenizer directives: RESET-SYMBOLS (in "Normal" mode)
+ * FCODE-END
+ *
+ * Inputs:
+ * Parameters: NONE
+ * Global Variables:
+ * current_device_node Points to current device's struct
+ * Leads to chain of dev-node structs
+ *
+ * Outputs:
+ * Returned Value:
+ * Global Variables:
+ * current_device_node Parent-device's struct becomes current
+ * Memory Freed
+ * All that was allocated for the tokens and the definers
+ * vocabs in the current device-node
+ * The copy of the input file name, except the top-level
+ * The current_device_node data-structure, except the top-level
+ *
+ **************************************************************************** */
+
+void delete_device_vocab( void )
+{
+ reset_tic_vocab( current_definitions, NULL );
+
+ if ( current_device_node != &top_level_dev_node )
+ {
+ device_node_t *temp_node = current_device_node;
+ current_device_node = current_device_node->parent_node;
+ free( temp_node->ifile_name );
+ free(temp_node);
+ }
+
+ current_definitions = &(current_device_node->tokens_vocab);
+}
+
+/* **************************************************************************
+ *
+ * Function name: finish_device_vocab
+ * Synopsis: Remove the device-node data-structure and all its
+ * vocabularies when the device is "finish"ed,
+ * with appropriate messages.
+ * Do not remove the top-level device node data-struct.
+ *
+ * Associated FORTH word: FINISH_DEVICE
+ *
+ * Inputs:
+ * Parameters: NONE
+ * Global Variables:
+ * current_device_node Current device's struct pointer
+ *
+ * Outputs:
+ * Returned Value: NONE
+ * Global Variables:
+ * current_device_node Parent-device's struct becomes current
+ * Printout:
+ * Advisory message.
+ *
+ * Error Detection:
+ * If current_device_node is already pointing at the top-level
+ * device node, it means there was no corresponding NEW-DEVICE
+ * Issue an ERROR.
+ * In immediate-execution mode, Control Structures that have not
+ * been completed are questionable; Issue WARNINGS via the
+ * dev_vocab_control_struct_check() routine.
+ *
+ * Process Explanation:
+ * This routine is called when "finish-device" is invoked, but only
+ * if we are in immediate-execution mode.
+ *
+ **************************************************************************** */
+
+void finish_device_vocab( void )
+{
+ bool at_top_level;
+
+ dev_vocab_control_struct_check();
+
+ /* We never remove the top-level device-node vocabulary,
+ * so we need to test whether we're about to.
+ */
+
+ at_top_level = BOOLVAL( current_device_node == &top_level_dev_node );
+ if ( at_top_level )
+ {
+ tokenization_error( TKERROR,
+ "Encountered %s without corresponding NEW-DEVICE. "
+ "Resetting definitions since start of tokenization.\n",
+ statbuf );
+ }else{
+ tokenization_error(INFO,
+ "Encountered %s. Resetting definitions of device node",
+ statbuf );
+ started_at( current_device_node->ifile_name,
+ current_device_node->line_no );
+ }
+
+ /* Now to business... */
+ delete_device_vocab();
+
+ /* Did we just get to the top-level device-node vocabulary
+ * when we weren't before?
+ */
+ if ( INVERSE(at_top_level) )
+ {
+ if ( current_device_node == &top_level_dev_node )
+ {
+ tokenization_error(INFO,
+ "Resuming definitions since start of tokenization.\n" );
+ }else{
+ tokenization_error(INFO,
+ "Resuming definitions of parent device-node" );
+ started_at( current_device_node->ifile_name,
+ current_device_node->line_no );
+ }
+ }
+}
+
+
+/* **************************************************************************
+ *
+ * Function name: in_what_node
+ * Synopsis: Format a string for use in a Message that might
+ * identify the start of the given device-node.
+ *
+ * Inputs:
+ * Parameters:
+ * the_node The device-node vocabulary about which
+ * to construct the identifying phrase.
+ * Local Static Variables:
+ * in_what_buffr Buffer in which to format the string.
+ * Global Variables:
+ * current_definitions Device-node vocabulary currently
+ * in effect.
+ *
+ * Outputs:
+ * Returned Value: Pointer to buffer w/ formatted string
+ * Local Static Variables:
+ * in_what_buffr Will contain the formatted string.
+ * show_where TRUE if the string needs to be followed-up
+ * (i.e., did not contain a terminating
+ * new-line) by just_where_started()
+ * or by just_started_at()
+ * show_which TRUE if the follow-up call should be
+ * to just_where_started() rather
+ * than to just_started_at()
+ * in_what_line Copy of line_no field from the_node
+ * in_what_file Copy of ifile_name field from the_node
+ *
+ * Process Explanation:
+ * Calling routine must ascertain that Global-scope is not in effect.
+ * The returned phrase can be used as a string argument in a Message.
+ * Set show_where TRUE if the_node->line_no is non-zero.
+ * Set show_which TRUE if the_node is either the Current or the
+ * Top-Level device-node
+ * If the originating line-number in the given Node structure is zero,
+ * the returned phrase will contain a terminating new-line.
+ * (This only happens if the given Node is the top-level Node,
+ * and it's the Current Node, and the "official" starting-point
+ * hasn't yet been established by an "FCode-Starter" such as
+ * FCODE-VERSION2 . Once that command has been given, even
+ * definitions that were made prior to it belong to the Node
+ * that started there.)
+ * Otherwise, show_where is returned TRUE, and show_which becomes
+ * relevant. If the given node is the Current or the Top-Level
+ * node, text about the originating file-name and line-number
+ * merely describes a node that is already uniquely identified,
+ * so the message appended to the buffer will have the phrase
+ * "which began" (which introduces what is known in grammar as
+ * an Appositive Subordinate Clause) and show_which will be
+ * returned TRUE. If the given node is not uniquely identifiable
+ * without the file- and line- phrase, then the Subordinate Clause
+ * is Indicative, and should be introduced with "that" (and no
+ * comma); in that case, we will return show_which as FALSE.
+ * After the calling routine displays the message in which the
+ * returned phrase is used, it must call show_node_start()
+ * to display the followe-up message, if any.
+ *
+ **************************************************************************** */
+
+char *in_what_node(device_node_t *the_node)
+{
+ bool top_node = BOOLVAL( the_node == &top_level_dev_node);
+ bool curr_node = BOOLVAL( the_node == current_device_node);
+ bool known_node = BOOLVAL( top_node || curr_node );
+ bool no_line = BOOLVAL( the_node->line_no == 0);
+
+ show_where = INVERSE( no_line );
+ show_which = known_node;
+ in_what_line = the_node->line_no;
+ in_what_file = the_node->ifile_name;
+
+ sprintf( in_what_buffr, "in the%s device-node%s",
+ INVERSE( known_node ) ? ""
+ : top_node ? " top-level" : " current" ,
+
+ no_line ? ".\n"
+ : known_node ? ", which began" : "" );
+
+
+ return( in_what_buffr);
+}
+
+
+/* **************************************************************************
+ *
+ * Function name: show_node_start
+ * Synopsis: Follow-up to the in_what_node() call. Print out,
+ * if applicable, the text about the originating
+ * file-name and line-number
+ *
+ * Inputs:
+ * Parameters: NONE
+ * Local Static Variables:
+ * show_where Nothing to do if not TRUE
+ * show_which TRUE if should call just_where_started()
+ * rather than just_started_at()
+ * in_what_line Line Number to use in the follow-up
+ * in_what_file File Name to use in the follow-up
+ *
+ * Outputs:
+ * Returned Value: NONE
+ * Local Static Variables:
+ * show_where Force to FALSE
+ * Printout:
+ * Follow-up to the in_what_node() call. Applicable text
+ * about the originating file-name and line-number.
+ *
+ * Process Explanation:
+ * By forcing show_where to FALSE after this is called, we
+ * can safely allow routines that might or might not have
+ * called in_what_node() to call this routine, without
+ * needing any additional "bookkeeping".
+ *
+ **************************************************************************** */
+
+void show_node_start( void)
+{
+ if ( show_where)
+ {
+ if ( show_which )
+ {
+ just_where_started( in_what_file, in_what_line);
+ }else{
+ just_started_at( in_what_file, in_what_line);
+ }
+ show_where = FALSE;
+ }
+}
+
+
+
+/* **************************************************************************
+ *
+ * Function name: exists_in_ancestor
+ * Synopsis: Issue a Message and return an indication if
+ * the given word exists in an ancestor of
+ * the current device-node.
+ * Used for additional error-message information.
+ *
+ *
+ * Inputs:
+ * Parameters:
+ * m_name "Method" name
+ * Global Variables:
+ * current_device_node Leads to chain of dev-node data-structs
+ * scope_is_global TRUE if "global" scope is in effect
+ *
+ * Outputs:
+ * Returned Value: TRUE if word found
+ * Printout:
+ * If m_name exists in an ancestor-node, print an ADVISORY
+ * giving the location where the ancestor originated.
+ *
+ * Error Detection:
+ * None here. Calling routine detected error; see below.
+ *
+ * Process Explanation:
+ * This routine was called as the result of detecting an error:
+ * viz., m_name was not found in either the current node
+ * or the base vocabulary. (Except: If "global" scope is
+ * in effect, we didn't search the current device-node).
+ *
+ **************************************************************************** */
+
+bool exists_in_ancestor( char *m_name)
+{
+ tic_hdr_t *found;
+ bool retval = FALSE;
+ if ( current_device_node != NULL )
+ {
+ device_node_t *grandpa = current_device_node->parent_node;
+
+ if ( scope_is_global ) grandpa = current_device_node;
+
+ for ( ; grandpa != NULL; grandpa = grandpa->parent_node )
+ {
+ found = lookup_tic_entry( m_name, grandpa->tokens_vocab);
+ if ( found != NULL )
+ {
+ retval = TRUE;
+ break;
+ }
+ }
+ if ( grandpa != NULL )
+ {
+ char as_what_buf[32] = "";
+ if ( as_a_what( found->fword_defr, as_what_buf) )
+ {
+ strcat( as_what_buf, " ");
+ }
+ tokenization_error(INFO, "%s is defined %s%s", m_name,
+ as_what_buf, in_what_node( grandpa) );
+ show_node_start();
+ }
+ }
+
+ return(retval );
+}
Added: fcode-utils/toke/devnode.h
===================================================================
--- fcode-utils/toke/devnode.h (rev 0)
+++ fcode-utils/toke/devnode.h 2006-08-18 12:47:12 UTC (rev 76)
@@ -0,0 +1,86 @@
+#ifndef _TOKE_DEVNODE_H
+#define _TOKE_DEVNODE_H
+
+/*
+ * OpenBIOS - free your system!
+ * ( FCode tokenizer )
+ *
+ * This program is part of a free implementation of the IEEE 1275-1994
+ * Standard for Boot (Initialization Configuration) Firmware.
+ *
+ * Copyright (C) 2001-2005 Stefan Reinauer, <stepan(a)openbios.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA, 02110-1301 USA
+ *
+ */
+
+/* **************************************************************************
+ *
+ * External/Prototype/Structure definitions for device-node management
+ *
+ * (C) Copyright 2005 IBM Corporation. All Rights Reserved.
+ * Module Author: David L. Paktor dlpaktor(a)us.ibm.com
+ *
+ **************************************************************************** */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "types.h"
+#include "ticvocab.h"
+
+/* **************************************************************************
+ * Structure Name: device_node_t
+ * Data for managing a device node; pointers
+ * to vocabs, data for messaging.
+ *
+ * Fields:
+ * parent_node Pointer to similar data for parent node
+ * line_no Copy of Line Number where "new-device" was invoked
+ * ifile_name Name of Input File where "new-device" was invoked
+ * tokens_vocab Pointer to vocab for this device's tokens
+ *
+ **************************************************************************** */
+
+typedef struct device_node {
+ struct device_node *parent_node ;
+ char *ifile_name ;
+ unsigned int line_no ;
+ tic_hdr_t *tokens_vocab ;
+} device_node_t;
+
+
+/* ************************************************************************** *
+ *
+ * Global Variables Exported
+ *
+ **************************************************************************** */
+
+extern char default_top_dev_ifile_name[];
+extern device_node_t *current_device_node;
+extern tic_hdr_t **current_definitions;
+
+/* ************************************************************************** *
+ *
+ * Function Prototypes / Functions Exported:
+ *
+ **************************************************************************** */
+void new_device_vocab( void );
+void delete_device_vocab( void );
+void finish_device_vocab( void );
+char *in_what_node(device_node_t *the_node);
+void show_node_start( void);
+bool exists_in_ancestor( char *m_name);
+
+#endif /* _TOKE_DEVNODE_H */
Modified: fcode-utils/toke/dictionary.c
===================================================================
--- fcode-utils/toke/dictionary.c 2006-08-18 09:45:11 UTC (rev 75)
+++ fcode-utils/toke/dictionary.c 2006-08-18 12:47:12 UTC (rev 76)
@@ -24,6 +24,12 @@
*
*/
+/* **************************************************************************
+ * Modifications made in 2005 by IBM Corporation
+ * (C) Copyright 2005 IBM Corporation. All Rights Reserved.
+ * Modifications Author: David L. Paktor dlpaktor(a)us.ibm.com
+ **************************************************************************** */
+
#include <stdio.h>
#include <stdlib.h>
#if defined(__linux__) && ! defined(__USE_BSD)
@@ -32,543 +38,2008 @@
#include <string.h>
#include <errno.h>
-#include "toke.h"
+#include "emit.h"
+#include "macros.h"
+#include "scanner.h"
+#include "ticvocab.h"
#include "dictionary.h"
+#include "vocabfuncts.h"
+#include "devnode.h"
+#include "clflags.h"
+#include "parselocals.h"
+#include "errhandler.h"
+#include "tokzesc.h"
+#include "conditl.h"
-typedef struct token {
- u8 *name;
- u16 fcode;
- struct token *next;
-} token_t;
+/* **************************************************************************
+ *
+ * Revision History:
+ * Updated Fri, 29 Jul 2005 by David L. Paktor
+ * Retrofit to handle "Current Device" as a separate vocabulary;
+ * if one is in effect, searches through it occur first, as
+ * do definitions to it, ahead of the general vocabulary. This
+ * is to support managing device-node vocabularies correctly.
+ * Updated Mon, 12 Dec 2005 by David L. Paktor
+ * Allow the user to specify a group of exceptions, words whose
+ * scope will be "global" within the tokenization. Under "global"
+ * scope, definitions will be made to the "core" vocabulary.
+ *
+ * Wed, 14 Dec 2005 by David L. Paktor
+ * Found a problem with the current approach. Need to be able to
+ * temporarily suspend meaning of "instance". Define: (1) an
+ * alias for INSTANCE called GENERIC_INSTANCE (2) a macro
+ * called INSTANCE that effectively no-ops it out; and, when
+ * it is time to restore "INSTANCE" to normal functionality,
+ * (3) an alias for GENERIC_INSTANCE called INSTANCE .
+ * Problem is that macros are treated as a separate vocabulary
+ * from FWords (and their aliases) and searching one before the
+ * other (either way) renders the second one searched unable to
+ * supercede the first one: If macros are searched first, (2)
+ * will be found ahead of the built-in FWord (which is what we
+ * want) but later, when we search for (3) among the FWords, it
+ * will not be found ahead of (2). If, on the other hand, we
+ * search FWords first, the macro defined in (2) will never be
+ * found.
+ * We need a way to define both (all?) types of definitions in a
+ * single vocabulary that will honor the LIFO order of def'ns.
+ *
+ * Mon, 19 Dec 2005 by David L. Paktor
+ * Begin development of implementation of a way to define both (all?)
+ * types of definitions in a single tic_hdr_t type vocabulary.
+ *
+ **************************************************************************** */
-static token_t *dictionary=NULL;
-static token_t *forthwords=NULL;
-static u16 lookup_token_dict(char *name, token_t *dict)
+
+/* **************************************************************************
+ *
+ * We will be creating several different lists of initial built-in
+ * definitions; together, they constitute the Global Vocabulary.
+ * (We will avoid the term "dictionary", since, in classical
+ * Forth terminology, it refers to the complete collection of
+ * vocabularies in an application.) The usage of the pointer
+ * to the Global Vocabulary is central to the operation of this
+ * program and the maintenance programmer needs to understand it.
+ * We may also refer to the Global Vocabulary as the "core" vocab.
+ *
+ * Each initial list will be created as an array of TIC-header entries.
+ * Because the global vocabulary is expandable by the user,
+ * we will not be searching the lists as arrays but rather as
+ * linked-lists; the run-time initialization routine will fill
+ * in their link-fields and also will link the various lists
+ * together, so we can group their initial declarations according
+ * to our convenience.
+ *
+ * A single pointer, called the "Global Vocabulary Dictionary Pointer"
+ * (okay, so classical Forth terminology isn't completely rigorous...)
+ * and abbreviated GV_DP, will point to the "tail" of the "thread".
+ * Similar vocabularies will be created for the device-nodes; look
+ * in the file devnode.fth for a more detailed discussion of those.
+ *
+ * The "FC-Tokens" list contains the names and FCode numeric tokens
+ * of the straightforward FORTH words that simply write a token
+ * directly to the tokenized output. We need to access these
+ * without being confused by aliases or other distractions, so
+ * we will keep a pointer to them especially for that purpose.
+ * Therefore it is IMPORTANT: that the "FC-Tokens" list MUST be the
+ * first table linked by the initialization routine, so that its
+ * last-searched entry's link-field is NULL.
+ *
+ * The "FWords" list contains FORTH words that require additional
+ * special action at tokenization-time. Their numeric values
+ * are derived from the fword_token enumeration declaration,
+ * and are used as the control-expression for a SWITCH statement
+ * with a large number of CASE labels in the handle_internal()
+ * function.
+ *
+ * The "Shared Words" list contains FORTH words that can be executed
+ * similarly both during "Tokenizer Escape" mode (i.e., the scope
+ * of the special brackets: tokenizer[ ... ]tokenizer ) and
+ * also within "Normal Tokenization" mode. Their numeric values
+ * are derived and used the same way as the "FWords". Since we
+ * will be needing to do a separate search through them at times,
+ * we will also need a lower-bracket pointer for them. (An upper
+ * bracket is irrelevant for these, because aliases can be added.
+ * This is not the case for the "FC-Tokens" list, because searches
+ * through those will be conducted from within this program.)
+ *
+ * The "definer" field in the TIC-header structure is primarily used to
+ * detect attempts to apply the TO directive to an inappropriate
+ * target. Its numeric values are a subset of the "FWord tokens".
+ * Certain "FC-Token" names are specified to be valid TO targets;
+ * their entries' "definer" fields will be initialized accordingly.
+ * Entries in FWord Token lists that are "shared" between "Normal
+ * Tokenization" and "Tokenizer Escape" modes will have their
+ * "definer" fields initialized to COMMON_FWORD . All other
+ * entries' "definer" fields will be initialized to UNSPECIFIED .
+ *
+ * Other files maintain and support additional lists with the same
+ * structure, which need to be linked together with the lists
+ * declared here. We prefer to keep the GV_DP private to this
+ * file, so it will be passed as a parameter where needed. (I'm
+ * not pleased to note, however, that it can't be kept completely
+ * private; it's needed for add_user_macro() and possibly other
+ * functions outside this file.)
+ *
+ * The words that can only be used during "Tokenizer Escape" mode and
+ * the IBM-style "Locals", as well as the device-node vocabularies,
+ * will need to be separate and will not be linked together with
+ * the Global Vocabulary.
+ *
+ **************************************************************************** */
+
+/* **************************************************************************
+ *
+ * We'll be initializing the lists later, but will be referencing
+ * the pointers sooner, so we need to declare the pointers here.
+ *
+ * We will keep all of these pointers private to this file.
+ *
+ **************************************************************************** */
+
+static tic_hdr_t *global_voc_dict_ptr = NULL; /* The Global Vocabulary */
+static tic_hdr_t *fc_tokens_list_ender = NULL; /* Tokens search ends here */
+static tic_hdr_t *fc_tokens_list_start = NULL; /* Start the search here */
+static tic_hdr_t *shared_fwords_ender = NULL; /* Shared FWords search end */
+static tic_hdr_t *global_voc_reset_ptr = NULL; /* Reset-point for G.V. */
+
+
+/* **************************************************************************
+ *
+ * Function name: lookup_core_word
+ * Synopsis: Return a pointer to the data-structure of the named
+ * word in the "Global" Vocabulary
+ *
+ * Inputs:
+ * Parameters:
+ * tname The name to look up
+ * Local Static Variables:
+ * global_voc_dict_ptr "Tail" of Global Vocabulary
+ *
+ * Outputs:
+ * Returned Value: Pointer to the data-structure, or
+ * NULL if not found.
+ *
+ **************************************************************************** */
+
+tic_hdr_t *lookup_core_word( char *tname)
{
- token_t *curr;
-
- for (curr=dict; curr!=NULL; curr=curr->next)
- if (!strcasecmp(name,(char *)curr->name))
- break;
+ tic_hdr_t *found ;
- if (curr)
- return curr->fcode;
-#ifdef DEBUG_TOKE
- printf("warning: token '%s' does not exist.\n", name);
-#endif
- return 0xffff;
+ found = lookup_tic_entry( tname, global_voc_dict_ptr);
+ return ( found ) ;
}
-u16 lookup_token(char *name)
+/* **************************************************************************
+ *
+ * Function name: exists_in_core
+ * Synopsis: Confirm whether the given name exists in the
+ * Global (aka "core") Vocabulary. Search the
+ * Global Vocabulary exclusively.
+ *
+ * Inputs:
+ * Parameters:
+ * name The name for which to look
+ * Local Static Variables:
+ * global_voc_dict_ptr "Tail" of Global Vocabulary
+ *
+ * Outputs:
+ * Returned Value: TRUE if name is found.
+ *
+ **************************************************************************** */
+
+bool exists_in_core( char *name)
{
- return lookup_token_dict(name, dictionary);
+ return exists_in_tic_vocab( name, global_voc_dict_ptr );
}
-u16 lookup_fword(char *name)
+/* **************************************************************************
+ *
+ * Function name: handle_core_word
+ * Synopsis: Perform a function in the "Global" Vocabulary and
+ * indicate whether the name is valid.
+ *
+ * Inputs:
+ * Parameters:
+ * tname The name to handle
+ * Local Static Variables:
+ * global_voc_dict_ptr "Tail" of Global Vocabulary
+ *
+ * Outputs:
+ * Returned Value: TRUE if the given name is valid in Global Vocab
+ *
+ * Error Detection:
+ * If the name is not in the "Global" Vocabulary, let the calling
+ * routine determine whether to print an error message or to
+ * try it out as a number.
+ *
+ **************************************************************************** */
+
+bool handle_core_word( char *tname )
{
- return lookup_token_dict(name, forthwords);
+ bool retval;
+
+ retval = handle_tic_vocab( tname, global_voc_dict_ptr );
+
+ return ( retval ) ;
}
-static int add_token_dict(u16 number, char *name, token_t **dict)
+
+/* **************************************************************************
+ *
+ * Function name: create_core_alias
+ * Synopsis: Create, in the "Global" ("core") Vocabulary, an entry
+ * for NEW_NAME that behaves the same as the latest
+ * definition of OLD_NAME, and whose behavior will
+ * not change even if a new definition of OLD_NAME
+ * is overlaid. Indicate if successful.
+ *
+ * Inputs:
+ * Parameters:
+ * new_name The name for the new alias to be created
+ * old_name The name of the old function to be duplicated
+ * Local Static Variables:
+ * global_voc_dict_ptr "Tail" of Global Vocabulary
+ *
+ * Outputs:
+ * Returned Value: TRUE if OLD_NAME was found.
+ * Local Static Variables:
+ * global_voc_dict_ptr Updated with the new entry
+ * Memory Allocated
+ * By support routine.
+ *
+ * Process Explanation:
+ * Both the "old" and "new" names are presumed to already point to
+ * stable, freshly allocated memory-spaces.
+ *
+ **************************************************************************** */
+
+bool create_core_alias( char *new_name, char *old_name)
{
- token_t *curr;
+ bool retval = create_tic_alias( new_name, old_name, &global_voc_dict_ptr);
+ return ( retval );
+}
- curr=malloc(sizeof(token_t));
- if(!curr) {
- printf("Out of memory while adding token.\n");
- exit(-ENOMEM);
+/* **************************************************************************
+ *
+ * The functions that go into the various lists' FUNCT field may be
+ * defined below, or might be defined externally.
+ *
+ * Often, we will need a function that merely recasts the type of the
+ * parameter field before passing it to the function that does
+ * the actual work.
+ *
+ * Prologs will be brief or even non-existent.
+ *
+ * Initialization macro definitions will accompany the functions.
+ *
+ **************************************************************************** */
+
+/* **************************************************************************
+ *
+ * For the "FCode-Tokens" list, simply generate the token directly.
+ * We need this layer for param type conversion.
+ * In case we're ever able to eliminate it, (or just on General
+ * Principles) we'll invoke it via a macro...
+ *
+ **************************************************************************** */
+
+static void emit_fc_token( tic_param_t pfield)
+{
+ u16 fc_tok = (u16)pfield.deflt_elem;
+ emit_fcode( fc_tok);
+}
+
+#define FC_TOKEN_FUNC emit_fc_token
+
+#define BUILTIN_FCODE( tok, nam) \
+ VALPARAM_TIC(nam, FC_TOKEN_FUNC, tok , UNSPECIFIED )
+
+/* Built-in FCodes with known definers: */
+#define BI_FCODE_VALUE( tok, nam) \
+ VALPARAM_TIC(nam, FC_TOKEN_FUNC, tok , VALUE )
+
+#define BI_FCODE_VRBLE( tok, nam) \
+ VALPARAM_TIC(nam, FC_TOKEN_FUNC, tok , VARIABLE )
+
+#define BI_FCODE_DEFER( tok, nam) \
+ VALPARAM_TIC(nam, FC_TOKEN_FUNC, tok , DEFER )
+
+#define BI_FCODE_CONST( tok, nam) \
+ VALPARAM_TIC(nam, FC_TOKEN_FUNC, tok , CONST )
+
+/* **************************************************************************
+ *
+ * The "FCode-Tokens" list includes tokens that are identified
+ * in the Standard as Obsolete. We will define a function
+ * that issues a WARNING before generating the token, and
+ * assign it to those elements of the list.
+ *
+ * Control the message via a command-line flag.
+ *
+ **************************************************************************** */
+
+static void obsolete_warning( void)
+{
+ if ( obso_fcode_warning )
+ {
+ tokenization_error( WARNING, "%s is an Obsolete FCode.\n",
+ strupr(statbuf) );
+ }
+}
+
+static void obsolete_fc_token( tic_param_t pfield)
+{
+ obsolete_warning();
+ emit_fc_token( pfield);
+}
+
+#define OBSO_FC_FUNC obsolete_fc_token
+
+#define OBSOLETE_FCODE( tok, nam) \
+ VALPARAM_TIC(nam, OBSO_FC_FUNC, tok , UNSPECIFIED )
+
+#define OBSOLETE_VALUE( tok, nam) \
+ VALPARAM_TIC(nam, OBSO_FC_FUNC, tok , VALUE )
+
+
+/* **************************************************************************
+ *
+ * The function for most of the "FWords" list, handle_internal() ,
+ * is defined externally, but not exported in a .h file,
+ * because we want to keep it as private as possible.
+ * We will declare its prototype here.
+ *
+ * Initialization macros for both "Normal Mode"-only and
+ * "Shared" entries are also defined here.
+ *
+ * Arguments:
+ * fwt (fword_token) Value of the FWord Token (from Enum list)
+ * nam (string) Name of the entry as seen in the source
+ *
+ **************************************************************************** */
+
+void handle_internal( tic_param_t pfield);
+/* "Skip-a-string when Ignoring" function. Same args and limited-proto ... */
+void skip_string( tic_param_t pfield);
+
+#define FWORD_EXEC_FUNC handle_internal
+
+#define BUILTIN_FWORD( fwt, nam) \
+ FWORD_TKN_TIC(nam, FWORD_EXEC_FUNC, fwt, BI_FWRD_DEFN )
+
+#define SHARED_FWORD( fwt, nam) \
+ FWORD_TKN_TIC(nam, FWORD_EXEC_FUNC, fwt, COMMON_FWORD )
+
+/* Variants: When Ignoring, SKip One Word */
+#define SHR_FWD_SKOW( fwt, nam) \
+ DUALFUNC_FWT_TIC(nam, FWORD_EXEC_FUNC, fwt, skip_a_word, COMMON_FWORD )
+
+/* Variants: When Ignoring, SKip one Word in line */
+#define SH_FW_SK_WIL( fwt, nam) \
+ DUALFUNC_FWT_TIC(nam, FWORD_EXEC_FUNC, fwt, \
+ skip_a_word_in_line, COMMON_FWORD )
+
+/* When Ignoring, SKip Two Words in line */
+#define SH_FW_SK2WIL( fwt, nam) \
+ DUALFUNC_FWT_TIC(nam, FWORD_EXEC_FUNC, fwt, \
+ skip_two_words_in_line, COMMON_FWORD )
+
+/* **************************************************************************
+ *
+ * Some of the entries in the "FWords" list -- both "Normal" (Built-in)
+ * and "Shared" also act as an "Ignore-handler".
+ *
+ * Arguments:
+ * nam (string) Name of the entry as seen in the source
+ * afunc (routine-name) Name of internal "active" function
+ * pval (integer) The "param field" item
+ * ifunc (routine-name) Name of "ignore-handling" function
+ *
+ **************************************************************************** */
+
+#define SHARED_IG_HDLR(nam, afunc, pval, ifunc) \
+ DUFNC_FWT_PARM(nam, afunc, pval, ifunc, COMMON_FWORD )
+
+/* A "Shared" entry that uses the same routine for both of its functions */
+#define SHR_SAMIG_FWRD( fwt, nam) \
+ DUFNC_FWT_PARM(nam, FWORD_EXEC_FUNC, fwt, FWORD_EXEC_FUNC, COMMON_FWORD )
+
+/* **************************************************************************
+ *
+ * But the "Normal" (Built-in) FWord Ignore-handler uses the same
+ * routine as the BUILTIN_FWORD for both of its functions.
+ *
+ * Arguments:
+ * fwt (fword_token) Value of the FWord Token (from Enum list)
+ * nam (string) Name of the entry as seen in the source
+ *
+ **************************************************************************** */
+#define BI_IG_FW_HDLR( fwt, nam) \
+ DUALFUNC_FWT_TIC(nam, FWORD_EXEC_FUNC, fwt, FWORD_EXEC_FUNC, BI_FWRD_DEFN )
+
+/* A variant: A "Built-In FWorD that SKiPs One Word", when Ignoring */
+#define BI_FWD_SKP_OW( fwt, nam) \
+ DUALFUNC_FWT_TIC(nam, FWORD_EXEC_FUNC, fwt, skip_a_word, BI_FWRD_DEFN )
+
+/* Another variant: A "Built-In FWorD String". skip_string when Ignoring */
+#define BI_FWD_STRING( fwt, nam) \
+ DUALFUNC_FWT_TIC(nam, FWORD_EXEC_FUNC, fwt, skip_string, BI_FWRD_DEFN )
+
+/* **************************************************************************
+ *
+ * In order to protect device-nodes' methods from being accessed
+ * by other device-nodes (with the attendant potential for
+ * disastrous consequences), we must establish a few rules:
+ *
+ * Each device-node has a separate vocabulary for its methods.
+ * New definitions are made to the "current" device's vocabulary.
+ * Searches for names go through the "current" device-node's
+ * vocabulary first, then through the core dictionary.
+ *
+ * A new-device (in interpretation-mode) creates a new device-node
+ * vocabulary. The node that had been current (presumably its
+ * parent) remains in memory but inactive.
+ *
+ * A finish-device (again, only in interpretation-mode) removes the
+ * current device-node's vocabulary from memory; its presumed
+ * parent once again becomes current.
+ *
+ * Tokenization starts with an implicit "new-device" in effect.
+ * The top-level device-node is never removed.
+ *
+ * The Global Variable current_definitions points to the vocabulary
+ * to which we will add and through which we will search first.
+ *
+ * If "global" scope is in effect, then current_definitions will
+ * point to the "Global" (also called "core") vocabulary.
+ *
+ **************************************************************************** */
+
+/* **************************************************************************
+ *
+ * Support for operations in "current" -- i.e., "global" vis-a-vis
+ * "device" -- scope.
+ * "Global" scope will not recognize words defined in "device" scope,
+ * but "device" scope will recognize "global" words.
+ *
+ **************************************************************************** */
+
+/* **************************************************************************
+ *
+ * Functions to enter "global" scope and resume "device" scope.
+ *
+ **************************************************************************** */
+
+static tic_hdr_t **save_device_definitions;
+/* Export the indication that "global" scope is in effect */
+bool scope_is_global = FALSE;
+
+
+void enter_global_scope( void )
+{
+ if ( scope_is_global )
+{
+ tokenization_error( WARNING,
+ "%s -- Global Scope already in effect; ignoring.\n",
+ strupr(statbuf) );
+ }else{
+ tokenization_error( INFO,
+ "Initiating Global Scope definitions.\n" );
+ scope_is_global = TRUE;
+ save_device_definitions = current_definitions;
+ current_definitions = &global_voc_dict_ptr;
+ }
+}
+
+void resume_device_scope( void )
+{
+ if ( scope_is_global )
+ {
+ tokenization_error( INFO,
+ "Terminating Global Scope definitions; "
+ "resuming Device-node definitions.\n" );
+ current_definitions = save_device_definitions;
+ scope_is_global = FALSE;
+ }else{
+ tokenization_error( WARNING,
+ "%s -- Device-node Scope already in effect; ignoring.\n",
+ strupr(statbuf) );
+ }
+
+}
+
+/* **************************************************************************
+ *
+ * Function name: lookup_current
+ * Synopsis: Return a pointer to the data-structure of the named
+ * word, either in the Current Device-Node vocab,
+ * or in the Global ("core") Vocabulary.
+ *
+ * Inputs:
+ * Parameters:
+ * tname The name to look for
+ * Global Variables:
+ * current_definitions Current vocabulary: Device-Node, or
+ * "core" if "global" scope in effect.
+ * scope_is_global TRUE if "global" scope is in effect
+ * Local Static Variables:
+ * global_voc_dict_ptr "Tail" of Global Vocabulary
+ *
+ * Outputs:
+ * Returned Value: Pointer to the data-structure, or
+ * NULL if not found.
+ *
+ * Process Explanation:
+ * If a current Device-Node Vocabulary in effect, search through it.
+ * If the given name was not found, and "global" scope is not in
+ * effect (i.e., "core" was not already searched), make a
+ * separate search through the Global ("core") Vocabulary
+ *
+ * Extraneous Remarks:
+ * This is the central routine for doing general word-searches that
+ * make use of the "normal"-mode search-list.
+ *
+ **************************************************************************** */
+
+tic_hdr_t *lookup_current( char *tname)
+{
+ /* Search Current Device Vocabulary ahead of global (core) vocabulary */
+ tic_hdr_t *retval;
+ retval = lookup_tic_entry( tname, *current_definitions);
+ if ( (retval == NULL) && INVERSE(scope_is_global) )
+{
+ retval = lookup_core_word( tname);
+ }
+ return ( retval );
+}
+
+/* **************************************************************************
+ *
+ * Function name: exists_in_current
+ * Synopsis: Confirm whether the given name exists either
+ * in the Current Device-Node vocab,
+ * or in the Global ("core") Vocabulary,
+ * or in Tokenizer Escape Mode, if that's current.
+ *
+ * Inputs:
+ * Parameters:
+ * tname The name to look for
+ *
+ * Outputs:
+ * Returned Value: TRUE if name is found
+ *
+ **************************************************************************** */
+
+bool exists_in_current( char *tname)
+{
+ tic_hdr_t *found = lookup_word( tname, NULL, NULL);
+ bool retval = BOOLVAL ( found != NULL);
+ return( retval);
}
- curr->next=*dict;
- curr->fcode=number;
- curr->name=(u8 *)name;
- *dict=curr;
- return 0;
+/* **************************************************************************
+ *
+ * Function name: handle_current
+ * Synopsis: Perform a function in the current device-node vocab,
+ * if one is in effect, or in the "Global" Vocabulary.
+ * Indicate whether the name is valid.
+ *
+ * Inputs:
+ * Parameters:
+ * tname The name to handle
+ * Global Variables:
+ * current_definitions Device-Node (or Global) Vocabulary
+ * currently in effect.
+ * scope_is_global TRUE if "global" scope is in effect
+ * Local Static Variables:
+ *
+ * Outputs:
+ * Returned Value: TRUE if the given name is valid
+ *
+ **************************************************************************** */
+
+bool handle_current( char *tname )
+{
+ bool retval = handle_tic_vocab( tname, *current_definitions );
+
+ if ( INVERSE(retval) && INVERSE(scope_is_global) )
+ {
+ retval = handle_core_word( tname );
+ }
+ return ( retval );
+
}
-int add_token(u16 number, char *name)
+
+/* **************************************************************************
+ *
+ * Function name: lookup_in_dev_node
+ * Synopsis: Return a pointer to the data-structure of the
+ * named word in the Current device node, if
+ * in "Device" scope. Used for error-reporting.
+ *
+ * Inputs:
+ * Parameters:
+ * tname The name to look for
+ * Global Variables:
+ * current_definitions Device-Node (or Global) Vocabulary
+ * currently in effect.
+ * scope_is_global FALSE if "Device" scope is in effect
+ *
+ * Outputs:
+ * Returned Value: Pointer to the data-structure, or
+ * NULL if not found.
+ *
+ **************************************************************************** */
+
+tic_hdr_t *lookup_in_dev_node( char *tname)
{
- return add_token_dict(number, name, &dictionary);
+ tic_hdr_t *retval = NULL;
+
+ if ( INVERSE(scope_is_global) )
+{
+ retval = lookup_tic_entry( tname, *current_definitions);
}
+ return ( retval );
+}
-static int add_special(u16 number, char *name)
+
+/* **************************************************************************
+ *
+ * In order to avoid unintentional "recursive"-ness, we need a way
+ * to render a newly created colon-definition non-findable
+ * until it's completed.
+ *
+ * We will accomplish this by saving and reverting the pointer to
+ * the newest entry, when we call the hide_last_colon() , and
+ * by restoring the pointer when we call reveal_last_colon()
+ *
+ * We need, therefore, to save the pointer to the last entry before
+ * we create the new entry.
+ *
+ **************************************************************************** */
+
+/* Update this each time a new definition is entered */
+static tic_hdr_t *save_current = NULL;
+
+/* **************************************************************************
+ *
+ * Function name: add_to_current
+ * Synopsis: Add a new entry to the "current" scope of definitions,
+ * which may be either the Global Vocabulary or the
+ * current Device-Node Vocabulary.
+ *
+ * Inputs:
+ * Parameters:
+ * name The name of the new entry
+ * fc_token The new entry's assigned FCode-number
+ * fw_definer The new entry's definer
+ * define_token If FALSE, suppress adding the entry,
+ * but preserve the side-effect of
+ * setting save_current
+ * Global Variables:
+ * current_definitions Pointer to pointer to "tail" of the
+ * Vocabulary currently in effect;
+ * either Device-node or Global.
+ *
+ * Outputs:
+ * Returned Value: NONE
+ * Global Variables:
+ * *current_definitions Updated with the new entry
+ * Local Static Variables:
+ * save_current Pointer to previous entry
+ * Memory Allocated
+ * For the new entry's copy of the name.
+ * When Freed?
+ * When the Device-Node is "finish"ed or the Global Vocabulary
+ * is reset, or when the program exits.
+ *
+ * Process Explanation:
+ * Because current_definitions points to the Global Vocabulary
+ * pointer during "global" scope, this routine is extremely
+ * straightforward.
+ * All user-defined words have the same action, i.e., emitting
+ * the assigned FCode-number. The new entry's "parameter
+ * field" size is, of course, zero; the "ignore-function"
+ * is NULL.
+ *
+ * Extraneous Remarks:
+ * The define_token parameter is a late addition, necessitated
+ * by the decision to continue processing after an erroneous
+ * attempt to create a definition inside a control-structure,
+ * in order to catch other errors.
+ *
+ *
+ **************************************************************************** */
+
+void add_to_current( char *name,
+ TIC_P_DEFLT_TYPE fc_token,
+ fwtoken definer,
+ bool define_token)
{
- return add_token_dict(number, name, &forthwords);
+ save_current = *current_definitions;
+ if ( define_token )
+{
+ char *nu_name = strdup( name);
+ add_tic_entry( nu_name, FC_TOKEN_FUNC, fc_token,
+ definer, 0 , NULL, current_definitions );
+ }
}
-void init_dictionary(void)
+
+void hide_last_colon ( void )
{
- add_token( 0x000, "end0" );
- add_token( 0x010, "b(lit)" );
- add_token( 0x011, "b(')" );
- add_token( 0x012, "b(\")" );
- add_token( 0x013, "bbranch" );
- add_token( 0x014, "b?branch" );
- add_token( 0x015, "b(loop)" );
- add_token( 0x016, "b(+loop)" );
- add_token( 0x017, "b(do)" );
- add_token( 0x018, "b(?do)" );
- add_token( 0x019, "i" );
- add_token( 0x01a, "j" );
- add_token( 0x01b, "b(leave)" );
- add_token( 0x01c, "b(of)" );
- add_token( 0x01d, "execute" );
- add_token( 0x01e, "+" );
- add_token( 0x01f, "-" );
- add_token( 0x020, "*" );
- add_token( 0x021, "/" );
- add_token( 0x022, "mod" );
- add_token( 0x023, "and" );
- add_token( 0x024, "or" );
- add_token( 0x025, "xor" );
- add_token( 0x026, "invert" );
- add_token( 0x027, "lshift" );
- add_token( 0x028, "rshift" );
- add_token( 0x029, ">>a" );
- add_token( 0x02a, "/mod" );
- add_token( 0x02b, "u/mod" );
- add_token( 0x02c, "negate" );
- add_token( 0x02d, "abs" );
- add_token( 0x02e, "min" );
- add_token( 0x02f, "max" );
- add_token( 0x030, ">r" );
- add_token( 0x031, "r>" );
- add_token( 0x032, "r@" );
- add_token( 0x033, "exit" );
- add_token( 0x034, "0=" );
- add_token( 0x035, "0<>" );
- add_token( 0x036, "0<" );
- add_token( 0x037, "0<=" );
- add_token( 0x038, "0>" );
- add_token( 0x039, "0>=" );
- add_token( 0x03a, "<" );
- add_token( 0x03b, ">" );
- add_token( 0x03c, "=" );
- add_token( 0x03d, "<>" );
- add_token( 0x03e, "u>" );
- add_token( 0x03f, "u<=" );
- add_token( 0x040, "u<" );
- add_token( 0x041, "u>=" );
- add_token( 0x042, ">=" );
- add_token( 0x043, "<=" );
- add_token( 0x044, "between" );
- add_token( 0x045, "within" );
- add_token( 0x046, "drop" );
- add_token( 0x047, "dup" );
- add_token( 0x048, "over" );
- add_token( 0x049, "swap" );
- add_token( 0x04A, "rot" );
- add_token( 0x04b, "-rot" );
- add_token( 0x04c, "tuck" );
- add_token( 0x04d, "nip" );
- add_token( 0x04e, "pick" );
- add_token( 0x04f, "roll" );
- add_token( 0x050, "?dup" );
- add_token( 0x051, "depth" );
- add_token( 0x052, "2drop" );
- add_token( 0x053, "2dup" );
- add_token( 0x054, "2over" );
- add_token( 0x055, "2swap" );
- add_token( 0x056, "2rot" );
- add_token( 0x057, "2/" );
- add_token( 0x058, "u2/" );
- add_token( 0x059, "2*" );
- add_token( 0x05a, "/c" );
- add_token( 0x05b, "/w" );
- add_token( 0x05c, "/l" );
- add_token( 0x05d, "/n" );
- add_token( 0x05e, "ca+" );
- add_token( 0x05f, "wa+" );
- add_token( 0x060, "la+" );
- add_token( 0x061, "na+" );
- add_token( 0x062, "char+" );
- add_token( 0x063, "wa1+" );
- add_token( 0x064, "la1+" );
- add_token( 0x065, "cell+" );
- add_token( 0x066, "chars" );
- add_token( 0x067, "/w*" );
- add_token( 0x068, "/l*" );
- add_token( 0x069, "cells" );
- add_token( 0x06a, "on" );
- add_token( 0x06b, "off" );
- add_token( 0x06c, "+!" );
- add_token( 0x06d, "@" );
- add_token( 0x06e, "l@" );
- add_token( 0x06f, "w@" );
- add_token( 0x070, "<w@" );
- add_token( 0x071, "c@" );
- add_token( 0x072, "!" );
- add_token( 0x073, "l!" );
- add_token( 0x074, "w!" );
- add_token( 0x075, "c!" );
- add_token( 0x076, "2@" );
- add_token( 0x077, "2!" );
- add_token( 0x078, "move" );
- add_token( 0x079, "fill" );
- add_token( 0x07a, "comp" );
- add_token( 0x07b, "noop" );
- add_token( 0x07c, "lwsplit" );
- add_token( 0x07d, "wljoin" );
- add_token( 0x07e, "lbsplit" );
- add_token( 0x07f, "bljoin" );
- add_token( 0x080, "wbflip" );
- add_token( 0x081, "upc" );
- add_token( 0x082, "lcc" );
- add_token( 0x083, "pack" );
- add_token( 0x084, "count" );
- add_token( 0x085, "body>" );
- add_token( 0x086, ">body" );
- add_token( 0x087, "fcode-revision" );
- add_token( 0x088, "span" );
- add_token( 0x089, "unloop" );
- add_token( 0x08a, "expect" );
- add_token( 0x08b, "alloc-mem" );
- add_token( 0x08c, "free-mem" );
- add_token( 0x08d, "key?" );
- add_token( 0x08e, "key" );
- add_token( 0x08f, "emit" );
- add_token( 0x090, "type" );
- add_token( 0x091, "(cr" );
- add_token( 0x092, "cr" );
- add_token( 0x093, "#out" );
- add_token( 0x094, "#line" );
- add_token( 0x095, "hold" );
- add_token( 0x096, "<#" );
- add_token( 0x097, "u#>" );
- add_token( 0x098, "sign" );
- add_token( 0x099, "u#" );
- add_token( 0x09a, "u#s" );
- add_token( 0x09b, "u." );
- add_token( 0x09c, "u.r" );
- add_token( 0x09d, "." );
- add_token( 0x09e, ".r" );
- add_token( 0x09f, ".s" );
- add_token( 0x0a0, "base" );
- add_token( 0x0a1, "convert" );
- add_token( 0x0a2, "$number" );
- add_token( 0x0a3, "digit" );
- add_token( 0x0a4, "-1" );
- add_token( 0x0a5, "0" );
- add_token( 0x0a6, "1" );
- add_token( 0x0a7, "2" );
- add_token( 0x0a8, "3" );
- add_token( 0x0a9, "bl" );
- add_token( 0x0aa, "bs" );
- add_token( 0x0ab, "bell" );
- add_token( 0x0ac, "bounds" );
- add_token( 0x0ad, "here" );
- add_token( 0x0ae, "aligned" );
- add_token( 0x0af, "wbsplit" );
- add_token( 0x0b0, "bwjoin" );
- add_token( 0x0b1, "b(<mark)" );
- add_token( 0x0b2, "b(>resolve)" );
- add_token( 0x0b3, "set-token-table" );
- add_token( 0x0b4, "set-table" );
- add_token( 0x0b5, "new-token" );
- add_token( 0x0b6, "named-token" );
- add_token( 0x0b7, "b(:)" );
- add_token( 0x0b8, "b(value)" );
- add_token( 0x0b9, "b(variable)" );
- add_token( 0x0ba, "b(constant)" );
- add_token( 0x0bb, "b(create)" );
- add_token( 0x0bc, "b(defer)" );
- add_token( 0x0bd, "b(buffer:)" );
- add_token( 0x0be, "b(field)" );
- add_token( 0x0bf, "b(code)" );
- add_token( 0x0c0, "instance" );
- add_token( 0x0c2, "b(;)" );
- add_token( 0x0c3, "b(to)" );
- add_token( 0x0c4, "b(case)" );
- add_token( 0x0c5, "b(endcase)" );
- add_token( 0x0c6, "b(endof)" );
- add_token( 0x0c7, "#" );
- add_token( 0x0c8, "#s" );
- add_token( 0x0c9, "#>" );
- add_token( 0x0ca, "external-token" );
- add_token( 0x0cb, "$find" );
- add_token( 0x0cc, "offset16" );
- add_token( 0x0cd, "evaluate" );
- add_token( 0x0d0, "c," );
- add_token( 0x0d1, "w," );
- add_token( 0x0d2, "l," );
- add_token( 0x0d3, "," );
- add_token( 0x0d4, "um*" );
- add_token( 0x0d5, "um/mod" );
- add_token( 0x0d8, "d+" );
- add_token( 0x0d9, "d-" );
- add_token( 0x0da, "get-token" );
- add_token( 0x0db, "set-token" );
- add_token( 0x0dc, "state" );
- add_token( 0x0dd, "compile" );
- add_token( 0x0de, "behavior" );
- add_token( 0x0f0, "start0" );
- add_token( 0x0f1, "start1" );
- add_token( 0x0f2, "start2" );
- add_token( 0x0f3, "start4" );
- add_token( 0x0fc, "ferror" );
- add_token( 0x0fd, "version1" );
- add_token( 0x0fe, "4-byte-id" );
- add_token( 0x0ff, "end1" );
- add_token( 0x101, "dma-alloc" );
- add_token( 0x102, "my-address" );
- add_token( 0x103, "my-space" );
- add_token( 0x104, "memmap" );
- add_token( 0x105, "free-virtual" );
- add_token( 0x106, ">physical" );
- add_token( 0x10f, "my-params" );
- add_token( 0x110, "property" );
- add_token( 0x111, "encode-int" );
- add_token( 0x112, "encode+" );
- add_token( 0x113, "encode-phys" );
- add_token( 0x114, "encode-string" );
- add_token( 0x115, "encode-bytes" );
- add_token( 0x116, "reg" );
- add_token( 0x117, "intr" );
- add_token( 0x118, "driver" );
- add_token( 0x119, "model" );
- add_token( 0x11a, "device-type" );
- add_token( 0x11b, "parse-2int" );
- add_token( 0x11c, "is-install" );
- add_token( 0x11d, "is-remove" );
- add_token( 0x11e, "is-selftest" );
- add_token( 0x11f, "new-device" );
- add_token( 0x120, "diagnostic-mode?" );
- add_token( 0x121, "display-status" );
- add_token( 0x122, "memory-test-issue" );
- add_token( 0x123, "group-code" );
- add_token( 0x124, "mask" );
- add_token( 0x125, "get-msecs" );
- add_token( 0x126, "ms" );
- add_token( 0x127, "finish-device" );
- add_token( 0x128, "decode-phys" );
- add_token( 0x12b, "interpose" );
- add_token( 0x130, "map-low" );
- add_token( 0x131, "sbus-intr>cpu" );
- add_token( 0x150, "#lines" );
- add_token( 0x151, "#columns" );
- add_token( 0x152, "line#" );
- add_token( 0x153, "column#" );
- add_token( 0x154, "inverse?" );
- add_token( 0x155, "inverse-screen?" );
- add_token( 0x156, "frame-buffer-busy?" );
- add_token( 0x157, "draw-character" );
- add_token( 0x158, "reset-screen" );
- add_token( 0x159, "toggle-cursor" );
- add_token( 0x15a, "erase-screen" );
- add_token( 0x15b, "blink-screen" );
- add_token( 0x15c, "invert-screen" );
- add_token( 0x15d, "insert-characters" );
- add_token( 0x15e, "delete-characters" );
- add_token( 0x15f, "insert-lines" );
- add_token( 0x160, "delete-lines" );
- add_token( 0x161, "draw-logo" );
- add_token( 0x162, "frame-buffer-adr" );
- add_token( 0x163, "screen-height" );
- add_token( 0x164, "screen-width" );
- add_token( 0x165, "window-top" );
- add_token( 0x166, "window-left" );
- add_token( 0x16a, "default-font" );
- add_token( 0x16b, "set-font" );
- add_token( 0x16c, "char-height" );
- add_token( 0x16d, "char-width" );
- add_token( 0x16e, ">font" );
- add_token( 0x16f, "fontbytes" );
- add_token( 0x170, "fb1-draw-character" );
- add_token( 0x171, "fb1-reset-screen" );
- add_token( 0x172, "fb1-toggle-cursor" );
- add_token( 0x173, "fb1-erase-screen" );
- add_token( 0x174, "fb1-blink-screen" );
- add_token( 0x175, "fb1-invert-screen" );
- add_token( 0x176, "fb1-insert-characters" );
- add_token( 0x177, "fb1-delete-characters" );
- add_token( 0x178, "fb1-insert-lines" );
- add_token( 0x179, "fb1-delete-lines" );
- add_token( 0x17a, "fb1-draw-logo" );
- add_token( 0x17b, "fb1-install" );
- add_token( 0x17c, "fb1-slide-up" );
- add_token( 0x180, "fb8-draw-character" );
- add_token( 0x181, "fb8-reset-screen" );
- add_token( 0x182, "fb8-toggle-cursor" );
- add_token( 0x183, "fb8-erase-screen" );
- add_token( 0x184, "fb8-blink-screen" );
- add_token( 0x185, "fb8-invert-screen" );
- add_token( 0x186, "fb8-insert-characters" );
- add_token( 0x187, "fb8-delete-characters" );
- add_token( 0x188, "fb8-insert-lines" );
- add_token( 0x189, "fb8-delete-lines" );
- add_token( 0x18a, "fb8-draw-logo" );
- add_token( 0x18b, "fb8-install" );
- add_token( 0x1a0, "return-buffer" );
- add_token( 0x1a1, "xmit-packet" );
- add_token( 0x1a2, "poll-packet" );
- add_token( 0x1a4, "mac-address" );
- add_token( 0x201, "device-name" );
- add_token( 0x202, "my-args" );
- add_token( 0x203, "my-self" );
- add_token( 0x204, "find-package" );
- add_token( 0x205, "open-package" );
- add_token( 0x206, "close-package" );
- add_token( 0x207, "find-method" );
- add_token( 0x208, "call-package" );
- add_token( 0x209, "$call-parent" );
- add_token( 0x20a, "my-package" );
- add_token( 0x20b, "ihandle>phandle" );
- add_token( 0x20d, "my-unit" );
- add_token( 0x20e, "$call-method" );
- add_token( 0x20f, "$open-package" );
- add_token( 0x210, "processor-type" );
- add_token( 0x211, "firmware-version" );
- add_token( 0x212, "fcode-version" );
- add_token( 0x213, "alarm" );
- add_token( 0x214, "(is-user-word)" );
- add_token( 0x215, "suspend-fcode" );
- add_token( 0x216, "abort" );
- add_token( 0x217, "catch" );
- add_token( 0x218, "throw" );
- add_token( 0x219, "user-abort" );
- add_token( 0x21a, "get-my-property" );
- add_token( 0x21b, "decode-int" );
- add_token( 0x21c, "decode-string" );
- add_token( 0x21d, "get-inherited-property" );
- add_token( 0x21e, "delete-property" );
- add_token( 0x21f, "get-package-property" );
- add_token( 0x220, "cpeek" );
- add_token( 0x221, "wpeek" );
- add_token( 0x222, "lpeek" );
- add_token( 0x223, "cpoke" );
- add_token( 0x224, "wpoke" );
- add_token( 0x225, "lpoke" );
- add_token( 0x226, "lwflip" );
- add_token( 0x227, "lbflip" );
- add_token( 0x228, "lbflips" );
- add_token( 0x229, "adr-mask" );
- add_token( 0x230, "rb@" );
- add_token( 0x231, "rb!" );
- add_token( 0x232, "rw@" );
- add_token( 0x233, "rw!" );
- add_token( 0x234, "rl@" );
- add_token( 0x235, "rl!" );
- add_token( 0x236, "wbflips" );
- add_token( 0x237, "lwflips" );
- add_token( 0x238, "probe" );
- add_token( 0x239, "probe-virtual" );
- add_token( 0x23b, "child" );
- add_token( 0x23c, "peer" );
- add_token( 0x23d, "next-property" );
- add_token( 0x23e, "byte-load" );
- add_token( 0x23f, "set-args" );
- add_token( 0x240, "left-parse-string" );
+ tic_hdr_t *temp_vocab;
+ /* The add_to_current() function will have been called before this
+ * one when a new colon-definition is created, so save_current
+ * will have been set to point to the entry that had been made
+ * just before the newest one, which we are hiding here.
+ */
+
+ temp_vocab = save_current ;
+ save_current = *current_definitions;
+ *current_definitions = temp_vocab;
+
+}
+
+void reveal_last_colon ( void )
+{
+ /* We call this function either when the colon-definition is
+ * completed, or when "recursive"-ness is intentional.
+ */
+ *current_definitions = save_current ;
+}
+
+
+/* **************************************************************************
+ *
+ * Function name: create_current_alias
+ * Synopsis: Create an alias for OLD_NAME, called NEW_NAME, in
+ * the "current" scope of definitions, which may
+ * be either the Global ("core") Vocabulary or the
+ * current Device-Node Vocabulary. Indicate if
+ * successful (i.e., OLD_NAME was valid).
+ * This is actually a little trickier than it may at
+ * first appear; read the Rules in the Process
+ * Explanation for full details...
+ *
+ * Inputs:
+ * Parameters:
+ * new_name The name for the new alias to be created
+ * old_name The name of the old function to be duplicated
+ * Global Variables:
+ * current_definitions Device-node vocabulary currently
+ * in effect.
+ * scope_is_global TRUE if "global" scope is in effect
+ * Local Static Variables:
+ * global_voc_dict_ptr "Tail" of Global Vocabulary
+ *
+ * Outputs:
+ * Returned Value: TRUE if OLD_NAME was found.
+ * Global Variables:
+ * *current_definitions Updated with the new entry
+ * Memory Allocated
+ * By support routine.
+ * When Freed?
+ * When RESET-SYMBOLS is issued (if "global" scope is in effect)
+ * or when the device-node is "finish"ed.
+ * Printout:
+ * Advisory message if Rule 3 (see below) is invoked.
+ *
+ * Process Explanation:
+ * Both the "old" and "new" names are presumed to already point to
+ * stable, freshly allocated memory-spaces.
+ * Rules:
+ * (1)
+ * If "global" scope is in effect, and the "old" name is found in
+ * the Global Vocabulary, then the "new" name will be created
+ * in the Global Vocabulary.
+ * (2)
+ * Similarly, if "device" scope is in effect, and the "old" name is
+ * found in the current device-node's vocabulary, the "new" name
+ * will be created in the current device-node's vocabulary.
+ * (3)
+ * BUT!: If "device" scope is in effect, and the "old" name is found
+ * in the Global Vocabulary, then the "new" name will be created
+ * in the current device-node's vocabulary. It will only be
+ * recognized in the scope of that device-node, and will be
+ * removed from memory when the device-node is "finish"ed.
+ * And, yes, it *is* supposed to work that way... ;-)
+ *
+ * Again, because current_definitions points to the Global Vocab
+ * pointer during "global" scope, the first two rules of this
+ * routine are extremely straightforward; it's Rule 3 that you
+ * have to watch out for... ;-)
+ *
+ * And one other thing:
+ * We will always make the alias's pfld_size zero. See the
+ * prolog for create_tic_alias() in ticvocab.c for details...
+ *
+ * Extraneous Remarks:
+ * I will stretch the rules of well-structured code here, too.
+ *
+ **************************************************************************** */
+
+bool create_current_alias( char *new_name, char *old_name )
+{
+ bool retval = FALSE;
+
+ if ( create_tic_alias( new_name, old_name, current_definitions) )
+ {
+ return ( TRUE );
+ }
+
+ if ( INVERSE(scope_is_global) )
+ {
+ tic_hdr_t *found = lookup_core_word( old_name );
+ if ( found != NULL )
+ {
+ add_tic_entry( new_name, found->funct,
+ found->pfield.deflt_elem,
+ found->fword_defr,
+ 0, found->ign_func,
+ current_definitions );
+ retval = TRUE;
+ {
+ tokenization_error( INFO,
+ "%s is a Global definition, but its alias, %s, "
+ "will only be defined %s",
+ strupr( old_name), new_name,
+ in_what_node( current_device_node) );
+ show_node_start();
+ }
+ }
+ }
+
+ return ( retval );
+}
+
+/* **************************************************************************
+ *
+ * Support functions specific to the lists will be defined
+ * after the lists are created.
+ *
+ **************************************************************************** */
+
+/* **************************************************************************
+ *
+ * Create the initial list (or "Table") of FCode-Tokens.
+ *
+ * Most Standard FCode tokens are not specified as to their definition
+ * type, but a few have a definer specified as either a VALUE, a
+ * VARIABLE or a DEFER; we will enter them with the appropriate macro.
+ *
+ **************************************************************************** */
+
+static tic_hdr_t tokens_table[] =
+{
+ BUILTIN_FCODE( 0x000, "end0" ) ,
+ BUILTIN_FCODE( 0x010, "b(lit)" ) ,
+ BUILTIN_FCODE( 0x011, "b(')" ) ,
+ BUILTIN_FCODE( 0x012, "b(\")" ) ,
+ BUILTIN_FCODE( 0x013, "bbranch" ) ,
+ BUILTIN_FCODE( 0x014, "b?branch" ) ,
+ BUILTIN_FCODE( 0x015, "b(loop)" ) ,
+ BUILTIN_FCODE( 0x016, "b(+loop)" ) ,
+ BUILTIN_FCODE( 0x017, "b(do)" ) ,
+ BUILTIN_FCODE( 0x018, "b(?do)" ) ,
+ BUILTIN_FCODE( 0x019, "i" ) ,
+ BUILTIN_FCODE( 0x01a, "j" ) ,
+ BUILTIN_FCODE( 0x01b, "b(leave)" ) ,
+ BUILTIN_FCODE( 0x01c, "b(of)" ) ,
+ BUILTIN_FCODE( 0x01d, "execute" ) ,
+ BUILTIN_FCODE( 0x01e, "+" ) ,
+ BUILTIN_FCODE( 0x01f, "-" ) ,
+ BUILTIN_FCODE( 0x020, "*" ) ,
+ BUILTIN_FCODE( 0x021, "/" ) ,
+ BUILTIN_FCODE( 0x022, "mod" ) ,
+ BUILTIN_FCODE( 0x023, "and" ) ,
+ BUILTIN_FCODE( 0x024, "or" ) ,
+ BUILTIN_FCODE( 0x025, "xor" ) ,
+ BUILTIN_FCODE( 0x026, "invert" ) ,
+ BUILTIN_FCODE( 0x026, "not" ) , /* Synonym for "invert" */
+ BUILTIN_FCODE( 0x027, "lshift" ) ,
+ BUILTIN_FCODE( 0x027, "<<" ) , /* Synonym for "lshift" */
+ BUILTIN_FCODE( 0x028, "rshift" ) ,
+ BUILTIN_FCODE( 0x028, ">>" ) , /* Synonym for "rshift" */
+ BUILTIN_FCODE( 0x029, ">>a" ) ,
+ BUILTIN_FCODE( 0x02a, "/mod" ) ,
+ BUILTIN_FCODE( 0x02b, "u/mod" ) ,
+ BUILTIN_FCODE( 0x02c, "negate" ) ,
+ BUILTIN_FCODE( 0x02d, "abs" ) ,
+ BUILTIN_FCODE( 0x02e, "min" ) ,
+ BUILTIN_FCODE( 0x02f, "max" ) ,
+ BUILTIN_FCODE( 0x030, ">r" ) ,
+ BUILTIN_FCODE( 0x031, "r>" ) ,
+ BUILTIN_FCODE( 0x032, "r@" ) ,
+ BUILTIN_FCODE( 0x033, "exit" ) ,
+ BUILTIN_FCODE( 0x034, "0=" ) ,
+ BUILTIN_FCODE( 0x035, "0<>" ) ,
+ BUILTIN_FCODE( 0x036, "0<" ) ,
+ BUILTIN_FCODE( 0x037, "0<=" ) ,
+ BUILTIN_FCODE( 0x038, "0>" ) ,
+ BUILTIN_FCODE( 0x039, "0>=" ) ,
+ BUILTIN_FCODE( 0x03a, "<" ) ,
+ BUILTIN_FCODE( 0x03b, ">" ) ,
+ BUILTIN_FCODE( 0x03c, "=" ) ,
+ BUILTIN_FCODE( 0x03d, "<>" ) ,
+ BUILTIN_FCODE( 0x03e, "u>" ) ,
+ BUILTIN_FCODE( 0x03f, "u<=" ) ,
+ BUILTIN_FCODE( 0x040, "u<" ) ,
+ BUILTIN_FCODE( 0x041, "u>=" ) ,
+ BUILTIN_FCODE( 0x042, ">=" ) ,
+ BUILTIN_FCODE( 0x043, "<=" ) ,
+ BUILTIN_FCODE( 0x044, "between" ) ,
+ BUILTIN_FCODE( 0x045, "within" ) ,
+ BUILTIN_FCODE( 0x046, "drop" ) ,
+ BUILTIN_FCODE( 0x047, "dup" ) ,
+ BUILTIN_FCODE( 0x048, "over" ) ,
+ BUILTIN_FCODE( 0x049, "swap" ) ,
+ BUILTIN_FCODE( 0x04A, "rot" ) ,
+ BUILTIN_FCODE( 0x04b, "-rot" ) ,
+ BUILTIN_FCODE( 0x04c, "tuck" ) ,
+ BUILTIN_FCODE( 0x04d, "nip" ) ,
+ BUILTIN_FCODE( 0x04e, "pick" ) ,
+ BUILTIN_FCODE( 0x04f, "roll" ) ,
+ BUILTIN_FCODE( 0x050, "?dup" ) ,
+ BUILTIN_FCODE( 0x051, "depth" ) ,
+ BUILTIN_FCODE( 0x052, "2drop" ) ,
+ BUILTIN_FCODE( 0x053, "2dup" ) ,
+ BUILTIN_FCODE( 0x054, "2over" ) ,
+ BUILTIN_FCODE( 0x055, "2swap" ) ,
+ BUILTIN_FCODE( 0x056, "2rot" ) ,
+ BUILTIN_FCODE( 0x057, "2/" ) ,
+ BUILTIN_FCODE( 0x058, "u2/" ) ,
+ BUILTIN_FCODE( 0x059, "2*" ) ,
+ BUILTIN_FCODE( 0x05a, "/c" ) ,
+ BUILTIN_FCODE( 0x05b, "/w" ) ,
+ BUILTIN_FCODE( 0x05c, "/l" ) ,
+ BUILTIN_FCODE( 0x05d, "/n" ) ,
+ BUILTIN_FCODE( 0x05e, "ca+" ) ,
+ BUILTIN_FCODE( 0x05f, "wa+" ) ,
+ BUILTIN_FCODE( 0x060, "la+" ) ,
+ BUILTIN_FCODE( 0x061, "na+" ) ,
+ BUILTIN_FCODE( 0x062, "char+" ) ,
+ BUILTIN_FCODE( 0x062, "ca1+" ) , /* Synonym for char+" */
+ BUILTIN_FCODE( 0x063, "wa1+" ) ,
+ BUILTIN_FCODE( 0x064, "la1+" ) ,
+ BUILTIN_FCODE( 0x065, "cell+" ) ,
+ BUILTIN_FCODE( 0x065, "na1+" ) , /* Synonym for "cell+" */
+ BUILTIN_FCODE( 0x066, "chars" ) ,
+ BUILTIN_FCODE( 0x066, "/c*" ) , /* Synonym for "chars" */
+ BUILTIN_FCODE( 0x067, "/w*" ) ,
+ BUILTIN_FCODE( 0x068, "/l*" ) ,
+ BUILTIN_FCODE( 0x069, "cells" ) ,
+ BUILTIN_FCODE( 0x069, "/n*" ) , /* Synonym for "cells" */
+ BUILTIN_FCODE( 0x06a, "on" ) ,
+ BUILTIN_FCODE( 0x06b, "off" ) ,
+ BUILTIN_FCODE( 0x06c, "+!" ) ,
+ BUILTIN_FCODE( 0x06d, "@" ) ,
+ BUILTIN_FCODE( 0x06e, "l@" ) ,
+ BUILTIN_FCODE( 0x06f, "w@" ) ,
+ BUILTIN_FCODE( 0x070, "<w@" ) ,
+ BUILTIN_FCODE( 0x071, "c@" ) ,
+ BUILTIN_FCODE( 0x072, "!" ) ,
+ BUILTIN_FCODE( 0x073, "l!" ) ,
+ BUILTIN_FCODE( 0x074, "w!" ) ,
+ BUILTIN_FCODE( 0x075, "c!" ) ,
+ BUILTIN_FCODE( 0x076, "2@" ) ,
+ BUILTIN_FCODE( 0x077, "2!" ) ,
+ BUILTIN_FCODE( 0x078, "move" ) ,
+ BUILTIN_FCODE( 0x079, "fill" ) ,
+ BUILTIN_FCODE( 0x07a, "comp" ) ,
+ BUILTIN_FCODE( 0x07b, "noop" ) ,
+ BUILTIN_FCODE( 0x07c, "lwsplit" ) ,
+ BUILTIN_FCODE( 0x07d, "wljoin" ) ,
+ BUILTIN_FCODE( 0x07e, "lbsplit" ) ,
+ BUILTIN_FCODE( 0x07f, "bljoin" ) ,
+ BUILTIN_FCODE( 0x080, "wbflip" ) ,
+ BUILTIN_FCODE( 0x080, "flip" ) , /* Synonym for "wbflip" */
+ BUILTIN_FCODE( 0x081, "upc" ) ,
+ BUILTIN_FCODE( 0x082, "lcc" ) ,
+ BUILTIN_FCODE( 0x083, "pack" ) ,
+ BUILTIN_FCODE( 0x084, "count" ) ,
+ BUILTIN_FCODE( 0x085, "body>" ) ,
+ BUILTIN_FCODE( 0x086, ">body" ) ,
+ BUILTIN_FCODE( 0x087, "fcode-revision" ) ,
+ BUILTIN_FCODE( 0x087, "version" ) , /* Synonym for "fcode-revision" */
+ BI_FCODE_VRBLE( 0x088, "span" ) ,
+ BUILTIN_FCODE( 0x089, "unloop" ) ,
+ BUILTIN_FCODE( 0x08a, "expect" ) ,
+ BUILTIN_FCODE( 0x08b, "alloc-mem" ) ,
+ BUILTIN_FCODE( 0x08c, "free-mem" ) ,
+ BUILTIN_FCODE( 0x08d, "key?" ) ,
+ BUILTIN_FCODE( 0x08e, "key" ) ,
+ BUILTIN_FCODE( 0x08f, "emit" ) ,
+ BUILTIN_FCODE( 0x090, "type" ) ,
+ BUILTIN_FCODE( 0x091, "(cr" ) ,
+ BUILTIN_FCODE( 0x092, "cr" ) ,
+ BI_FCODE_VRBLE( 0x093, "#out" ) ,
+ BI_FCODE_VRBLE( 0x094, "#line" ) ,
+ BUILTIN_FCODE( 0x095, "hold" ) ,
+ BUILTIN_FCODE( 0x096, "<#" ) ,
+ BUILTIN_FCODE( 0x097, "u#>" ) ,
+ BUILTIN_FCODE( 0x098, "sign" ) ,
+ BUILTIN_FCODE( 0x099, "u#" ) ,
+ BUILTIN_FCODE( 0x09a, "u#s" ) ,
+ BUILTIN_FCODE( 0x09b, "u." ) ,
+ BUILTIN_FCODE( 0x09c, "u.r" ) ,
+ BUILTIN_FCODE( 0x09d, "." ) ,
+ BUILTIN_FCODE( 0x09e, ".r" ) ,
+ BUILTIN_FCODE( 0x09f, ".s" ) ,
+ BI_FCODE_VRBLE( 0x0a0, "base" ) ,
+ OBSOLETE_FCODE( 0x0a1, "convert" ) ,
+ BUILTIN_FCODE( 0x0a2, "$number" ) ,
+ BUILTIN_FCODE( 0x0a3, "digit" ) ,
+ BI_FCODE_CONST( 0x0a4, "-1" ) ,
+ BI_FCODE_CONST( 0x0a4, "true" ) , /* Synonym for "-1" */
+ BI_FCODE_CONST( 0x0a5, "0" ) ,
+ BI_FCODE_CONST( 0x0a5, "false" ) , /* Synonym for "0" */
+ BI_FCODE_CONST( 0x0a5, "struct" ) , /* Synonym for "0" */
+ BI_FCODE_CONST( 0x0a6, "1" ) ,
+ BI_FCODE_CONST( 0x0a7, "2" ) ,
+ BI_FCODE_CONST( 0x0a8, "3" ) ,
+ BI_FCODE_CONST( 0x0a9, "bl" ) ,
+ BI_FCODE_CONST( 0x0aa, "bs" ) ,
+ BI_FCODE_CONST( 0x0ab, "bell" ) ,
+ BUILTIN_FCODE( 0x0ac, "bounds" ) ,
+ BUILTIN_FCODE( 0x0ad, "here" ) ,
+ BUILTIN_FCODE( 0x0ae, "aligned" ) ,
+ BUILTIN_FCODE( 0x0af, "wbsplit" ) ,
+ BUILTIN_FCODE( 0x0b0, "bwjoin" ) ,
+ BUILTIN_FCODE( 0x0b1, "b(<mark)" ) ,
+ BUILTIN_FCODE( 0x0b2, "b(>resolve)" ) ,
+ OBSOLETE_FCODE( 0x0b3, "set-token-table" ) ,
+ OBSOLETE_FCODE( 0x0b4, "set-table" ) ,
+ BUILTIN_FCODE( 0x0b5, "new-token" ) ,
+ BUILTIN_FCODE( 0x0b6, "named-token" ) ,
+ BUILTIN_FCODE( 0x0b7, "b(:)" ) ,
+ BUILTIN_FCODE( 0x0b8, "b(value)" ) ,
+ BUILTIN_FCODE( 0x0b9, "b(variable)" ) ,
+ BUILTIN_FCODE( 0x0ba, "b(constant)" ) ,
+ BUILTIN_FCODE( 0x0bb, "b(create)" ) ,
+ BUILTIN_FCODE( 0x0bc, "b(defer)" ) ,
+ BUILTIN_FCODE( 0x0bd, "b(buffer:)" ) ,
+ BUILTIN_FCODE( 0x0be, "b(field)" ) ,
+ OBSOLETE_FCODE( 0x0bf, "b(code)" ) ,
+ BUILTIN_FCODE( 0x0c0, "instance" ) ,
+ BUILTIN_FCODE( 0x0c2, "b(;)" ) ,
+ BUILTIN_FCODE( 0x0c3, "b(to)" ) ,
+ BUILTIN_FCODE( 0x0c4, "b(case)" ) ,
+ BUILTIN_FCODE( 0x0c5, "b(endcase)" ) ,
+ BUILTIN_FCODE( 0x0c6, "b(endof)" ) ,
+ BUILTIN_FCODE( 0x0c7, "#" ) ,
+ BUILTIN_FCODE( 0x0c8, "#s" ) ,
+ BUILTIN_FCODE( 0x0c9, "#>" ) ,
+ BUILTIN_FCODE( 0x0ca, "external-token" ) ,
+ BUILTIN_FCODE( 0x0cb, "$find" ) ,
+ BUILTIN_FCODE( 0x0cc, "offset16" ) ,
+ BUILTIN_FCODE( 0x0cd, "evaluate" ) ,
+ BUILTIN_FCODE( 0x0cd, "eval" ) , /* Synonym for "evaluate" */
+ BUILTIN_FCODE( 0x0d0, "c," ) ,
+ BUILTIN_FCODE( 0x0d1, "w," ) ,
+ BUILTIN_FCODE( 0x0d2, "l," ) ,
+ BUILTIN_FCODE( 0x0d3, "," ) ,
+ BUILTIN_FCODE( 0x0d4, "um*" ) ,
+ BUILTIN_FCODE( 0x0d4, "u*x" ) , /* Synonym for "um*" */
+ BUILTIN_FCODE( 0x0d5, "um/mod" ) ,
+ BUILTIN_FCODE( 0x0d5, "xu/mod" ) , /* Synonym for "um/mod" */
+ BUILTIN_FCODE( 0x0d8, "d+" ) ,
+ BUILTIN_FCODE( 0x0d8, "x+" ) , /* Synonym for "d+" */
+ BUILTIN_FCODE( 0x0d9, "d-" ) ,
+ BUILTIN_FCODE( 0x0d9, "x-" ) , /* Synonym for "d-" */
+ BUILTIN_FCODE( 0x0da, "get-token" ) ,
+ BUILTIN_FCODE( 0x0db, "set-token" ) ,
+ BI_FCODE_VRBLE( 0x0dc, "state" ) ,
+ BUILTIN_FCODE( 0x0dd, "compile" ) ,
+ BUILTIN_FCODE( 0x0de, "behavior" ) ,
+ BUILTIN_FCODE( 0x0f0, "start0" ) ,
+ BUILTIN_FCODE( 0x0f1, "start1" ) ,
+ BUILTIN_FCODE( 0x0f2, "start2" ) ,
+ BUILTIN_FCODE( 0x0f3, "start4" ) ,
+ BUILTIN_FCODE( 0x0fc, "ferror" ) ,
+ BUILTIN_FCODE( 0x0fd, "version1" ) ,
+ OBSOLETE_FCODE( 0x0fe, "4-byte-id" ) ,
+ BUILTIN_FCODE( 0x0ff, "end1" ) ,
+ OBSOLETE_FCODE( 0x101, "dma-alloc" ) ,
+ BUILTIN_FCODE( 0x102, "my-address" ) ,
+ BUILTIN_FCODE( 0x103, "my-space" ) ,
+ OBSOLETE_FCODE( 0x104, "memmap" ) ,
+ BUILTIN_FCODE( 0x105, "free-virtual" ) ,
+ OBSOLETE_FCODE( 0x106, ">physical" ) ,
+ OBSOLETE_FCODE( 0x10f, "my-params" ) ,
+ BUILTIN_FCODE( 0x110, "property" ) ,
+ BUILTIN_FCODE( 0x110, "attribute" ) , /* Synonym for "property" */
+ BUILTIN_FCODE( 0x111, "encode-int" ) ,
+ BUILTIN_FCODE( 0x111, "xdrint" ) , /* Synonym for "encode-int" */
+ BUILTIN_FCODE( 0x112, "encode+" ) ,
+ BUILTIN_FCODE( 0x112, "xdr+" ) , /* Synonym for "encode+" */
+ BUILTIN_FCODE( 0x113, "encode-phys" ) ,
+ BUILTIN_FCODE( 0x113, "xdrphys" ) , /* Synonym for "encode-phys" */
+ BUILTIN_FCODE( 0x114, "encode-string" ) ,
+ BUILTIN_FCODE( 0x114, "xdrstring" ) , /* Synonym for "encode-string" */
+ BUILTIN_FCODE( 0x115, "encode-bytes" ) ,
+ BUILTIN_FCODE( 0x115, "xdrbytes" ) , /* Synonym for "encode-bytes" */
+ BUILTIN_FCODE( 0x116, "reg" ) ,
+ OBSOLETE_FCODE( 0x117, "intr" ) ,
+ OBSOLETE_FCODE( 0x118, "driver" ) ,
+ BUILTIN_FCODE( 0x119, "model" ) ,
+ BUILTIN_FCODE( 0x11a, "device-type" ) ,
+ BUILTIN_FCODE( 0x11b, "parse-2int" ) ,
+ BUILTIN_FCODE( 0x11b, "decode-2int" ) , /* Synonym for "parse-2int" */
+ BUILTIN_FCODE( 0x11c, "is-install" ) ,
+ BUILTIN_FCODE( 0x11d, "is-remove" ) ,
+ BUILTIN_FCODE( 0x11e, "is-selftest" ) ,
+ BUILTIN_FCODE( 0x11f, "new-device" ) ,
+ BUILTIN_FCODE( 0x120, "diagnostic-mode?" ) ,
+ BUILTIN_FCODE( 0x121, "display-status" ) ,
+ BUILTIN_FCODE( 0x122, "memory-test-issue" ) ,
+ OBSOLETE_FCODE( 0x123, "group-code" ) ,
+ BI_FCODE_VRBLE( 0x124, "mask" ) ,
+ BUILTIN_FCODE( 0x125, "get-msecs" ) ,
+ BUILTIN_FCODE( 0x126, "ms" ) ,
+ BUILTIN_FCODE( 0x127, "finish-device" ) ,
+ BUILTIN_FCODE( 0x128, "decode-phys" ) ,
+ BUILTIN_FCODE( 0x12b, "interpose" ) ,
+ BUILTIN_FCODE( 0x130, "map-low" ) ,
+ BUILTIN_FCODE( 0x130, "map-sbus" ) , /* Synonym for "map-low" */
+ BUILTIN_FCODE( 0x131, "sbus-intr>cpu" ) ,
+ BI_FCODE_VALUE( 0x150, "#lines" ) ,
+ BI_FCODE_VALUE( 0x151, "#columns" ) ,
+ BI_FCODE_VALUE( 0x152, "line#" ) ,
+ BI_FCODE_VALUE( 0x153, "column#" ) ,
+ BI_FCODE_VALUE( 0x154, "inverse?" ) ,
+ BI_FCODE_VALUE( 0x155, "inverse-screen?" ) ,
+ OBSOLETE_VALUE( 0x156, "frame-buffer-busy?" ) ,
+ BI_FCODE_DEFER( 0x157, "draw-character" ) ,
+ BI_FCODE_DEFER( 0x158, "reset-screen" ) ,
+ BI_FCODE_DEFER( 0x159, "toggle-cursor" ) ,
+ BI_FCODE_DEFER( 0x15a, "erase-screen" ) ,
+ BI_FCODE_DEFER( 0x15b, "blink-screen" ) ,
+ BI_FCODE_DEFER( 0x15c, "invert-screen" ) ,
+ BI_FCODE_DEFER( 0x15d, "insert-characters" ) ,
+ BI_FCODE_DEFER( 0x15e, "delete-characters" ) ,
+ BI_FCODE_DEFER( 0x15f, "insert-lines" ) ,
+ BI_FCODE_DEFER( 0x160, "delete-lines" ) ,
+ BI_FCODE_DEFER( 0x161, "draw-logo" ) ,
+ BI_FCODE_VALUE( 0x162, "frame-buffer-adr" ) ,
+ BI_FCODE_VALUE( 0x163, "screen-height" ) ,
+ BI_FCODE_VALUE( 0x164, "screen-width" ) ,
+ BI_FCODE_VALUE( 0x165, "window-top" ) ,
+ BI_FCODE_VALUE( 0x166, "window-left" ) ,
+ BUILTIN_FCODE( 0x16a, "default-font" ) ,
+ BUILTIN_FCODE( 0x16b, "set-font" ) ,
+ BI_FCODE_VALUE( 0x16c, "char-height" ) ,
+ BI_FCODE_VALUE( 0x16d, "char-width" ) ,
+ BUILTIN_FCODE( 0x16e, ">font" ) ,
+ BI_FCODE_VALUE( 0x16f, "fontbytes" ) ,
+ OBSOLETE_FCODE( 0x170, "fb1-draw-character" ) ,
+ OBSOLETE_FCODE( 0x171, "fb1-reset-screen" ) ,
+ OBSOLETE_FCODE( 0x172, "fb1-toggle-cursor" ) ,
+ OBSOLETE_FCODE( 0x173, "fb1-erase-screen" ) ,
+ OBSOLETE_FCODE( 0x174, "fb1-blink-screen" ) ,
+ OBSOLETE_FCODE( 0x175, "fb1-invert-screen" ) ,
+ OBSOLETE_FCODE( 0x176, "fb1-insert-characters" ) ,
+ OBSOLETE_FCODE( 0x177, "fb1-delete-characters" ) ,
+ OBSOLETE_FCODE( 0x178, "fb1-insert-lines" ) ,
+ OBSOLETE_FCODE( 0x179, "fb1-delete-lines" ) ,
+ OBSOLETE_FCODE( 0x17a, "fb1-draw-logo" ) ,
+ OBSOLETE_FCODE( 0x17b, "fb1-install" ) ,
+ OBSOLETE_FCODE( 0x17c, "fb1-slide-up" ) ,
+ BUILTIN_FCODE( 0x180, "fb8-draw-character" ) ,
+ BUILTIN_FCODE( 0x181, "fb8-reset-screen" ) ,
+ BUILTIN_FCODE( 0x182, "fb8-toggle-cursor" ) ,
+ BUILTIN_FCODE( 0x183, "fb8-erase-screen" ) ,
+ BUILTIN_FCODE( 0x184, "fb8-blink-screen" ) ,
+ BUILTIN_FCODE( 0x185, "fb8-invert-screen" ) ,
+ BUILTIN_FCODE( 0x186, "fb8-insert-characters" ) ,
+ BUILTIN_FCODE( 0x187, "fb8-delete-characters" ) ,
+ BUILTIN_FCODE( 0x188, "fb8-insert-lines" ) ,
+ BUILTIN_FCODE( 0x189, "fb8-delete-lines" ) ,
+ BUILTIN_FCODE( 0x18a, "fb8-draw-logo" ) ,
+ BUILTIN_FCODE( 0x18b, "fb8-install" ) ,
+ OBSOLETE_FCODE( 0x1a0, "return-buffer" ) ,
+ OBSOLETE_FCODE( 0x1a1, "xmit-packet" ) ,
+ OBSOLETE_FCODE( 0x1a2, "poll-packet" ) ,
+ BUILTIN_FCODE( 0x1a4, "mac-address" ) ,
+ BUILTIN_FCODE( 0x201, "device-name" ) ,
+ BUILTIN_FCODE( 0x201, "name" ) , /* Synonym for "device-name" */
+ BUILTIN_FCODE( 0x202, "my-args" ) ,
+ BI_FCODE_VALUE( 0x203, "my-self" ) ,
+ BUILTIN_FCODE( 0x204, "find-package" ) ,
+ BUILTIN_FCODE( 0x205, "open-package" ) ,
+ BUILTIN_FCODE( 0x206, "close-package" ) ,
+ BUILTIN_FCODE( 0x207, "find-method" ) ,
+ BUILTIN_FCODE( 0x208, "call-package" ) ,
+ BUILTIN_FCODE( 0x209, "$call-parent" ) ,
+ BUILTIN_FCODE( 0x20a, "my-parent" ) ,
+ BUILTIN_FCODE( 0x20b, "ihandle>phandle" ) ,
+ BUILTIN_FCODE( 0x20d, "my-unit" ) ,
+ BUILTIN_FCODE( 0x20e, "$call-method" ) ,
+ BUILTIN_FCODE( 0x20f, "$open-package" ) ,
+ OBSOLETE_FCODE( 0x210, "processor-type" ) ,
+ OBSOLETE_FCODE( 0x211, "firmware-version" ) ,
+ OBSOLETE_FCODE( 0x212, "fcode-version" ) ,
+ BUILTIN_FCODE( 0x213, "alarm" ) ,
+ BUILTIN_FCODE( 0x214, "(is-user-word)" ) ,
+ BUILTIN_FCODE( 0x215, "suspend-fcode" ) ,
+ BUILTIN_FCODE( 0x216, "abort" ) ,
+ BUILTIN_FCODE( 0x217, "catch" ) ,
+ BUILTIN_FCODE( 0x218, "throw" ) ,
+ BUILTIN_FCODE( 0x219, "user-abort" ) ,
+ BUILTIN_FCODE( 0x21a, "get-my-property" ) ,
+ BUILTIN_FCODE( 0x21a, "get-my-attribute" ) , /* Synonym for "get-my-property" */
+ BUILTIN_FCODE( 0x21b, "decode-int" ) ,
+ BUILTIN_FCODE( 0x21b, "xdrtoint" ) , /* Synonym for "decode-int" */
+ BUILTIN_FCODE( 0x21c, "decode-string" ) ,
+ BUILTIN_FCODE( 0x21c, "xdrtostring" ), /* Synonym for "decode-string" */
+ BUILTIN_FCODE( 0x21d, "get-inherited-property" ) ,
+ BUILTIN_FCODE( 0x21d, "get-inherited-attribute" ) , /* Synonym for "get-inherited-property" */
+ BUILTIN_FCODE( 0x21e, "delete-property" ) ,
+ BUILTIN_FCODE( 0x21e, "delete-attribute" ) , /* Synonym for "delete-property" */
+ BUILTIN_FCODE( 0x21f, "get-package-property" ) ,
+ BUILTIN_FCODE( 0x21f, "get-package-attribute" ) , /* Synonym for "get-package-property" */
+ BUILTIN_FCODE( 0x220, "cpeek" ) ,
+ BUILTIN_FCODE( 0x221, "wpeek" ) ,
+ BUILTIN_FCODE( 0x222, "lpeek" ) ,
+ BUILTIN_FCODE( 0x223, "cpoke" ) ,
+ BUILTIN_FCODE( 0x224, "wpoke" ) ,
+ BUILTIN_FCODE( 0x225, "lpoke" ) ,
+ BUILTIN_FCODE( 0x226, "lwflip" ) ,
+ BUILTIN_FCODE( 0x227, "lbflip" ) ,
+ BUILTIN_FCODE( 0x228, "lbflips" ) ,
+ OBSOLETE_FCODE( 0x229, "adr-mask" ) ,
+ BUILTIN_FCODE( 0x230, "rb@" ) ,
+ BUILTIN_FCODE( 0x231, "rb!" ) ,
+ BUILTIN_FCODE( 0x232, "rw@" ) ,
+ BUILTIN_FCODE( 0x233, "rw!" ) ,
+ BUILTIN_FCODE( 0x234, "rl@" ) ,
+ BUILTIN_FCODE( 0x235, "rl!" ) ,
+ BUILTIN_FCODE( 0x236, "wbflips" ) ,
+ BUILTIN_FCODE( 0x236, "wflips" ) , /* Synonym for "wbflips" */
+ BUILTIN_FCODE( 0x237, "lwflips" ) ,
+ BUILTIN_FCODE( 0x237, "lflips" ) , /* Synonym for "lwflips" */
+ OBSOLETE_FCODE( 0x238, "probe" ) ,
+ OBSOLETE_FCODE( 0x239, "probe-virtual" ) ,
+ BUILTIN_FCODE( 0x23b, "child" ) ,
+ BUILTIN_FCODE( 0x23c, "peer" ) ,
+ BUILTIN_FCODE( 0x23d, "next-property" ) ,
+ BUILTIN_FCODE( 0x23e, "byte-load" ) ,
+ BUILTIN_FCODE( 0x23f, "set-args" ) ,
+ BUILTIN_FCODE( 0x240, "left-parse-string" ) ,
+
/* FCodes from 64bit extension addendum */
- add_token( 0x22e, "rx@" );
- add_token( 0x22f, "rx!" );
- add_token( 0x241, "bxjoin" );
- add_token( 0x242, "<l@" );
- add_token( 0x243, "lxjoin" );
- add_token( 0x244, "wxjoin" );
- add_token( 0x245, "x," );
- add_token( 0x246, "x@" );
- add_token( 0x247, "x!" );
- add_token( 0x248, "/x" );
- add_token( 0x249, "/x*" );
- add_token( 0x24a, "xa+" );
- add_token( 0x24b, "xa1+" );
- add_token( 0x24c, "xbflip" );
- add_token( 0x24d, "xbflips" );
- add_token( 0x24e, "xbsplit" );
- add_token( 0x24f, "xlflip" );
- add_token( 0x250, "xlflips" );
- add_token( 0x251, "xlsplit" );
- add_token( 0x252, "xwflip" );
- add_token( 0x253, "xwflips" );
- add_token( 0x254, "xwsplit" );
+ BUILTIN_FCODE( 0x22e, "rx@" ) ,
+ BUILTIN_FCODE( 0x22f, "rx!" ) ,
+ BUILTIN_FCODE( 0x241, "bxjoin" ) ,
+ BUILTIN_FCODE( 0x242, "<l@" ) ,
+ BUILTIN_FCODE( 0x243, "lxjoin" ) ,
+ BUILTIN_FCODE( 0x244, "wxjoin" ) ,
+ BUILTIN_FCODE( 0x245, "x," ) ,
+ BUILTIN_FCODE( 0x246, "x@" ) ,
+ BUILTIN_FCODE( 0x247, "x!" ) ,
+ BUILTIN_FCODE( 0x248, "/x" ) ,
+ BUILTIN_FCODE( 0x249, "/x*" ) ,
+ BUILTIN_FCODE( 0x24a, "xa+" ) ,
+ BUILTIN_FCODE( 0x24b, "xa1+" ) ,
+ BUILTIN_FCODE( 0x24c, "xbflip" ) ,
+ BUILTIN_FCODE( 0x24d, "xbflips" ) ,
+ BUILTIN_FCODE( 0x24e, "xbsplit" ) ,
+ BUILTIN_FCODE( 0x24f, "xlflip" ) ,
+ BUILTIN_FCODE( 0x250, "xlflips" ) ,
+ BUILTIN_FCODE( 0x251, "xlsplit" ) ,
+ BUILTIN_FCODE( 0x252, "xwflip" ) ,
+ BUILTIN_FCODE( 0x253, "xwflips" ) ,
+ BUILTIN_FCODE( 0x254, "xwsplit" )
+};
- add_special(COLON, ":");
- add_special(SEMICOLON, ";");
- add_special(TOKENIZE, "'");
- add_special(AGAIN, "again");
- add_special(ALIAS, "alias");
- add_special(GETTOKEN, "[']");
- add_special(ASCII, "ascii");
- add_special(BEGIN, "begin");
- add_special(BUFFER, "buffer:");
- add_special(CASE, "case");
- add_special(CONST, "constant");
- add_special(CONTROL, "control");
- add_special(CREATE, "create");
- add_special(DECIMAL, "decimal");
- add_special(DEFER, "defer");
- add_special(CDO, "?do");
- add_special(DO, "do");
- add_special(ELSE, "else");
- add_special(ENDCASE, "endcase");
- add_special(ENDOF, "endof");
- add_special(EXTERNAL, "external");
- add_special(FIELD, "field");
- add_special(HEADERLESS, "headerless");
- add_special(HEADERS, "headers");
- add_special(HEX, "hex");
- add_special(IF, "if");
- add_special(CLEAVE, "?leave");
- add_special(LEAVE, "leave");
- add_special(CLOOP, "+loop");
- add_special(LOOP, "loop");
- add_special(OCTAL, "octal");
- add_special(OF, "of");
- add_special(REPEAT, "repeat");
- add_special(THEN, "then");
- add_special(TO, "to");
- add_special(UNTIL, "until");
- add_special(VALUE, "value");
- add_special(VARIABLE, "variable");
- add_special(WHILE, "while");
- add_special(OFFSET16, "offset16");
- add_special(BEGINTOK, "tokenizer[");
- add_special(EMITBYTE, "emit-byte");
- add_special(ENDTOK, "]tokenizer");
- add_special(FLOAD, "fload");
- add_special(STRING, "\"");
- add_special(PSTRING, ".\"");
- add_special(PBSTRING, ".(");
- add_special(SSTRING, "s\"");
- add_special(RECURSIVE, "recursive");
- add_special(NEXTFCODE, "next-fcode");
+static const int number_of_builtin_tokens =
+ sizeof(tokens_table)/sizeof(tic_hdr_t);
+
+/* **************************************************************************
+ *
+ * Support functions specific to the FCode-Tokens list.
+ *
+ **************************************************************************** */
+
+
+/* **************************************************************************
+ *
+ * Function name: emit_token
+ * Synopsis: Emit the FCode token for the given FCode name.
+ *
+ * Inputs:
+ * Parameters:
+ * fc_name The name of the FCode
+ * Local Static Variables:
+ * fc_tokens_list_start "Tail" of the "FC-Tokens" list
+ *
+ * Outputs:
+ * Returned Value: NONE
+ *
+ * Error Detection:
+ * This routine should only be called with hard-coded names from
+ * within the program. If the given name is not found in
+ * the Built-in Tokens Table, that is a FATAL error.
+ *
+ * Process Explanation:
+ * Because the "FCode-Tokens" table was linked first, and the
+ * pointer kept for this purpose, the "FC-Tokens" list can
+ * be a subset of the "core" list, yet, when necessary, can
+ * be searched with the same routines.
+ *
+ * Extraneous Remarks:
+ * I will bend the strict rules of well-structured code;
+ * the exception case should never occur.
+ *
+ **************************************************************************** */
+
+void emit_token( const char *fc_name)
+{
+
+ if ( handle_tic_vocab( (char *)fc_name, fc_tokens_list_start) )
+ {
+ return;
+ }
+
+ tokenization_error( FATAL, "Did not recognize FCode name %s", fc_name);
+}
+
+
+/* **************************************************************************
+ *
+ * Function name: lookup_token
+ * Synopsis: Return a pointer to the data-structure of the named
+ * word in the "FC-Tokens" list
+ *
+ * Inputs:
+ * Parameters:
+ * tname The name to look up
+ * Local Static Variables:
+ * fc_tokens_list_start "Tail" of the "FC-Tokens" list
+ *
+ * Outputs:
+ * Returned Value: Pointer to the data-structure, or
+ * NULL if not found.
+ *
+ **************************************************************************** */
+
+tic_hdr_t *lookup_token( char *tname)
+{
+ tic_hdr_t *found ;
+
+ found = lookup_tic_entry( tname, fc_tokens_list_start);
+ return ( found ) ;
+}
+
+/* **************************************************************************
+ *
+ * Function name: entry_is_token
+ * Synopsis: Indicate whether the supplied pointer to a tic_hdr_t
+ * data-structure is one for which a single-token FCode
+ * number is assigned.
+ *
+ * Inputs:
+ * Parameters:
+ * test_entry The entry to test; may be NULL
+ * Local macros:
+ * FC_TOKEN_FUNC The function associated with
+ * most single-token entries.
+ * OBSO_FC_FUNC The function associated with
+ * "obsolete" FCode tokens.
+ *
+ * Outputs:
+ * Returned Value: TRUE if the data-structure is
+ * a single-token entry.
+ *
+ * Process Explanation:
+ * We cannot rely on the "definer" field to indicate whether
+ * it is a single-token entry; instead, we will look at
+ * the associated function.
+ * Keep this routine here to avoid needing to export the names
+ * of the permitted functions or their synonymous macros.
+ * If we ever need to change it, we can do so at a single
+ * point of maintenance.
+ * Because the entry might have been found in the initial list
+ * of entries to the "FCode-Tokens" list, we need to check
+ * whether the associated function is either the general
+ * single-token emitting function, FC_TOKEN_FUNC , or the
+ * function OBSO_FC_FUNC , which presents a message before
+ * emitting, but is still a valid single-token function.
+ *
+ **************************************************************************** */
+
+bool entry_is_token( tic_hdr_t *test_entry )
+{
+ bool retval = FALSE;
+ if ( test_entry != NULL )
+ {
+ if ( ( test_entry->funct == FC_TOKEN_FUNC ) ||
+ ( test_entry->funct == OBSO_FC_FUNC ) )
+ {
+ retval = TRUE;
+ }
+ }
+ return ( retval );
+}
+
+/* **************************************************************************
+ *
+ * Function name: token_entry_warning
+ * Synopsis: Issue whatever warnings the given token_entry
+ * requires. F['] needs this.
+ * Inputs:
+ * Parameters:
+ * test_entry The entry to test; may be NULL
+ * Local macro:
+ * OBSO_FC_FUNC The function associated with
+ * "obsolete" entries.
+ * Outputs:
+ * Returned Value: NONE
+ *
+ * Error Detection:
+ * Warnings required by the given token_entry.
+ *
+ * Extraneous Remarks:
+ * At present, it's only the "Obsolete" warning.
+ * But this is the place to add others,
+ * should they become necessary.
+ *
+ **************************************************************************** */
+
+void token_entry_warning( tic_hdr_t *t_entry)
+{
+ if ( t_entry->funct == OBSO_FC_FUNC )
+ {
+ obsolete_warning();
+ }
+}
+
+
+/* **************************************************************************
+ *
+ * Create the initial "FWords" list.
+ *
+ **************************************************************************** */
+
+static tic_fwt_hdr_t fwords_list[] = {
+
+ BI_FWD_SKP_OW(COLON, ":") ,
+ BUILTIN_FWORD(SEMICOLON, ";") ,
+ BI_FWD_SKP_OW(TICK, "'") ,
+ BUILTIN_FWORD(AGAIN, "again") ,
+ BI_FWD_SKP_OW(BRACK_TICK, "[']") ,
+ BI_FWD_SKP_OW(ASCII, "ascii") ,
+ BUILTIN_FWORD(BEGIN, "begin") ,
+ BI_FWD_SKP_OW(BUFFER, "buffer:") ,
+ BUILTIN_FWORD(CASE, "case") ,
+ BI_FWD_SKP_OW(CONST, "constant") ,
+ BI_FWD_SKP_OW(CONTROL, "control") ,
+ BI_FWD_SKP_OW(CREATE, "create") ,
+
+ BI_FWD_SKP_OW(DEFER, "defer") ,
+ BUILTIN_FWORD(CDO, "?do") ,
+ BUILTIN_FWORD(DO, "do") ,
+ BUILTIN_FWORD(ELSE, "else") ,
+ BUILTIN_FWORD(ENDCASE, "endcase") ,
+ BUILTIN_FWORD(ENDOF, "endof") ,
+ BUILTIN_FWORD(EXTERNAL, "external") ,
+ BI_FWD_SKP_OW(FIELD, "field") ,
+ BUILTIN_FWORD(FINISH_DEVICE, "finish-device" ) ,
+ BUILTIN_FWORD(HEADERLESS, "headerless") ,
+ BUILTIN_FWORD(HEADERS, "headers") ,
+
+ BUILTIN_FWORD(INSTANCE , "instance") ,
+
+ BUILTIN_FWORD(IF, "if") ,
+ BUILTIN_FWORD(UNLOOP, "unloop") ,
+ BUILTIN_FWORD(LEAVE, "leave") ,
+ BUILTIN_FWORD(PLUS_LOOP, "+loop") ,
+ BUILTIN_FWORD(LOOP, "loop") ,
+
+ BUILTIN_FWORD(OF, "of") ,
+ BUILTIN_FWORD(REPEAT, "repeat") ,
+ BUILTIN_FWORD(THEN, "then") ,
+ BI_FWD_SKP_OW(TO, "to") ,
+ BI_FWD_SKP_OW(IS, "is") , /* Deprecated synonym to TO */
+ BUILTIN_FWORD(UNTIL, "until") ,
+ BI_FWD_SKP_OW(VALUE, "value") ,
+ BI_FWD_SKP_OW(VARIABLE, "variable") ,
+ BUILTIN_FWORD(WHILE, "while") ,
+ BUILTIN_FWORD(OFFSET16, "offset16") ,
+
+ BI_FWD_STRING(STRING, "\"") , /* XXXXX */
+ BI_FWD_STRING(PSTRING, ".\"") , /* XXXXX */
+ BI_FWD_STRING(PBSTRING, ".(") , /* XXXXX */
+ BI_FWD_STRING(SSTRING, "s\"") , /* XXXXX */
+ BUILTIN_FWORD(IFILE_NAME, "[input-file-name]"),
+ BUILTIN_FWORD(ILINE_NUM, "[line-number]"),
+ BUILTIN_FWORD(RECURSE, "recurse") ,
+ BUILTIN_FWORD(RECURSIVE, "recursive") ,
+ BUILTIN_FWORD(RET_STK_FETCH, "r@") ,
+ BUILTIN_FWORD(RET_STK_FROM, "r>") ,
+ BUILTIN_FWORD(RET_STK_TO, ">r") ,
+ BUILTIN_FWORD(THEN, "endif" ) , /* Synonym for "then" */
+ BUILTIN_FWORD(NEW_DEVICE, "new-device" ) ,
+ BUILTIN_FWORD(LOOP_I, "i") ,
+ BUILTIN_FWORD(LOOP_J, "j") ,
/* version1 is also an fcode word, but it
* needs to trigger some tokenizer internals */
- add_special(VERSION1, "version1");
- add_special(START0, "start0");
- add_special(START1, "start1");
- add_special(START2, "start2");
- add_special(START4, "start4");
- add_special(END0, "end0");
- add_special(END1, "end1");
- add_special(FCODE_V1, "fcode-version1");
- add_special(FCODE_V2, "fcode-version2");
- add_special(FCODE_V3, "fcode-version3");
- add_special(FCODE_END, "fcode-end");
- add_special(FCODE_DATE, "fcode-date");
- add_special(FCODE_TIME, "fcode-time");
-
- add_special(HEXVAL, "h#");
- add_special(DECVAL, "d#");
- add_special(OCTVAL, "o#");
- add_special(CHAR, "char");
- add_special(CCHAR, "[char]");
- add_special(ABORTTXT, "abort\"");
+ BUILTIN_FWORD(VERSION1, "version1") ,
+ BUILTIN_FWORD(START0, "start0") ,
+ BUILTIN_FWORD(START1, "start1") ,
+ BUILTIN_FWORD(START2, "start2") ,
+ BUILTIN_FWORD(START4, "start4") ,
+ BUILTIN_FWORD(END0, "end0") ,
+ BUILTIN_FWORD(END1, "end1") ,
+ BUILTIN_FWORD(FCODE_V1, "fcode-version1") ,
+ BUILTIN_FWORD(FCODE_V2, "fcode-version2") ,
+ BUILTIN_FWORD(FCODE_V3, "fcode-version3") ,
+ BUILTIN_FWORD(FCODE_END, "fcode-end") ,
- add_special(ENCODEFILE, "encode-file");
+ /* Support for IBM-style Locals */
+ BI_FWD_STRING(CURLY_BRACE, "{") ,
+ BI_FWD_STRING(DASH_ARROW, "->") ,
+ BUILTIN_FWORD(EXIT, "exit") ,
+
+ BUILTIN_FWORD(CHAR, "char") ,
+ BUILTIN_FWORD(CCHAR, "[char]") ,
+ BI_FWD_STRING(ABORTTXT, "abort\"") ,
+
+ BUILTIN_FWORD(ENCODEFILE, "encode-file") ,
+
+ BI_IG_FW_HDLR(ESCAPETOK, "tokenizer[") ,
+ BI_IG_FW_HDLR(ESCAPETOK, "f[") , /* An IBM-ish synonym */
+};
+
+static const int number_of_builtin_fwords =
+ sizeof(fwords_list)/sizeof(tic_hdr_t);
+
+/* **************************************************************************
+ *
+ * Create the initial list of "Shared_Words" (words that can
+ * be executed similarly both during normal tokenization,
+ * and also within "Tokenizer Escape Mode").
+ *
+ **************************************************************************** */
+
+static tic_fwt_hdr_t shared_words_list[] = {
+ SHARED_FWORD(FLOAD, "fload") ,
+ /* As does the "Allow Multi-Line" directive */
+ SHR_SAMIG_FWRD(ALLOW_MULTI_LINE, "multi-line") ,
+
+ SHR_FWD_SKOW( F_BRACK_TICK, "f[']") ,
+
+ SH_FW_SK2WIL(ALIAS, "alias") ,
+ SHARED_FWORD(DECIMAL, "decimal") ,
+ SHARED_FWORD(HEX, "hex") ,
+ SHARED_FWORD(OCTAL, "octal") ,
+ SH_FW_SK_WIL(HEXVAL, "h#") ,
+ SH_FW_SK_WIL(DECVAL, "d#") ,
+ SH_FW_SK_WIL(OCTVAL, "o#") ,
+
+ SH_FW_SK_WIL(ASC_NUM, "a#") ,
+ SH_FW_SK_WIL(ASC_LEFT_NUM, "al#") ,
+
+ /* IBM-style extension. Might be generalizable... */
+ SHARED_FWORD(FLITERAL, "fliteral") ,
+
+ /* Directives to extract the value of a Command-Line symbol */
+ SH_FW_SK_WIL(DEFINED, "[defined]") ,
+ SH_FW_SK_WIL(DEFINED, "#defined") ,
+ SH_FW_SK_WIL(DEFINED, "[#defined]") ,
+
+ /* Present the current date or time, either as an */
+ /* in-line string or as a user-generated message. */
+ SHARED_FWORD(FCODE_DATE, "[fcode-date]") ,
+ SHARED_FWORD(FCODE_TIME, "[fcode-time]") ,
+
+ /* Current definition under construction, similarly */
+ SHARED_FWORD(FUNC_NAME, "[function-name]"),
+
+ /* Synonymous forms of the #ELSE and #THEN operators,
+ * associated with Conditional-Compilation,
+ * allowing for various syntax-styles, and for
+ * expansion by alias.
+ */
+
+ /* #ELSE operators */
+ SHARED_FWORD(CONDL_ELSE, "#else") ,
+ SHARED_FWORD(CONDL_ELSE, "[else]") ,
+ SHARED_FWORD(CONDL_ELSE, "[#else]") ,
+
+ /* #THEN operators */
+ SHARED_FWORD(CONDL_ENDER, "#then") ,
+ SHARED_FWORD(CONDL_ENDER, "[then]") ,
+ SHARED_FWORD(CONDL_ENDER, "[#then]") ,
+ /* #ENDIF variants for users who favor C-style notation */
+ SHARED_FWORD(CONDL_ENDER, "#endif") ,
+ SHARED_FWORD(CONDL_ENDER, "[endif]") ,
+ SHARED_FWORD(CONDL_ENDER, "[#endif]") ,
+
+
+ SHARED_FWORD(OVERLOAD, "overload" ) ,
+
+ SHARED_FWORD(GLOB_SCOPE , "global-definitions" ) ,
+ SHARED_FWORD(DEV_SCOPE , "device-definitions" ) ,
+
+ /* Directives to change a command-line flag value from source */
+ SH_FW_SK_WIL(CL_FLAG, "[FLAG]") ,
+ SH_FW_SK_WIL(CL_FLAG, "#FLAG") ,
+ SH_FW_SK_WIL(CL_FLAG, "[#FLAG]") ,
+
+ /* Directives to force display of a command-line flags' values */
+ SHARED_FWORD(SHOW_CL_FLAGS, "[FLAGS]") ,
+ SHARED_FWORD(SHOW_CL_FLAGS, "#FLAGS") ,
+ SHARED_FWORD(SHOW_CL_FLAGS, "[#FLAGS]") ,
+ SHARED_FWORD(SHOW_CL_FLAGS, "SHOW-FLAGS") ,
+
+ /* Directives to save and retrieve the FCode Assignment number */
+ SHARED_FWORD(PUSH_FCODE, "FCODE-PUSH") ,
+ SHARED_FWORD(POP_FCODE, "FCODE-POP") ,
+
+ /* Directive to reset the FCode Assignment number and
+ * re-initialize FCode Range overlap checking.
+ */
+ SHARED_FWORD(RESET_FCODE, "FCODE-RESET") ,
+
/* pci header generation is done differently
* across the available tokenizers. We try to
* be compatible to all of them
*/
- add_special(PCIHDR, "pci-header");
- add_special(PCIEND, "pci-end"); /* SUN syntax */
- add_special(PCIEND, "pci-header-end"); /* Firmworks syntax */
- add_special(PCIREV, "pci-revision"); /* SUN syntax */
- add_special(PCIREV, "pci-code-revision"); /* SUN syntax */
- add_special(PCIREV, "set-rev-level"); /* Firmworks syntax */
- add_special(NOTLAST, "not-last-image");
+ SHARED_FWORD(PCIHDR, "pci-header") ,
+ SHARED_FWORD(PCIEND, "pci-end") , /* SUN syntax */
+ SHARED_FWORD(PCIEND, "pci-header-end") , /* Firmworks syntax */
+ SHARED_FWORD(PCIREV, "pci-revision") , /* SUN syntax */
+ SHARED_FWORD(PCIREV, "pci-code-revision") , /* SUN syntax */
+ SHARED_FWORD(PCIREV, "set-rev-level") , /* Firmworks syntax */
+ SHARED_FWORD(NOTLAST, "not-last-image") ,
+ SHARED_FWORD(NOTLAST, "not-last-img") , /* Shorthand form */
+ SHARED_FWORD(ISLAST, "last-image") ,
+ SHARED_FWORD(ISLAST, "last-img") , /* Shorthand form */
+ SHARED_FWORD(SETLAST, "set-last-image") ,
+ SHARED_FWORD(SETLAST, "set-last-img") , /* Shorthand form */
+
+ SH_FW_SK_WIL(SAVEIMG, "save-image") ,
+ SH_FW_SK_WIL(SAVEIMG, "save-img") , /* Shorthand form */
+
+ SHARED_FWORD(RESETSYMBS, "reset-symbols") ,
+
+ /* User-Macro definers */
+ SHARED_IG_HDLR("[MACRO]", add_user_macro, 0 , skip_user_macro) ,
+
+ /* Comments and Remarks */
+ SHARED_IG_HDLR("\\", process_remark, '\n', process_remark) ,
+ SHARED_IG_HDLR("(", process_remark, ')', process_remark) ,
+
+ /* Directives to print or discard a user-generated message */
+ SHARED_IG_HDLR("[MESSAGE]", user_message, '\n', skip_user_message) ,
+ SHARED_IG_HDLR("#MESSAGE", user_message, '\n', skip_user_message) ,
+ SHARED_IG_HDLR("[#MESSAGE]", user_message, '\n', skip_user_message) ,
+ SHARED_IG_HDLR("#MESSAGE\"", user_message, '"' , skip_user_message) ,
+};
+
+static const int number_of_shared_words =
+ sizeof(shared_words_list)/sizeof(tic_hdr_t);
+
+/* **************************************************************************
+ *
+ * Function name: lookup_shared_word
+ * Synopsis: Return a pointer to the data-structure of the named
+ * word, only if it is a "Shared Word"
+ *
+ * Inputs:
+ * Parameters:
+ * tname The name to look for
+ * Local Static Variables:
+ * global_voc_dict_ptr "Tail" of Global Vocabulary
+ *
+ * Outputs:
+ * Returned Value: Pointer to the data-structure, or
+ * NULL if not found.
+ *
+ * Process Explanation:
+ * The "Shared Words" are scattered among the Global Vocabulary;
+ * the user is allowed to create aliases, which may be in the
+ * Current-Device. We will search through the "current" scope
+ * and decide whether the name we found is a "Shared Word" by
+ * looking for COMMON_FWORD in the "definer" field.
+ *
+ * Extraneous Remarks:
+ * This is the only place where an additional check of the
+ * "definer" field is required to identify a desired entry.
+ * Should another "definer"-type be required, I recommend
+ * defining a general-purpose function in ticvocab.c and
+ * applying it here and in the other place(s).
+ *
+ **************************************************************************** */
+
+tic_hdr_t *lookup_shared_word( char *tname)
+{
+ tic_hdr_t *found ;
+ tic_hdr_t *retval = NULL ;
+
+ found = lookup_current( tname );
+ if ( found != NULL )
+ {
+ if ( found->fword_defr == COMMON_FWORD )
+ {
+ retval = found ;
+ }
+ }
+
+ return ( retval );
+
}
+
+/* **************************************************************************
+ *
+ * Function name: handle_shared_word
+ * Synopsis: Perform the function associated with the given name
+ * only if it is a "Shared Word". Indicate if it was.
+ *
+ * Inputs:
+ * Parameters:
+ * tname The "target" name for which to look
+ *
+ * Outputs:
+ * Returned Value: TRUE if the name is a valid "Shared Word"
+ *
+ * Extraneous Remarks:
+ * This is very similar to a call to handle_tic_vocab() except
+ * for the additional filtering for a "Shared Word" definer.
+ *
+ **************************************************************************** */
+
+bool handle_shared_word( char *tname )
+{
+ tic_hdr_t *found ;
+ bool retval = FALSE;
+
+ found = lookup_shared_word( tname );
+ if ( found != NULL )
+ {
+ found->funct(found->pfield);
+ retval = TRUE;
+ }
+
+ return ( retval ) ;
+}
+
+
+/* **************************************************************************
+ *
+ * Function name: lookup_shared_f_exec_word
+ * Synopsis: Return a pointer to the data-structure of the named
+ * word, only if it is a "Shared F-Exec Word"
+ *
+ * Inputs:
+ * Parameters:
+ * tname The name to look for
+ * Local Static Variables:
+ * global_voc_dict_ptr "Tail" of Global Vocabulary
+ * Macro Definitions:
+ * FWORD_EXEC_FUNC The "Active" function of the
+ * sub-class of "Shared Word"s
+ * that is the object of this
+ * routine's search
+ *
+ * Outputs:
+ * Returned Value: Pointer to the data-structure, or
+ * NULL if not found.
+ *
+ * Process Explanation:
+ * The "Shared F-Exec Words" are the subset of "Shared Words" that
+ * have the FWORD_EXEC_FUNC as their "Active" function.
+ *
+ * Extraneous Remarks:
+ * This is the only routine that requires a check of two fields;
+ * it seems unlikely that there will be any need to generalize
+ * the core of this routine...
+ *
+ **************************************************************************** */
+
+tic_hdr_t *lookup_shared_f_exec_word( char *tname)
+{
+ tic_hdr_t *found ;
+ tic_hdr_t *retval = NULL ;
+
+ found = lookup_shared_word( tname );
+ if ( found != NULL )
+ {
+ if ( found->funct == FWORD_EXEC_FUNC )
+ {
+ retval = found ;
+ }
+ }
+
+ return ( retval );
+
+}
+
+/* **************************************************************************
+ *
+ * Function name: init_dictionary
+ * Synopsis: Initialize all the vocabularies. For the Global
+ * Vocabulary, fill in the link fields in each of the
+ * otherwise pre-initialized built-in lists, link the
+ * lists together, and set the relevant pointers. For
+ * other lists, call their initialization routines.
+ *
+ * Inputs:
+ * Parameters: NONE
+ * Global Variables:
+ * Local Static Variables:
+ * tokens_table Base of the "FC-Tokens" list
+ * number_of_builtin_tokens Number of "FC-Token" entries
+ * fwords_list Base of the "FWords" list
+ * number_of_builtin_fwords Number of "FWord" entries
+ * shared_words_list Base of the "Shared Words" list
+ * number_of_shared_words Number of "Shared Words" entries
+ *
+ * Outputs:
+ * Returned Value: NONE
+ * Local Static Variables:
+ * global_voc_dict_ptr "Tail" of Global Vocabulary
+ * fc_tokens_list_start "Tail" of "FC-Tokens" list
+ * fc_tokens_list_ender End of "FC-Tokens" search
+ * shared_fwords_ender End of Shared Words" search
+ * global_voc_reset_ptr Reset-point for Global Vocab
+ *
+ * Process Explanation:
+ * The first linked will be the last searched.
+ * Link the "FC-Tokens" first, and mark their limits
+ * Link the "FWords" next,
+ * Mark the end-limit of the "Shared Words", and link them
+ * The "Conditionals", defined in another file, are also "Shared";
+ * link them next.
+ * Then link the Built-In Macros, also defined in another file.
+ * These constitute the Global Vocabulary.
+ * Mark the reset-point for the Global Vocabulary.
+ * The "Tokenizer Escape" mode vocabulary is not linked to the Global
+ * Vocabulary; call its initialization routine.
+ *
+ * Extraneous Remarks:
+ * I only wish I had done this sooner...
+ *
+ **************************************************************************** */
+
+void init_dictionary( void )
+{
+
+ global_voc_dict_ptr = NULL; /* Belt-and-suspenders... */
+
+ /* The "FC-Tokens" list must be linked first. */
+ fc_tokens_list_ender = global_voc_dict_ptr;
+ init_tic_vocab( tokens_table,
+ number_of_builtin_tokens,
+ &global_voc_dict_ptr ) ;
+ fc_tokens_list_start = global_voc_dict_ptr;
+
+ /* Link the "FWords" next */
+ init_tic_vocab( (tic_hdr_t *)fwords_list,
+ number_of_builtin_fwords,
+ &global_voc_dict_ptr ) ;
+
+ /* Mark the end-limit of the "Shared Words", and link them. */
+ shared_fwords_ender = global_voc_dict_ptr;
+ init_tic_vocab( (tic_hdr_t *)shared_words_list,
+ number_of_shared_words,
+ &global_voc_dict_ptr ) ;
+
+ /* Link the "Conditionals" to the Global Vocabulary. */
+ init_conditionals_vocab( &global_voc_dict_ptr ) ;
+
+ /* Link the Built-In Macros */
+ init_macros( &global_voc_dict_ptr ) ;
+
+ /* Mark the reset-point for the Global Vocabulary. */
+ global_voc_reset_ptr = global_voc_dict_ptr;
+
+ /* Initialize the "Tokenizer Escape" mode vocabulary */
+ init_tokz_esc_vocab();
+
+ /* Locals and Device-Node vocabularies are initially empty */
+
+}
+
+/* **************************************************************************
+ *
+ * Function name: reset_normal_vocabs
+ * Synopsis: Reset the vocabularies that were created in "Normal"
+ * (as distinguished from "Tokenizer Escape") mode
+ * to the proper state for a fresh tokenization.
+ *
+ * Associated FORTH words: END0 END1
+ * Associated Tokenizer directives: RESET-SYMBOLS (in "Normal" mode)
+ * FCODE-END
+ *
+ * Inputs:
+ * Parameters: NONE
+ * Global Variables:
+ * global_voc_reset_ptr Position to which to reset
+ * the "Global" Vocabulary
+ * current_device_node Vocab struct of current dev-node
+ *
+ * Outputs:
+ * Returned Value: NONE
+ * Global Variables:
+ * global_voc_dict_ptr Reset to "Built-In" position
+ * current_device_node Reset to point at "root" dev-node
+ * Memory Freed
+ * All memory allocated by user-definitions in "normal" mode
+ * -- Macros, Conditionals and Device-node Vocabularies -- are
+ * reset via function call.
+ *
+ * Error Detection:
+ * Presence of extra device-node data structure(s) indicates that
+ * there were more "new-device" calls than "finish-device";
+ * report each as an ERROR
+ *
+ * Process Explanation:
+ * Vocabularies created in other files, that have different
+ * data-structures, will have "reset" routines of their
+ * own associated with them in the files in which they
+ * are created. Those routines will be called from here.
+ * Definitions in the "Tokenizer Escape Vocabulary", i.e.,
+ * the one in effect in "Tokenizer Escape" mode, are
+ * specifically not touched by this routine.
+ *
+ **************************************************************************** */
+
+void reset_normal_vocabs( void )
+{
+ reset_tic_vocab( &global_voc_dict_ptr, global_voc_reset_ptr );
+
+ /* Delete the top-level device-node vocab.
+ * If there are extra device-nodes,
+ * delete their data structures and show errors
+ */
+ do
+ {
+ if ( current_device_node->parent_node != NULL )
+ {
+ tokenization_error( TKERROR,
+ "Missing FINISH-DEVICE for new device");
+ started_at( current_device_node->ifile_name,
+ current_device_node->line_no );
+ }
+ delete_device_vocab();
+ } while ( current_device_node->parent_node != NULL );
+
+}
+
+
+/* **************************************************************************
+ *
+ * Function name: reset_vocabs
+ * Synopsis: Reset all the vocabularies to the proper state
+ * for beginning a fresh tokenization, particularly
+ * when multiple files are named on the command-line
+ *
+ * Inputs:
+ * Parameters: NONE
+ *
+ * Outputs:
+ * Returned Value: NONE
+ * Memory Freed
+ * All memory allocated by user-definitions will be freed
+ *
+ * Process Explanation:
+ * Call the reset_normal_vocabs() routine to get the vocabularies
+ * that apply to "Normal" mode, then call the "reset" routine
+ * for the "Tokenizer Escape Vocabulary", which is supposed
+ * to persist across device-nodes but not across input-files
+ * named on the command-line.
+ *
+ **************************************************************************** */
+
+void reset_vocabs( void )
+{
+ reset_normal_vocabs();
+ reset_tokz_esc();
+}
Modified: fcode-utils/toke/dictionary.h
===================================================================
--- fcode-utils/toke/dictionary.h 2006-08-18 09:45:11 UTC (rev 75)
+++ fcode-utils/toke/dictionary.h 2006-08-18 12:47:12 UTC (rev 76)
@@ -1,3 +1,6 @@
+#ifndef _TOKE_DICTIONARY_H
+#define _TOKE_DICTIONARY_H
+
/*
* OpenBIOS - free your system!
* ( FCode tokenizer )
@@ -24,81 +27,152 @@
*
*/
-#define COLON 0x01
-#define SEMICOLON 0x02
-#define TOKENIZE 0x03
-#define AGAIN 0x04
-#define ALIAS 0x05
-#define GETTOKEN 0x06
-#define ASCII 0x07
-#define BEGIN 0x08
-#define BUFFER 0x09
-#define CASE 0x0a
-#define CONST 0x0b
-#define CONTROL 0x0c
-#define CREATE 0x0d
-#define DECIMAL 0x0e
-#define DEFER 0x0f
-#define CDO 0x10
-#define DO 0x11
-#define ELSE 0x12
-#define ENDCASE 0x13
-#define ENDOF 0x14
-#define EXTERNAL 0x15
-#define FIELD 0x16
-#define HEADERLESS 0x17
-#define HEADERS 0x18
-#define HEX 0x19
-#define IF 0x1a
-#define CLEAVE 0x1b
-#define LEAVE 0x1c
-#define CLOOP 0x1d
-#define LOOP 0x1e
-#define OCTAL 0x1f
-#define OF 0x20
-#define REPEAT 0x21
-#define THEN 0x22
-#define TO 0x23
-#define UNTIL 0x24
-#define VALUE 0x25
-#define VARIABLE 0x26
-#define WHILE 0x27
-#define OFFSET16 0x28
-#define BEGINTOK 0x29
-#define EMITBYTE 0x2a
-#define ENDTOK 0x2b
-#define FLOAD 0x2c
-#define STRING 0x2d
-#define PSTRING 0x2e
-#define PBSTRING 0x2f
-#define SSTRING 0x30
-#define RECURSIVE 0x31
-#define HEXVAL 0x32
-#define DECVAL 0x33
-#define OCTVAL 0x34
+/* **************************************************************************
+ * Modifications made in 2005 by IBM Corporation
+ * (C) Copyright 2005 IBM Corporation. All Rights Reserved.
+ * Modifications Author: David L. Paktor dlpaktor(a)us.ibm.com
+ **************************************************************************** */
-#define END0 0xdb
-#define END1 0xdc
-#define CHAR 0xdd
-#define CCHAR 0xde
-#define ABORTTXT 0xdf
+/* **************************************************************************
+ *
+ * Numeric values for FWord-type vocabulary entries. Used by the
+ * big "switch" statement in handle_internal(); a subset are
+ * also used as "definer-type" values associated with various
+ * types of definitions.
+ *
+ **************************************************************************** */
-#define NEXTFCODE 0xef
+typedef enum fword_token {
+ UNSPECIFIED = 0xBAADD00D , /* Default (absence-of) "definer" */
+ COMMON_FWORD = 0xC0EDC0DE , /* Definer indicating a "shared" FWord */
+ BI_FWRD_DEFN = 0xB1F4409D , /* Definer indicating a "built-in FWord" */
+ COLON = 1 ,
+ SEMICOLON ,
+ TICK ,
+ AGAIN ,
+ ALIAS ,
+ BRACK_TICK ,
+ F_BRACK_TICK ,
+ ASCII ,
+ BEGIN ,
+ BUFFER ,
+ CASE ,
+ CONST ,
+ CONTROL ,
+ CREATE ,
+ DECIMAL ,
+ DEFER ,
+ DEFINED ,
+ CDO ,
+ DO ,
+ ELSE ,
+ ENDCASE ,
+ ENDOF ,
+ EXTERNAL ,
+ INSTANCE ,
+ FIELD ,
+ NEW_DEVICE ,
+ FINISH_DEVICE ,
+ FLITERAL ,
+ HEADERLESS ,
+ HEADERS ,
+ HEX ,
+ IF ,
+ UNLOOP ,
+ LEAVE ,
+ LOOP_I ,
+ LOOP_J ,
+ LOOP ,
+ PLUS_LOOP ,
+ OCTAL ,
+ OF ,
+ REPEAT ,
+ THEN ,
+ TO ,
+ IS ,
+ UNTIL ,
+ VALUE ,
+ VARIABLE ,
+ WHILE ,
+ OFFSET16 ,
+ ESCAPETOK ,
+ EMITBYTE ,
+ FLOAD ,
+ STRING ,
+ PSTRING ,
+ PBSTRING ,
+ SSTRING ,
+ RECURSIVE ,
+ RECURSE ,
+ RET_STK_FETCH ,
+ RET_STK_FROM ,
+ RET_STK_TO ,
+ HEXVAL ,
+ DECVAL ,
+ OCTVAL ,
-#define ENCODEFILE 0xf0
+ ret_stk_from ,
+ ASC_NUM , /* Convert char seq to number */
+ ASC_LEFT_NUM , /* same, only left-justified. */
-#define FCODE_V1 0xf1
-#define FCODE_V3 0xf2
-#define NOTLAST 0xf3
-#define PCIREV 0xf4
-#define PCIHDR 0xf5
-#define PCIEND 0xf6
-#define START0 0xf7
-#define START1 0xf8
-#define START2 0xf9
-#define START4 0xfa
-#define VERSION1 0xfb
-#define FCODE_TIME 0xfc
-#define FCODE_DATE 0xfd
-#define FCODE_V2 0xfe
-#define FCODE_END 0xff
+ CONDL_ENDER , /* Conditional "[THEN] / [ENDIF]" variants */
+ CONDL_ELSE , /* Conditional "[ELSE]" directive variants */
+
+ PUSH_FCODE , /* Save the FCode Assignment number */
+ POP_FCODE , /* Retrieve the FCode Assignment number */
+ RESET_FCODE , /* Reset FCode Ass't nr and overlap checking */
+
+ CURLY_BRACE , /* Support for IBM-style Locals */
+ DASH_ARROW ,
+ LOCAL_VAL ,
+ EXIT ,
+
+ FUNC_NAME ,
+ IFILE_NAME ,
+ ILINE_NUM ,
+
+ CL_FLAG ,
+ SHOW_CL_FLAGS ,
+
+ OVERLOAD ,
+ ALLOW_MULTI_LINE ,
+ MACRO_DEF ,
+ GLOB_SCOPE ,
+ DEV_SCOPE ,
+
+ /* This value has to be adjusted
+ * so that FCODE_END comes
+ * out to be 0xff
+ */
+ END0 = 0xd7 , /* 0xd7 */
+ END1 , /* 0xd8 */
+ CHAR , /* 0xd9 */
+ CCHAR , /* 0xda */
+ ABORTTXT , /* 0xdb */
+
+ NEXTFCODE , /* 0xdc */
+
+ ENCODEFILE , /* 0xdd */
+
+ FCODE_V1 , /* 0xde */
+ FCODE_V3 , /* 0xdf */
+ NOTLAST , /* 0xef */
+ ISLAST , /* 0xf0 */
+ SETLAST , /* 0xf1 */
+ PCIREV , /* 0xf2 */
+ PCIHDR , /* 0xf3 */
+ PCIEND , /* 0xf4 */
+ RESETSYMBS , /* 0xf5 */
+ SAVEIMG , /* 0xf6 */
+ START0 , /* 0xf7 */
+ START1 , /* 0xf8 */
+ START2 , /* 0xf9 */
+ START4 , /* 0xfa */
+ VERSION1 , /* 0xfb */
+ FCODE_TIME , /* 0xfc */
+ FCODE_DATE , /* 0xfd */
+ FCODE_V2 , /* 0xfe */
+ FCODE_END = 0xff /* 0xff */
+} fwtoken ;
+
+#endif /* _TOKE_DICTIONARY_H */
Modified: fcode-utils/toke/emit.c
===================================================================
--- fcode-utils/toke/emit.c 2006-08-18 09:45:11 UTC (rev 75)
+++ fcode-utils/toke/emit.c 2006-08-18 12:47:12 UTC (rev 76)
@@ -24,283 +24,548 @@
*
*/
+/* **************************************************************************
+ * Modifications made in 2005 by IBM Corporation
+ * (C) Copyright 2005 IBM Corporation. All Rights Reserved.
+ * Modifications Author: David L. Paktor dlpaktor(a)us.ibm.com
+ **************************************************************************** */
+
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
+
+#include "pcihdr.h"
+
#include "toke.h"
+#include "vocabfuncts.h"
#include "stack.h"
+#include "scanner.h"
#include "emit.h"
+#include "clflags.h"
+#include "errhandler.h"
+#include "stream.h"
+#include "nextfcode.h"
-extern bool offs16;
-extern int verbose;
-extern u8 *ostart, *opc, *oend;
+/* **************************************************************************
+ *
+ * Global Variables Imported
+ * verbose Enable optional messages, set by "-v" switch
+ * noerrors "Ignore Errors" flag, set by "-i" switch
+ *
+ **************************************************************************** */
-/* PCI data */
-extern u16 pci_vpd, pci_revision;
-extern bool pci_is_last_image;
-/* header pointers */
-extern u8 *fcode_hdr;
-extern u8 *pci_hdr;
+/* **************************************************************************
+ *
+ * Macro to zero-fill a field of the size of the given structure
+ * into the Output Buffer using the emit_byte() routine.
+ *
+ **************************************************************************** */
-extern bool haveend;
+#define EMIT_STRUCT(x) {int j; for (j=0; j < sizeof(x) ; j++ ) emit_byte(0); }
-u16 lookup_token(char *name);
-static bool little_endian(void)
+/* **************************************************************************
+ *
+ * Local Static Variables, offsets into Output Buffer of ...:
+ * fcode_start_ob_off First FCode-Start byte
+ * fcode_hdr_ob_off FCode Header (Format byte)
+ * fcode_body_ob_off First functional FCode after FCode Header.
+ * pci_hdr_ob_off Start of PCI ROM Header Block structure
+ * pci_data_blk_ob_off Start of PCI Data Header Block structure
+ *
+ * For all of these, -1 means "Not initialized"
+ *
+ *************************************************************************** */
+
+static int fcode_start_ob_off = -1;
+static int fcode_hdr_ob_off = -1;
+static int fcode_body_ob_off = -1;
+static int pci_hdr_ob_off = -1;
+static int pci_data_blk_ob_off = -1;
+
+/* **************************************************************************
+ *
+ * These are to detect a particular error: If FCode has
+ * been written, before an Fcode-start<n> or before
+ * a PCI-header
+ *
+ **************************************************************************** */
+
+static bool fcode_written = FALSE;
+
+/* **************************************************************************
+ *
+ * Variables and Functions Imported, with
+ * Exposure as Limited as possible:
+ * ostart
+ * olen
+ * increase_output_buffer
+ *
+ **************************************************************************** */
+
+extern u8 *ostart;
+extern int olen;
+extern void increase_output_buffer( void);
+
+
+/* **************************************************************************
+ *
+ * Function name: init_emit
+ * Synopsis: Initialize Local Static Variables before starting
+ * Output.
+ * Exposure as Limited as possible.
+ *
+ **************************************************************************** */
+void init_emit( void); /* Prototype. Limit Exposure. */
+void init_emit( void)
{
- static short one=1;
- return *(char *)&one==1;
+ fcode_start_ob_off = -1;
+ fcode_hdr_ob_off = -1;
+ fcode_body_ob_off = -1;
+ pci_hdr_ob_off = -1;
+ pci_data_blk_ob_off = -1;
+ fcode_written = FALSE;
+ haveend = FALSE; /* Get this one too... */
}
-int emit_byte(u8 data)
-{
- u8 *newout;
- int newsize;
- if(opc==oend) {
- /* need more output space */
- newsize = (oend - ostart) * 2;
- printf("Increasing output buffer to %d bytes.\n", newsize);
- if ((newout=realloc(ostart, newsize)) == NULL) {
- printf("toke: could not allocate %d bytes for output buffer\n", newsize);
- exit(-1);
- }
+/* **************************************************************************
+ *
+ * Function name: emit_byte
+ * Synopsis: Fundamental routine for placing a byte
+ * into the Output Buffer. Also, check
+ * whether the buffer needs to be expanded.
+ * For internal use only.
+ *
+ **************************************************************************** */
- /* move pointers */
- opc=newout+(opc-ostart);
- ostart=newout;
- oend=ostart+newsize;
+static void emit_byte(u8 data)
+{
+ if ( opc == olen)
+ {
+ increase_output_buffer();
}
- *opc=data;
+
+ *(ostart+opc) = data ;
opc++;
-
- return 0;
}
-int emit_fcode(u16 tok)
+void emit_fcode(u16 tok)
{
if ((tok>>8))
emit_byte(tok>>8);
emit_byte(tok&0xff);
-
- return 0;
+ fcode_written = TRUE;
}
-int emit_token(const char *name)
+static void emit_num32(u32 num)
{
- return emit_fcode(lookup_token((char *)name));
-}
-
-int emit_num32(u32 num)
-{
emit_byte(num>>24);
emit_byte((num>>16)&0xff);
emit_byte((num>>8)&0xff);
emit_byte(num&0xff);
- return 0;
}
-int emit_num16(u16 num)
+/* **************************************************************************
+ *
+ * Function name: user_emit_byte
+ * Synopsis: Action of user-mandated call to emit-byte.
+ * Covers the corner-case where this is the
+ * first command issued in the source input.
+ *
+ **************************************************************************** */
+
+void user_emit_byte(u8 data)
{
- emit_byte(num>>8);
- emit_byte(num&0xff);
-
- return 0;
+ emit_byte( data);
+ fcode_written = TRUE;
}
-int emit_offset(s16 offs)
+void emit_offset(s16 offs)
{
+ /* Calling routine will test for out-of-range FCode-Offset */
if (offs16)
- emit_num16(offs);
- else
- emit_byte(offs);
-
- return 0;
+ emit_byte(offs>>8);
+ emit_byte(offs&0xff);
}
-s16 receive_offset(void)
+void emit_literal(u32 num)
{
- s16 offs=0;
-
- if (offs16) {
- offs=((*opc)<<8)|(*(opc+1));
- } else
- offs=(*opc);
-
- return offs;
+ emit_token("b(lit)");
+ emit_num32(num);
}
-int emit_string(u8 *string, unsigned int cnt)
+void emit_string(u8 *string, signed int cnt)
{
- unsigned int i=0;
+ signed int i=0;
+ signed int cnt_cpy = cnt;
- if (cnt>255) {
- printf("string too long.");
- exit(1);
+ if ( cnt_cpy > STRING_LEN_MAX )
+ {
+ tokenization_error( TKERROR,
+ "String too long: %d characters. Truncating.\n",cnt);
+ cnt_cpy = STRING_LEN_MAX ;
}
- emit_byte(cnt);
- for (i=0; i<cnt; i++)
+ emit_byte(cnt_cpy);
+ for (i=0; i<cnt_cpy; i++)
emit_byte(string[i]);
-
- return 0;
}
-int emit_fcodehdr(void)
+void emit_fcodehdr(const char *starter_name)
{
- /* We comply with IEEE 1275-1994 */
- emit_byte(0x08);
- /* checksum */
- emit_num16(0);
+ /* Check for error conditions */
+ if ( fcode_written )
+ {
+ tokenization_error( TKERROR ,
+ "Cannot create FCode header after FCode output has begun.\n");
+ if ( ! noerrors ) return ;
+ }
- /* len */
- emit_num32(0);
+ fcode_header_t *fcode_hdr;
- return 0;
+ fcode_start_ob_off = opc;
+ emit_token( starter_name );
+
+ fcode_hdr_ob_off = opc;
+ fcode_hdr = (fcode_header_t *)(ostart+fcode_hdr_ob_off);
+
+ EMIT_STRUCT(fcode_header_t);
+
+ fcode_body_ob_off = opc;
+
+ /* Format = 8 means we comply with IEEE 1275-1994 */
+ fcode_hdr->format = 0x08;
+
}
-int finish_fcodehdr(void)
+/* **************************************************************************
+ *
+ * Function name: finish_fcodehdr
+ * Fill in the FCode header's checksum and length fields, and
+ * reset the FCode-header pointer for the next image.
+ *
+ * If haveend is true then the end0 has already been written
+ * and fcode_ender() has been called.
+ *
+ * Print a WARNING message if the end-of-file was encountered
+ * without an end0 or an fcode-end
+ *
+ * Print an informative message to standard-output giving the
+ * checksum. Call list_fcode_ranges() to print the
+ * value of the last FCode-token that was assigned or
+ * the Ranges of assigned FCode-token values if so be...
+ * The final FCode-binary file-length will be printed
+ * when the binary file is being closed.
+ *
+ **************************************************************************** */
+
+void finish_fcodehdr(void)
{
- u16 checksum=0;
- u32 len,i;
- if(!fcode_hdr)
+ if( fcode_hdr_ob_off == -1 )
{
- printf("warning: trying to fix up unknown fcode header\n");
- return -1;
+ tokenization_error( TKERROR,
+ "Missing FCode header.\n");
+ return ;
}
- /* If the program does not do this, we do */
+ /* If the program did not end cleanly, we'll handle it */
if (!haveend)
+ {
+ tokenization_error ( WARNING,
+ "End-of-file encountered without END0 or FCODE-END. "
+ "Supplying END0\n");
emit_token("end0");
+ fcode_ender();
+ }
- len=(unsigned long)opc-(unsigned long)(fcode_hdr-1);
+ /* Calculate and place checksum and length, if haven't already */
+ if ( fcode_start_ob_off != -1 )
+ {
+ u16 checksum;
+ int length;
+
+ u8 *fcode_body = ostart+fcode_body_ob_off;
+ u8 *ob_end = ostart+opc;
+ fcode_header_t *fcode_hdr =
+ (fcode_header_t *)(ostart+fcode_hdr_ob_off);
- for (i=8;i<len;i++)
- checksum+=fcode_hdr[i-1];
+ length = opc - fcode_start_ob_off;
- dpush((unsigned long)opc);
- opc=fcode_hdr+1;
- emit_num16(checksum);
- emit_num32(len);
- opc=(u8 *)dpop();
+ for ( checksum = 0;
+ fcode_body < ob_end ;
+ checksum += *(fcode_body++) ) ;
+
+ BIG_ENDIAN_WORD_STORE(fcode_hdr->checksum , checksum);
+ BIG_ENDIAN_LONG_STORE(fcode_hdr->length , length);
+
if (verbose)
- printf("toke: checksum is 0x%04x (%d bytes)\n",
- checksum, len);
+ {
+ printf( "toke: checksum is 0x%04x (%d bytes). ",
+ checksum, length);
+ list_fcode_ranges( TRUE);
+ }
+ }
- fcode_hdr=NULL;
+ /* Reset things for the next image... */
+ fcode_start_ob_off = -1;
+ fcode_hdr_ob_off = -1;
+ fcode_body_ob_off = -1;
+ fcode_written = FALSE;
haveend=FALSE;
- return 0;
}
-int emit_pcihdr(u16 vid, u16 did, u32 classid)
+/* **************************************************************************
+ *
+ * Function name: emit_pci_rom_hdr
+ * Synopsis: Write the PCI ROM Header Block into the Output Buffer
+ *
+ * Inputs:
+ * Parameters: NONE
+ * Global Variables:
+ * opc Output Buffer Position Counter
+ * ostart Start of Output Buffer
+ *
+ * Outputs:
+ * Returned Value: NONE
+ * Global Variables:
+ * pci_hdr_ob_off PCI ROM Header Block Position
+ * (Offset) in Output Buffer
+ * FCode Output buffer:
+ * Write the part of the PCI ROM Header Block we know:
+ * Fill in the signature and the field reserved for
+ * "processor architecture unique data".
+ * Fill in the "Pointer to PCI Data Structure" with the
+ * size of the data structure, because the first PCI
+ * Data Structure will follow immediately.
+ *
+ * Error Detection: (Handled by calling routine)
+ *
+ **************************************************************************** */
+
+static void emit_pci_rom_hdr(void)
{
- int i;
+ rom_header_t *pci_hdr;
+ pci_hdr_ob_off = opc;
+ pci_hdr = (rom_header_t *)(ostart + pci_hdr_ob_off);
+
+ EMIT_STRUCT(rom_header_t);
/* PCI start signature */
- emit_byte(0x55); emit_byte(0xaa);
+ LITTLE_ENDIAN_WORD_STORE(pci_hdr->signature,0xaa55);
/* Processor architecture */
- emit_byte(0x34); emit_byte(0x00);
+ /* Note:
+ * The legacy code used to read:
+ *
+ * pci_hdr->reserved[0] = 0x34;
+ *
+ * I don't know what significance the literal 34 had, but
+ * by what might just be an odd coincidence, it is equal
+ * to the combined lengths of the PCI-ROM- and PCI-Data-
+ * headers.
+ *
+ * I suspect that it is more than merely an odd coincidence,
+ * and that the following would be preferable:
+ */
- /* 20 bytes of padding */
- for (i=0; i<20; i++) emit_byte(0x00);
+ LITTLE_ENDIAN_WORD_STORE( pci_hdr->reserved ,
+ (sizeof(rom_header_t) + sizeof(pci_data_t)) ) ;
+ /* already handled padding */
+
/* pointer to start of PCI data structure */
- emit_byte(0x1c); emit_byte(0x00);
+ LITTLE_ENDIAN_WORD_STORE(pci_hdr->data_ptr, sizeof(rom_header_t) );
- /* 2 bytes of zero padding */
- emit_byte(0x00); emit_byte(0x00);
+}
- /* PCI Data structure */
- emit_byte('P'); emit_byte('C'); emit_byte('I'); emit_byte('R');
- /* vendor id */
- emit_byte(vid&0xff); emit_byte(vid>>8);
- /* device id */
- emit_byte(did&0xff); emit_byte(did>>8);
- /* vital product data */
- emit_byte(0x00); emit_byte(0x00);
- /* length of pci data structure */
- emit_byte(0x18); emit_byte(0x00);
- /* PCI data structure revision */
- emit_byte(0x00);
-
- if (little_endian()) {
- /* reg level programming */
- emit_byte(classid & 0xff);
- /* class code */
- emit_byte((classid>>8)&0xff);
- emit_byte((classid>>16)&0xff);
- } else {
- /* class code */
- emit_byte((classid>>8)&0xff);
- emit_byte((classid>>16)&0xff);
- /* reg level programming */
- emit_byte(classid & 0xff);
+/* **************************************************************************
+ *
+ * Function name: emit_pci_data_block
+ * Synopsis: Write the PCI Data Block into the Output Buffer
+ *
+ * Inputs:
+ * Parameters: NONE
+ * Global Variables:
+ * opc Output Buffer Position Counter
+ * Data-Stack Items:
+ * Top: Class Code
+ * Next: Device ID
+ * 3rd: Vendor ID
+ *
+ * Outputs:
+ * Returned Value: NONE
+ * Global Variables:
+ * pci_data_blk_ob_off PCI Data Header Block Position
+ * (Offset) in Output Buffer
+ * Data-Stack, # of Items Popped: 3
+ * FCode Output buffer:
+ * Write the PCI Data Header Block: Fill in the signature,
+ * Vendor ID, Device ID and Class Code, and everything
+ * else whose value we know. (Size and Checksum will
+ * have to wait until we finish the image...)
+ * Printout:
+ * Advisory of Vendor, Device and Class
+ *
+ * Error Detection: (Handled by calling routine)
+ *
+ **************************************************************************** */
+
+static void emit_pci_data_block(void)
+{
+ pci_data_t *pci_data_blk;
+ u32 class_id = dpop();
+ u16 dev_id = dpop();
+ u16 vend_id = dpop();
+
+ pci_data_blk_ob_off = opc;
+ pci_data_blk = (pci_data_t *)(ostart + pci_data_blk_ob_off);
+
+ EMIT_STRUCT(pci_data_t);
+
+ BIG_ENDIAN_LONG_STORE(pci_data_blk->signature , PCI_DATA_HDR );
+
+ LITTLE_ENDIAN_WORD_STORE(pci_data_blk->vendor , vend_id );
+ LITTLE_ENDIAN_WORD_STORE(pci_data_blk->device , dev_id );
+ LITTLE_ENDIAN_TRIPLET_STORE(pci_data_blk->class_code , class_id );
+
+ LITTLE_ENDIAN_WORD_STORE(pci_data_blk->dlen , sizeof(pci_data_t) );
+
+ pci_data_blk->drevision = PCI_DATA_STRUCT_REV ;
+
+ /* code type = open firmware = 1 */
+ pci_data_blk->code_type = 1;
+
+ /* last image flag */
+ pci_data_blk->last_image_flag = pci_is_last_image ? 0x80 : 0 ;
+
+ tokenization_error(INFO ,
+ "PCI header vendor id=0x%04x, "
+ "device id=0x%04x, class=%06x\n",
+ vend_id, dev_id, class_id );
+
+}
+
+/* **************************************************************************
+ *
+ * Function name: emit_pcihdr
+ * Synopsis: Supervise the writing of PCI Header information
+ * into the Output Buffer, when the PCI-HEADER
+ * tokenizer directive has been encountered.
+ *
+ * Inputs:
+ * Parameters: NONE
+ * Global Variables:
+ * fcode_start_ob_off Initted if FCode output has begun
+ * noerrors The "Ignore Errors" flag
+ *
+ * Outputs:
+ * Returned Value: NONE
+ * Global Variables:
+ * FCode Output buffer:
+ *
+ * Error Detection:
+ * An attempt to write a PCI Header after FCode output -- either an
+ * Fcode-start<n> or ordinary FCode -- has begun is an ERROR.
+ * Report it; do nothing further, unless "Ignore Errors" is set.
+ *
+ **************************************************************************** */
+
+void emit_pcihdr(void)
+{
+
+ /* Check for error conditions */
+ if (
+ /* FCODE-START<n> has already been issued */
+ ( fcode_start_ob_off != -1 )
+ /* Other FCode has been written */
+ || fcode_written
+ )
+ {
+ tokenization_error( TKERROR ,
+ "Cannot create PCI header after FCode output has begun.\n");
+ if ( ! noerrors ) return ;
}
- /* size of image - to be filled later */
- emit_byte(0x00); emit_byte(0x00);
- /* revision level */
- emit_byte(0x00); emit_byte(0x00);
- /* code type = open firmware */
- emit_byte(0x01);
- emit_byte(0x80);
- /* 2 bytes of padding */
- emit_byte(0x00); emit_byte(0x00);
+ emit_pci_rom_hdr();
- return 0;
+ emit_pci_data_block();
}
+/* **************************************************************************
+ *
+ * Function name: finish_pcihdr
+ * Synopsis: Fill-in the fields of the PCI Header that could
+ * not be determined until the end of the PCI-block.
+ *
+ *************************************************************************** */
-int finish_pcihdr(void)
+void finish_pcihdr(void)
{
- u8 *tpc;
- u32 imgsize=opc-ostart, imgblocks;
+
+ u32 imagesize ;
+ u32 imageblocks;
int padding;
- if(!pci_hdr)
+ rom_header_t *pci_hdr;
+ pci_data_t *pci_data_blk;
+
+ if( pci_data_blk_ob_off == -1 )
{
- printf("error: trying to fix up unknown pci header\n");
- return -1;
+ tokenization_error( TKERROR,
+ "%s without PCI-HEADER\n", strupr(statbuf) );
+ return ;
}
+ pci_hdr = (rom_header_t *)(ostart + pci_hdr_ob_off);
+ pci_data_blk = (pci_data_t *)(ostart + pci_data_blk_ob_off);
+
/* fix up vpd */
- tpc=opc;
- opc=pci_hdr+36;
- emit_byte(pci_vpd&0xff); emit_byte(pci_vpd>>8);
+ LITTLE_ENDIAN_WORD_STORE(pci_data_blk->vpd, pci_vpd);
- /* fix up image size */
- opc=pci_hdr+44;
- imgblocks=(imgsize+511)>>9; /* size is in 512byte blocks */
- emit_byte(imgblocks&0xff); emit_byte(imgblocks>>8);
+ /* Calculate image size and padding */
+ imagesize = opc - pci_hdr_ob_off; /* Padding includes PCI hdr */
+ imageblocks = (imagesize + 511) >> 9; /* Size in 512-byte blocks */
+ padding = (imageblocks << 9) - imagesize;
+
+ /* fix up image size. */
+ LITTLE_ENDIAN_WORD_STORE(pci_data_blk->ilen, imageblocks);
/* fix up revision */
- emit_byte(pci_revision&0xff); emit_byte(pci_revision>>8);
+ if ( big_end_pci_image_rev )
+ {
+ BIG_ENDIAN_WORD_STORE(pci_data_blk->irevision, pci_image_rev);
+ }else{
+ LITTLE_ENDIAN_WORD_STORE(pci_data_blk->irevision, pci_image_rev);
+ }
/* fix up last image flag */
- opc++;
- emit_byte(pci_is_last_image?0x80:0x00);
- opc=tpc;
+ pci_data_blk->last_image_flag = pci_is_last_image ? 0x80 : 0 ;
/* align to 512bytes */
- padding=((imgsize+511)&0xfffffe00)-imgsize;
+
printf("Adding %d bytes of zero padding to PCI image.\n",padding);
while (padding--)
emit_byte(0);
+ if ( ! pci_is_last_image )
+ {
+ printf("Note: PCI header is not last image.\n");
+ }
+ printf("\n");
- pci_hdr=NULL;
- return 0;
+ pci_hdr_ob_off = -1;
+ pci_data_blk_ob_off = -1;
}
void finish_headers(void)
{
- if (fcode_hdr) finish_fcodehdr();
- if (pci_hdr) finish_pcihdr();
+ if (fcode_hdr_ob_off != -1) finish_fcodehdr();
+ if (pci_hdr_ob_off != -1) finish_pcihdr();
}
Modified: fcode-utils/toke/emit.h
===================================================================
--- fcode-utils/toke/emit.h 2006-08-18 09:45:11 UTC (rev 75)
+++ fcode-utils/toke/emit.h 2006-08-18 12:47:12 UTC (rev 76)
@@ -1,3 +1,6 @@
+#ifndef _TOKE_EMIT_H
+#define _TOKE_EMIT_H
+
/*
* OpenBIOS - free your system!
* ( FCode tokenizer )
@@ -24,21 +27,90 @@
*
*/
-#ifndef _H_EMIT
-#define _H_EMIT
+/* **************************************************************************
+ * Modifications made in 2005 by IBM Corporation
+ * (C) Copyright 2005 IBM Corporation. All Rights Reserved.
+ * Modifications Author: David L. Paktor dlpaktor(a)us.ibm.com
+ **************************************************************************** */
+
+#include "types.h"
-int emit_byte(u8 data);
-int emit_fcode(u16 tok);
-int emit_token(const char *name);
-int emit_num32(u32 num);
-int emit_num16(u16 num);
-int emit_offset(s16 offs);
-s16 receive_offset(void);
-int emit_string(u8 *string, unsigned int cnt);
-int emit_fcodehdr(void);
-int finish_fcodehdr(void);
-int emit_pcihdr(u16 vid, u16 did, u32 classid);
-int finish_pcihdr(void);
+/* **************************************************************************
+ * Structure Name: fcode_header_t
+ * Synopsis: FCode Header within the Output Buffer
+ *
+ * Fields:
+ * format, checksum and length All as prescribed in P1275, Sec 5.2.2.5
+ *
+ * Note that the Checksum and Length fields are stated as byte-arrays
+ * rather than as integers. This is intended to guarantee that
+ * their endian-ness will remain independent of the endian-ness
+ * of the host-platform on which this Tokenizer is running.
+ * Note also that, as integers, both are BIG-Endian.
+ *
+ **************************************************************************** */
+
+typedef struct {
+ u8 format;
+ u8 checksum[2]; /* [0] = Hi byte, [1] = Lo */
+ u8 length[4]; /* [0] = Hi, [1] = Hi-mid, [2] = Lo-mid, [3] = Lo */
+} fcode_header_t;
+
+
+/* **************************************************************************
+ * Macro Name: STRING_LEN_MAX
+ * Max number of bytes allowable in an output string
+ *
+ * Arguments: NONE
+ *
+ * This value must remail hard-coded and immutable. It represents the
+ * maximum number allowed in a FORTH counted-string's count-byte
+ * (which is, of course, the maximum number that can be expressed
+ * in an unsigned byte).
+ * It should not be used for anything else (e.g., buffer sizes), and
+ * most especially not for anything that might be changed!
+ *
+ **************************************************************************** */
+
+#define STRING_LEN_MAX 255
+
+
+/* **************************************************************************
+ * Macro Name: GET_BUF_MAX
+ * Size alloted to input-string buffer
+ *
+ * Arguments: NONE
+ *
+ * This is a generous allotment for the buffer into which
+ * input strings are gathered. Overflow calculations are
+ * also based on it. It may be changed safely.
+ * We like to keep it a nice power-of-two to make the memory-
+ * allocation routine run efficiently and happily (Okay, so
+ * that's anthropormism: It's efficient and *we*'re happy.
+ * Better? I thought so... ;-)
+ *
+ **************************************************************************** */
+
+#define GET_BUF_MAX 1024
+
+
+/* ************************************************************************** *
+ *
+ * Function Prototypes / Functions Exported:
+ *
+ **************************************************************************** */
+
+void emit_fcode(u16 tok);
+void user_emit_byte(u8 data);
+
+void emit_offset(s16 offs);
+void emit_string(u8 *string, signed int cnt);
+void emit_fcodehdr(const char *starter_name);
+void finish_fcodehdr(void);
+void emit_pcihdr(void);
+void finish_pcihdr(void);
void finish_headers(void);
+void emit_end0(void);
+void emit_literal(u32 num);
-#endif /* _H_EMIT */
+#endif /* _TOKE_EMIT_H */
Added: fcode-utils/toke/errhandler.c
===================================================================
--- fcode-utils/toke/errhandler.c (rev 0)
+++ fcode-utils/toke/errhandler.c 2006-08-18 12:47:12 UTC (rev 76)
@@ -0,0 +1,956 @@
+/*
+ * OpenBIOS - free your system!
+ * ( FCode tokenizer )
+ *
+ * This program is part of a free implementation of the IEEE 1275-1994
+ * Standard for Boot (Initialization Configuration) Firmware.
+ *
+ * Copyright (C) 2001-2005 Stefan Reinauer, <stepan(a)openbios.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA, 02110-1301 USA
+ *
+ */
+
+/* **************************************************************************
+ *
+ * Error-Handler for Tokenizer
+ *
+ * Controls printing of various classes of errors
+ *
+ * (C) Copyright 2005 IBM Corporation. All Rights Reserved.
+ * Module Author: David L. Paktor dlpaktor(a)us.ibm.com
+ *
+ **************************************************************************** */
+
+/* **************************************************************************
+ *
+ * Functions Exported:
+ * init_error_handler Initialize the error-counts,
+ * announce the file names.
+ * tokenization_error Handle an error of the given class,
+ * print the given message in the
+ * standard format.
+ * started_at Supplemental message, giving a back-reference
+ * to the "starting" point of a compound
+ * error, including last-colon identification.
+ * just_started_at Supplemental back-reference to "starting" point
+ * of compound error, but without last-colon
+ * identification.
+ * where_started Supplemental message, giving a more terse back-
+ * -reference to "start" of compound-error.
+ * just_where_started Supplemental message, more terse back-reference,
+ * without last-colon identification.
+ * in_last_colon Supplemental back-reference message,
+ * identifying last Colon-definition.
+ * safe_malloc malloc with built-in failure test.
+ * error_summary Summarize final error-message status
+ * before completing tokenization.
+ *
+ **************************************************************************** */
+
+
+/* **************************************************************************
+ *
+ * We will define a set of bit-valued error-types and a
+ * global bit-mask. Each error-message will be associated
+ * with one of the bit-valued error-types. The bit-mask,
+ * which will be set by a combination of defaults and user
+ * inputs (mainly command-line arguments), will control
+ * whether an error-message of any given type is printed.
+ *
+ * Another bit-mask variable will accumulate the error-
+ * types that occur within any given run; at the end of
+ * the run, it will be examined to determine if the run
+ * failed, i.e., if the output should be suppressed.
+ *
+ **************************************************************************** */
+
+/* **************************************************************************
+ *
+ * Error-types fall into the following broad categories:
+ * FATAL Cause to immediately stop activity
+ * TKERROR Sufficient to make the run a failure,
+ * but not to stop activity.
+ * WARNING Not necessarily an error, but something
+ * to avoid. E.g., it might rely on
+ * assumptions that are not necessarily
+ * what the user/programmer wants. Or:
+ * It's a deprecated feature, or one
+ * that might be incompatible with
+ * other standard tokenizers.
+ * INFO Nothing is changed in processing, but
+ * an advisory is still in order.
+ * MESSAGE Message generated by the user. (Complete;
+ * new-line will be added by display routine.)
+ * P_MESSAGE Partial Message -- Instigated by user, but
+ * pre-formatted and not complete. New-line
+ * will be added by follow-up routine.
+ *
+ **************************************************************************** */
+
+#include <stdio.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+
+#include "types.h"
+#include "toke.h"
+#include "stream.h"
+#include "errhandler.h"
+#include "scanner.h"
+
+/* **************************************************************************
+ *
+ * Global Variables Imported
+ * iname Name of file currently being processed
+ * lineno Current line-number being processed
+ * noerrors "Ignore Errors" flag, set by "-i" switch
+ * opc FCode Output Buffer Position Counter
+ * verbose If true, enable Advisory Messages
+ *
+ **************************************************************************** */
+
+/* **************************************************************************
+ *
+ * Internal Static Variables
+ * print_msg Whether beginning of a message was printed;
+ * therefore, whether to print the rest.
+ * errs_to_print Error Verbosity Mask. Bits set correspond
+ * to message-types that will be printed
+ * May be altered by Command-Line switches.
+ * err_types_found Accumulated Error-types. Bits
+ * set correspond to error-types
+ * that have occurred.
+ * message_dest Message Dest'n. Usually ERRMSG_DESTINATION
+ * (stdout) except when we need to switch.
+ * err_count Count of Error Messages
+ * warn_count Count of Warning Messages
+ * info_count Count of "Advisory" Messages
+ * user_msg_count Count of User-generated Messages
+ * fatal_err_exit Exit code to be used for "Fatal" error.
+ * This is a special accommodation
+ * for the safe_malloc routine.
+ *
+ **************************************************************************** */
+
+static bool print_msg ;
+static int errs_to_print = ( FATAL | TKERROR | WARNING |
+ MESSAGE | P_MESSAGE | FORCE_MSG ) ;
+static int err_types_found = 0 ;
+static int err_count = 0 ;
+static int warn_count = 0 ;
+static int info_count = 0 ;
+static int user_msg_count = 0 ;
+static int fatal_err_exit = -1 ;
+static FILE *message_dest; /* Would like to init to ERRMSG_DESTINATION
+ * here, but the compiler complains...
+ */
+
+/* **************************************************************************
+ *
+ * Internal Static Constant Structure
+ * err_category Correlate each error-type code with its
+ * Counter-variable and the printable
+ * form of its name.
+ * num_categories Number of entries in the err_category table
+ *
+ **************************************************************************** */
+
+typedef struct {
+ int type_bit ; /* Error-type single-bit code */
+ char *category_name ; /* Printable-name base */
+ char *single ; /* Suffix to print singular of name */
+ char *plural ; /* Suffix to print plural of name */
+ int *counter ; /* Associated Counter-variable */
+ bool new_line ; /* Whether to print new-line at end */
+} err_category ;
+
+static const err_category error_categories[] = {
+ /* FATAL must be the first entry in the table. */
+ /* No plural is needed; only one is allowed.... */
+ { FATAL, "Fatal Error", "", "", &err_count , TRUE },
+
+ { TKERROR, "Error" , "", "s", &err_count , FALSE },
+ { WARNING, "Warning" , "", "s", &warn_count , FALSE },
+ { INFO, "Advisor" , "y", "ies", &info_count , FALSE },
+ { MESSAGE , "Message" , "", "s", &user_msg_count , TRUE },
+ { P_MESSAGE , "Message" , "", "s", &user_msg_count , FALSE }
+};
+
+static const int num_categories =
+ ( sizeof(error_categories) / sizeof(err_category) );
+
+
+#ifdef NEEDS_STRUPR
+
+/* **************************************************************************
+ *
+ * Function name: toup
+ * Synopsis: Support function for strupper
+ * Converts one character
+ *
+ * Inputs:
+ * Parameters:
+ * chr_ptr Pointer to the character
+ *
+ * Outputs:
+ * Returned Value: None
+ * Supplied Pointers:
+ * The character pointed to is changed
+ *
+ * Process Explanation:
+ * Because this fills in a lack in the host system, we cannot
+ * rely on the functions islower or toupper , which are
+ * usually built-in but might be similarly missing.
+ *
+ **************************************************************************** */
+
+static void toup( char *chr_ptr)
+{
+ const unsigned char upcas_diff = ( 'a' - 'A' );
+ if ( ( *chr_ptr >= 'a' ) && ( *chr_ptr <= 'z' ) )
+ {
+ *chr_ptr -= upcas_diff ;
+ }
+}
+
+/* **************************************************************************
+ *
+ * Function name: strupper
+ * Synopsis: Replacement for strupr on systems that don't
+ * seem to have it. A necessary hack.
+ *
+ * Inputs:
+ * Parameters:
+ * strung Pointer to the string to be changed
+ *
+ * Outputs:
+ * Returned Value: Same pointer that was passed in
+ * Supplied Pointers:
+ * The string pointed to will be converted to upper case
+ *
+ * Process Explanation:
+ * Because it fills in a lack in the host system, this routine
+ * does not rely on the functions islower or toupper
+ * which are usually built-in but might be missing.
+ *
+ **************************************************************************** */
+
+char *strupper( char *strung)
+{
+ char *strindx;
+ for (strindx = strung; *strindx != 0; strindx++)
+ {
+ toup( strindx);
+ }
+ return strung;
+}
+
+/* **************************************************************************
+ *
+ * If strupr is missing, it's a good bet that so is strlwr
+ *
+ **************************************************************************** */
+
+/* **************************************************************************
+ *
+ * Function name: tolow
+ * Synopsis: Support function for strlower
+ * Converts one character
+ *
+ * Inputs:
+ * Parameters:
+ * chr_ptr Pointer to the character
+ *
+ * Outputs:
+ * Returned Value: None
+ * Supplied Pointers:
+ * The character pointed to is changed
+ *
+ * Process Explanation:
+ * Because this fills in a lack in the host system, we cannot
+ * rely on the functions isupper or tolower , which are
+ * usually built-in but might be similarly missing.
+ *
+ **************************************************************************** */
+
+static void tolow( char *chr_ptr)
+{
+ const unsigned char lowcas_diff = ( 'A' - 'a' );
+ if ( ( *chr_ptr >= 'A' ) && ( *chr_ptr <= 'Z' ) )
+ {
+ *chr_ptr -= lowcas_diff ;
+ }
+}
+
+/* **************************************************************************
+ *
+ * Function name: strlower
+ * Synopsis: Replacement for strlwr on systems that don't
+ * seem to have it. A necessary hack.
+ *
+ * Inputs:
+ * Parameters:
+ * strung Pointer to the string to be changed
+ *
+ * Outputs:
+ * Returned Value: Same pointer that was passed in
+ * Supplied Pointers:
+ * The string pointed to will be converted to lower case
+ *
+ * Process Explanation:
+ * Because it fills in a lack in the host system, this routine
+ * does not rely on the functions isupper or tolower
+ * which are usually built-in but might be missing.
+ *
+ **************************************************************************** */
+
+char *strlower( char *strung)
+{
+ char *strindx;
+ for (strindx = strung; *strindx != 0; strindx++)
+ {
+ tolow( strindx);
+ }
+ return strung;
+}
+
+
+#endif /* NEEDS_STRUPR */
+
+/* **************************************************************************
+ *
+ * Function name: init_error_handler
+ * Synopsis: Initialize the error-handler before starting a
+ * new tokenization; both the aspects that will
+ * persist across the entire run and those that
+ * need to be reset, such as error-counts.
+ *
+ * Inputs:
+ * Parameters: NONE
+ * Global Variables:
+ * verbose Set by "-v" switch
+ * Macro:
+ * ERRMSG_DESTINATION Error message destination;
+ * (Set by development-time switch)
+ * FFLUSH_STDOUT Flush STDOUT if err-msg-dest is STDERR
+ *
+ * Outputs:
+ * Returned Value: NONE
+ * Global Variables:
+ * errs_to_print Add the INFO bit if verbose is set
+ * Local Static Variables:
+ * message_dest Point it at ERRMSG_DESTINATION (stderr)
+ * Reset the following to zero:
+ * err_types_found Accumulated Error-types.
+ * err_count Count of Error Messages
+ * warn_count Count of Warning Messages
+ * info_count Count of "Advisory" Messages
+ * user_msg_count Count of User-generated Messages
+ * Other Exotic Effects:
+ * Flush stdout if Error message destination is not stdout, to
+ * avoid collisions with stderr once Error Messaging begins.
+ *
+ * Extraneous Remarks:
+ * This needs to be done before attempting to read the input file,
+ * so that any Messages that occur there can be properly counted.
+ *
+ **************************************************************************** */
+
+void init_error_handler( void)
+{
+ message_dest = ERRMSG_DESTINATION;
+ if ( verbose ) errs_to_print |= INFO ;
+ err_types_found = 0 ;
+ err_count = 0 ;
+ warn_count = 0 ;
+ info_count = 0 ;
+ user_msg_count = 0 ;
+ FFLUSH_STDOUT
+}
+
+/* **************************************************************************
+ *
+ * Function name: tokenization_error
+ * Synopsis: Handle an error of the given class,
+ * print the given message in the standard format.
+ *
+ * Inputs:
+ * Parameters:
+ * err_type int One of the bit-valued error-types
+ * The remaining parameters are a format string and corresponding
+ * data objects such as would be sent to printf()
+ * Global Variables:
+ * errs_to_print Error Verbosity Mask.
+ * iname Name of file currently being processed
+ * lineno Current line-number being processed
+ * fatal_err_exit Exit code for "Fatal" error, if applicable.
+ * Macro:
+ * ERRMSG_DESTINATION Error message destination;
+ * (Development-time switch)
+ * Note: Whether this routine will or will not supply a new-line
+ * at the end of the printout depends on the category of the
+ * message. The new-line is included for a FATAL or a User-
+ * Generated Message, and excluded for the rest. For those,
+ * the calling routine must be responsible for including a
+ * new-line at the end of the format string or for otherwise
+ * finishing the line, as by calling started_at()
+ *
+ * Outputs:
+ * Returned Value: NONE
+ * Local Static Variables:
+ * err_types_found Accumulated Error-types.
+ * print_msg Whether this message was printed;
+ * may be used by started_at()
+ * One of the following Category Counters
+ * will be incremented, as applicable:
+ * err_count
+ * warn_count
+ * info_count
+ * user_msg_count
+ * Printout: Directed to stdout or stderr
+ * (see definition of ERRMSG_DESTINATION)
+ *
+ * Error Detection:
+ * Err_type not in list
+ * Print special message; treat cause as an Error.
+ * Force printout.
+ *
+ * Process Explanation:
+ * Accumulated the Error-type into err_types_found
+ * Identify the Error-Category:
+ * Check the Error-Type against the bit-code.
+ * The Error-type may have more than one bit set,
+ * but if it matches the Category bit-code, it's it.
+ * If it doesn't match any Error-Category bit-code, print
+ * a special message and treat it as an ERROR code.
+ * Check the Error-Type against the Error Verbosity Mask;
+ * If it has a bit set, print the Error-Category, together
+ * with the source-file name and line number, and
+ * the rest of the message as supplied.
+ * The table that translates the Error-type into a printable
+ * Error-Category string also identifies the applicable
+ * Category Counter; increment it.
+ * Of course, there's no return from a FATAL error; it exits.
+ *
+ **************************************************************************** */
+
+void tokenization_error( int err_type, char* msg, ... )
+{
+ int indx ;
+
+ /* Initial settings: treat as an Error. */
+ char *catgy_name = "Error";
+ char *catgy_suffx = "";
+ int *catgy_counter = &err_count;
+ bool print_new_line = FALSE;
+
+ /* Accumulated the Error-type into err_types_found */
+ err_types_found |= err_type;
+
+ /* Identify the Error-Category. */
+ for ( indx = 0 ; indx < num_categories ; indx ++ )
+ {
+ if ( ( error_categories[indx].type_bit & err_type ) != 0 )
+ {
+ catgy_name = error_categories[indx].category_name;
+ catgy_suffx = error_categories[indx].single;
+ catgy_counter = error_categories[indx].counter;
+ print_new_line = error_categories[indx].new_line;
+ break;
+ }
+ }
+
+ /* Special message if err_type not in list; treat as an Error. */
+ if ( catgy_name == NULL )
+ {
+ fprintf(ERRMSG_DESTINATION,
+ "Program error: Unknown Error-Type, 0x%08x. "
+ " Will treat as Error.\n", err_type) ;
+ err_types_found |= TKERROR;
+ print_msg = TRUE ;
+ } else {
+ /* Check the Error-Type against the Error Verbosity Mask */
+ print_msg = BOOLVAL( ( errs_to_print & err_type ) != 0 );
+ }
+
+ if ( print_msg )
+ {
+ va_list argp;
+
+ if ( iname != NULL )
+ {
+ fprintf(ERRMSG_DESTINATION, "%s%s: File %s, Line %d. ",
+ catgy_name, catgy_suffx, iname, lineno);
+ }else{
+ /* Don't print iname or lineno if no file opened. */
+ fprintf(ERRMSG_DESTINATION, "%s%s: ",
+ catgy_name, catgy_suffx);
+ }
+
+ va_start(argp, msg);
+ vfprintf(ERRMSG_DESTINATION, msg, argp);
+ va_end(argp);
+ if ( print_new_line ) fprintf(ERRMSG_DESTINATION, "\n");
+
+ /* Increment the category-counter. */
+ *catgy_counter += 1;
+ }
+ if ( err_type == FATAL )
+ {
+ fprintf(ERRMSG_DESTINATION, "Tokenization terminating.\n");
+ error_summary();
+ exit ( fatal_err_exit );
+ }
+}
+
+/* **************************************************************************
+ *
+ * Function name: print_where_started
+ * Synopsis: Supplemental message, following a tokenization_error,
+ * giving a back-reference to the "start" point of
+ * the compound-error being reported.
+ * This is a retro-fit; it does the heavy lifting for
+ * the routines started_at() , just_started_at() ,
+ * where_started() , just_where_started() and
+ * in_last_colon() .
+ *
+ * Inputs:
+ * Parameters:
+ * show_started Whether to print a phrase about "started"
+ * show_that_st Whether to print "that started" as opposed
+ * to " , which started"
+ * saved_ifile File-name saved for "back-reference"
+ * saved_lineno Line-number saved for "back-reference"
+ * may_show_incolon Whether to allow a call to in_last_colon()
+ * Needed to prevent infinite recursion...
+ * Global Variables:
+ * iname Name of file currently being processed
+ * lineno Current line-number being processed
+ * Local Static Variables:
+ * print_msg Whether the beginning part of the message
+ * was printed by tokenization_error()
+ * message_dest Message Destination. Is ERRMSG_DESTINATION
+ * (stdout) usually, except sometimes...
+ *
+ * Outputs:
+ * Returned Value: None
+ * Printout:
+ * The remainder of a message: the location of a back-reference.
+ * The phrase "that started" is switchable. This routine
+ * will supply the leading space and a new-line; the routines
+ * that call this can be used to finish the line.
+ *
+ * Process Explanation:
+ * This routine is called immediately after tokenization_error()
+ * If tokenization_error() didn't print, neither will we.
+ * The residual state of print_msg will tell us that.
+ * If the preceding message ended with something general about a
+ * "Colon Definition" or "Device-Node" or the like, we want
+ * the message to read: "that started on line ... [in file ...]"
+ * If the end of the preceding message was something more specific,
+ * we just want the message to read: "on line ... [in file ...]"
+ * If the saved input file name doesn't match our current input
+ * file name, we will print it and the saved line-number.
+ * If the file name hasn't changed, we will print only the saved
+ * line-number.
+ * If neither is changed, there's no point in printing any of the
+ * above-mentioned text.
+ * If a Colon-definition is in progress, show its name and the
+ * line on which it started. Protect against infinite loop!
+ * End the line.
+ *
+ * Extraneous Remarks:
+ * This is a retrofit. Earlier, it was just started_at() . Later,
+ * I generated more specific messages, and needed a way to leave
+ * out the "that started". I could, theoretically, have added
+ * the extra parameter to started_at() , but by now there are
+ * so many of calls to it that I'd rather leave them as is, and
+ * just change the name of the routine in the few places that
+ * need the terser form of the message.
+ *
+ **************************************************************************** */
+
+static void print_where_started( bool show_started,
+ bool show_that_st,
+ char * saved_ifile,
+ unsigned int saved_lineno,
+ bool may_show_incolon)
+{
+ if ( print_msg )
+ {
+ bool fil_is_diff;
+ bool lin_is_diff;
+
+ /* File names are case-sensitive */
+ fil_is_diff = BOOLVAL(strcmp(saved_ifile, iname) != 0 );
+ lin_is_diff = BOOLVAL(saved_lineno != lineno );
+ if ( fil_is_diff || lin_is_diff )
+ {
+ if ( show_started )
+ {
+ if ( show_that_st )
+ {
+ fprintf(message_dest, " that");
+ }else{
+ fprintf(message_dest, " , which");
+ }
+ fprintf(message_dest, " started");
+ }
+ fprintf(message_dest, " on line %d", saved_lineno);
+ if ( fil_is_diff )
+ {
+ fprintf(message_dest, " of file %s", saved_ifile);
+ }
+ }
+
+ if ( may_show_incolon )
+ {
+ in_last_colon();
+ }else{
+ fprintf(message_dest, "\n");
+ }
+ }
+}
+
+/* **************************************************************************
+ *
+ * Function name: started_at
+ * Synopsis: Supplemental back-reference message,
+ * with the "that started" phrase,
+ * and with last-colon identification.
+ *
+ * Inputs:
+ * Parameters:
+ * saved_ifile File-name saved for "back-reference"
+ * saved_lineno Line-number saved for "back-reference"
+ *
+ * Outputs:
+ * Returned Value: None
+ * Global Variables:
+ * Printout:
+ * The "...started at..." remainder of a message, giving a back-
+ * -reference to the "start" point supplied in the params,
+ * and the start of the current Colon-definition if one is
+ * in effect.
+ * Will supply a new-line and can be used to finish the line.
+ *
+ **************************************************************************** */
+
+void started_at( char * saved_ifile, unsigned int saved_lineno)
+{
+ print_where_started( TRUE, TRUE, saved_ifile, saved_lineno, TRUE);
+}
+
+
+/* **************************************************************************
+ *
+ * Function name: print_started_at
+ * Synopsis: Same as started_at() except output will be directed
+ * to stdout instead of to ERRMSG_DESTINATION
+ *
+ * Extraneous Remarks:
+ * A retrofit. Can you tell?
+ *
+ **************************************************************************** */
+
+void print_started_at( char * saved_ifile, unsigned int saved_lineno)
+{
+ message_dest = stdout;
+ started_at( saved_ifile, saved_lineno);
+ message_dest = ERRMSG_DESTINATION;
+}
+
+
+/* **************************************************************************
+ *
+ * Function name: just_started_at
+ * Synopsis: Supplemental back-reference message,
+ * with the "that started" phrase,
+ * but without last-colon identification.
+ *
+ * Inputs:
+ * Parameters:
+ * saved_ifile File-name saved for "back-reference"
+ * saved_lineno Line-number saved for "back-reference"
+ *
+ * Outputs:
+ * Returned Value: None
+ * Global Variables:
+ * Printout:
+ * The "...started at..." remainder of a message, giving a back-
+ * -reference to the "start" point supplied in the params,
+ * and no more.
+ * Will supply a new-line and can be used to finish the line.
+ *
+ **************************************************************************** */
+
+void just_started_at( char * saved_ifile, unsigned int saved_lineno)
+{
+ print_where_started( TRUE, TRUE, saved_ifile, saved_lineno, FALSE);
+}
+
+/* **************************************************************************
+ *
+ * Function name: where_started
+ * Synopsis: Supplemental back-reference message,
+ * without the "that started" phrase,
+ * but with last-colon identification.
+ *
+ * Inputs:
+ * Parameters:
+ * saved_ifile File-name saved for "back-reference"
+ * saved_lineno Line-number saved for "back-reference"
+ *
+ * Outputs:
+ * Returned Value: None
+ * Global Variables:
+ * Printout:
+ * The remainder of a message, giving a back-reference to the
+ * "start" point supplied in the parameters, and the start
+ * of the current Colon-definition if one is in effect.
+ * Will supply a new-line and can be used to finish the line.
+ *
+ **************************************************************************** */
+
+void where_started( char * saved_ifile, unsigned int saved_lineno)
+{
+ print_where_started( FALSE, FALSE, saved_ifile, saved_lineno, TRUE);
+}
+
+/* **************************************************************************
+ *
+ * Function name: just_where_started
+ * Synopsis: Supplemental back-reference message,
+ * without the "that started" phrase,
+ * and without last-colon identification.
+ *
+ * Inputs:
+ * Parameters:
+ * saved_ifile File-name saved for "back-reference"
+ * saved_lineno Line-number saved for "back-reference"
+ *
+ * Outputs:
+ * Returned Value: None
+ * Global Variables:
+ * Printout:
+ * The remainder of a message, giving a back-reference to the
+ * "start" point supplied in the parameters, and no more.
+ * Will supply a new-line and can be used to finish the line.
+ *
+ **************************************************************************** */
+
+void just_where_started( char * saved_ifile, unsigned int saved_lineno)
+{
+ print_where_started( FALSE, FALSE, saved_ifile, saved_lineno, FALSE);
+}
+
+/* **************************************************************************
+ *
+ * Function name: in_last_colon
+ * Synopsis: Supplemental back-reference message, identifying
+ * last Colon-definition if one is in effect.
+ * Can be used to finish the line in either case.
+ *
+ * Inputs:
+ * Parameters: NONE
+ * Global Variables:
+ * incolon TRUE if Colon-definition is in progress
+ * last_colon_defname Name of last colon-definition
+ * last_colon_filename File where last colon-def'n made
+ * last_colon_lineno Line number of last colon-def'n
+ * Local Static Variables:
+ * print_msg Whether the beginning part of the message
+ * was printed by tokenization_error()
+ * message_dest Message Destination. Is ERRMSG_DESTINATION
+ * (stdout) usually, except sometimes...
+ *
+ * Outputs:
+ * Returned Value: NONE
+ * Printout:
+ * Remainder of a message:
+ * "in definition of ... , which started ..."
+ *
+ * Process Explanation:
+ * Because this routine does some of its own printing, it needs
+ * to check the residual state of print_msg first.
+ * The calling routine does not need to test incolon ; it can
+ * call this to end the line in either case.
+ *
+ **************************************************************************** */
+
+void in_last_colon( void )
+{
+ if ( print_msg )
+ {
+ if ( incolon )
+ {
+ fprintf( message_dest, " in definition of %s ",
+ strupr( last_colon_defname) );
+ print_where_started( TRUE, FALSE,
+ last_colon_filename, last_colon_lineno, FALSE);
+ }else{
+ fprintf(message_dest, "\n");
+ }
+ }
+}
+
+
+/* **************************************************************************
+ *
+ * Function name: safe_malloc
+ * Synopsis: malloc with built-in failure test.
+ *
+ * Inputs:
+ * Parameters:
+ * size size_t Size of memory-chunk to allocate
+ * phrase char * Phrase to print after "... while "
+ * in case of failure.
+ *
+ * Outputs:
+ * Returned Value: Pointer to allocated memory
+ * Global Variables:
+ * fatal_err_exit On memory allocation failure, change
+ * to a special system-defined value
+ *
+ * Error Detection:
+ * On memory allocation failure, declare a FATAL error. Set up
+ * for a special system-defined EXIT value that indicates
+ * insufficient memory.
+ *
+ * Process Explanation:
+ * It is the responsibility of the calling routine to be sure
+ * the "phrase" is unique within the program. It is intended
+ * as a debugging aid, to help localize the point of failure.
+ *
+ **************************************************************************** */
+
+_PTR safe_malloc( size_t size, char *phrase)
+{
+ _PTR retval ;
+ retval = malloc (size);
+ if ( !retval )
+ {
+ fatal_err_exit = -ENOMEM ;
+ tokenization_error( FATAL, "Out of memory while %s.", phrase);
+ }
+ return ( retval );
+}
+
+/* **************************************************************************
+ *
+ * Function name: error_summary
+ * Synopsis: Summarize final error-message status
+ * before completing tokenization.
+ * Indicate if OK to produce output.
+ *
+ * Inputs:
+ * Parameters: NONE
+ * Global Variables:
+ * noerrors "Ignore Errors" flag, set by "-i" switch
+ * err_types_found Accumulated Error-types.
+ * error_categories Table of Error-types, Message-Counters
+ * and their printable names.
+ * opc FCode Output Buffer Position Counter
+ * (zero means there was no output).
+ *
+ * Outputs:
+ * Returned Value: True = OK to produce output (But caller
+ * must still verify non-zero opc)
+ * Printout:
+ * Various messages.
+ *
+ * Process Explanation:
+ * The first entry in the error_categories table is FATAL
+ * We won't need to print a tally of that...
+ *
+ **************************************************************************** */
+
+bool error_summary( void )
+{
+ /* Bit-mask of error-types that require suppressing output */
+ static const int suppress_mask = ( FATAL | TKERROR );
+ bool retval = TRUE;
+ bool suppressing = FALSE;
+
+ /* There's no escaping a FATAL error */
+ if ( ( err_types_found & FATAL ) != 0 )
+ {
+ /* FATAL error. Don't even bother with the tally. */
+ suppressing = TRUE;
+ } else {
+
+ if ( opc == 0 )
+ {
+ printf ( "Nothing Tokenized");
+ }else{
+ printf ( "Tokenization Completed");
+ }
+
+ if ( err_types_found != 0 )
+ {
+ int indx;
+ bool tally_started = FALSE ;
+ printf (". ");
+ /*
+ * Print a tally of the error-types;
+ * handle plurals and punctuation appropriately.
+ */
+ /* Start at indx = 1 to skip examining FATALs */
+ for ( indx = 1; indx < num_categories ; indx ++ )
+ {
+ if ( *(error_categories[indx].counter) > 0 )
+ {
+ printf ("%s %d %s%s",
+ tally_started ? "," : "" ,
+ *(error_categories[indx].counter),
+ error_categories[indx].category_name,
+ *(error_categories[indx].counter) > 1 ?
+ error_categories[indx].plural :
+ error_categories[indx].single );
+ /* Zero out the counter, to prevent displaying the
+ * number of Messages twice, since it's shared
+ * by the "Messages" and "P_Messages" categories.
+ */
+ *(error_categories[indx].counter) = 0;
+ tally_started = TRUE;
+ }
+ }
+ }
+ printf (".\n");
+
+ if ( ( err_types_found & suppress_mask ) != 0 )
+ { /* Errors found. Not OK to produce output */
+ /* Unless "Ignore Errors" flag set... */
+ if ( INVERSE(noerrors) )
+ {
+ suppressing = TRUE;
+ }else{
+ if ( opc > 0 )
+ {
+ printf ("Error-detection over-ridden; "
+ "producing binary output.\n");
+ }
+ }
+ }
+ }
+ if ( suppressing )
+ {
+ retval = FALSE ;
+ printf ("Suppressing binary output.\n");
+ }
+ return ( retval );
+}
+
Added: fcode-utils/toke/errhandler.h
===================================================================
--- fcode-utils/toke/errhandler.h (rev 0)
+++ fcode-utils/toke/errhandler.h 2006-08-18 12:47:12 UTC (rev 76)
@@ -0,0 +1,119 @@
+#ifndef _TOKE_ERRHANDLER_H
+#define _TOKE_ERRHANDLER_H
+
+/*
+ * OpenBIOS - free your system!
+ * ( FCode tokenizer )
+ *
+ * This program is part of a free implementation of the IEEE 1275-1994
+ * Standard for Boot (Initialization Configuration) Firmware.
+ *
+ * Copyright (C) 2001-2005 Stefan Reinauer, <stepan(a)openbios.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA, 02110-1301 USA
+ *
+ */
+
+/* **************************************************************************
+ *
+ * Function Prototypes for Tokenizer Error-Handler
+ *
+ * Defines symbols for the various classes of errors
+ * for the Error-Handler and for all its users
+ *
+ *
+ * (C) Copyright 2005 IBM Corporation. All Rights Reserved.
+ * Module Author: David L. Paktor dlpaktor(a)us.ibm.com
+ *
+ **************************************************************************** */
+
+#include "types.h"
+
+#define FATAL 0x80000000
+#define TKERROR 0x04000000
+#define WARNING 0x00200000
+#define INFO 0x00010000
+#define MESSAGE 0x00000800
+#define P_MESSAGE 0x00000040
+#define FORCE_MSG 0x00000001
+
+void init_error_handler( void);
+void tokenization_error( int err_type, char* msg, ... );
+void started_at( char * saved_ifile, unsigned int saved_lineno);
+void print_started_at( char * saved_ifile, unsigned int saved_lineno);
+void just_started_at( char * saved_ifile, unsigned int saved_lineno);
+void where_started( char * saved_ifile, unsigned int saved_lineno);
+void just_where_started( char * saved_ifile, unsigned int saved_lineno);
+void in_last_colon( void );
+_PTR safe_malloc( size_t size, char *phrase);
+bool error_summary( void ); /* Return TRUE if OK to produce output. */
+
+
+/* **************************************************************************
+ *
+ * Macros:
+ * ERRMSG_DESTINATION During development, I used this to switch
+ * error message destination between STDOUT and STDERR, until I
+ * settled on which is preferable. Recently, I have proven to
+ * my satisfaction that STDERR is preferable: error-messages
+ * produced by a sub-shell will be correctly synchronized with
+ * the error-messages we produce. When I tested using STDOUT
+ * for error-messages, that error-case looked garbled.
+ * FFLUSH_STDOUT fflush( stdout) if error message destination
+ * is STDERR, No-op if it's STDOUT. A few of these, judiciously
+ * placed, kept our own regular and error messages nicely in sync.
+ *
+ **************************************************************************** */
+
+#define ERRMSG_DESTINATION stderr
+#define FFLUSH_STDOUT fflush( stdout);
+
+/* We're no longer switching the above.
+ * The below is left here to show what had been done formerly.
+ */
+#if -1 /* Switchable error-message destination */
+#else /* Switchable error-message destination */
+#define ERRMSG_DESTINATION stdout
+#define FFLUSH_STDOUT /* Don't need to do anything here */
+#endif /* Switchable error-message destination */
+
+/* Some systems don't seem to have strupr */
+#ifdef SYS_IS_GNU_Linux
+#define NEEDS_STRUPR
+#endif /* SYS_IS_GNU_Linux */
+#ifdef SYS_IS_AIX
+#define NEEDS_STRUPR
+#endif /* SYS_IS_AIX */
+/* ??? Should this instead be tuned to Proc'r is PPC ??? Why? */
+
+#ifdef NEEDS_STRUPR
+
+/* **************************************************************************
+ *
+ * A necessary hack for systems that don't seem
+ * to have strupr and strlwr
+ * Let's avoid a naming conflict, just in case...
+ *
+ **************************************************************************** */
+
+extern char *strupper( char *strung);
+#define strupr strupper
+
+extern char *strlower( char *strung);
+#define strlwr strlower
+
+
+#endif /* NEEDS_STRUPR */
+
+#endif /* _TOKE_ERRHANDLER_H */
Added: fcode-utils/toke/flowcontrol.c
===================================================================
--- fcode-utils/toke/flowcontrol.c (rev 0)
+++ fcode-utils/toke/flowcontrol.c 2006-08-18 12:47:12 UTC (rev 76)
@@ -0,0 +1,2080 @@
+/*
+ * OpenBIOS - free your system!
+ * ( FCode tokenizer )
+ *
+ * This program is part of a free implementation of the IEEE 1275-1994
+ * Standard for Boot (Initialization Configuration) Firmware.
+ *
+ * Copyright (C) 2001-2005 Stefan Reinauer, <stepan(a)openbios.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA, 02110-1301 USA
+ *
+ */
+
+/* **************************************************************************
+ *
+ * Support Functions for tokenizing FORTH Flow-Control structures.
+ *
+ * (C) Copyright 2005 IBM Corporation. All Rights Reserved.
+ * Module Author: David L. Paktor dlpaktor(a)us.ibm.com
+ *
+ **************************************************************************** */
+
+/* **************************************************************************
+ *
+ * Functions Exported:
+ * These first two do their work after the calling routine
+ * has written the token for the required variant:
+ *
+ * mark_do Mark branches for "do" variants
+ * resolve_loop Resolve "loop" variants' branches
+ *
+ * The remaining routines' descriptions are all similar:
+ * Write the token(s), handle the outputs, mark
+ * or resolve the branches, and verify correct
+ * control-structure matching, for tokenizing
+ * the ........................ statement in FORTH
+ * emit_if IF
+ * emit_else ELSE
+ * emit_then THEN
+ * emit_begin BEGIN
+ * emit_again AGAIN
+ * emit_until UNTIL
+ * emit_while WHILE
+ * emit_repeat REPEAT
+ * emit_case CASE
+ * emit_of OF
+ * emit_endof ENDOF
+ * emit_endcase ENDCASE
+ *
+ * Three additional routines deal with matters of overall balance
+ * of the Control-Structures, and identify the start of any that
+ * were not balanced. The first just displays Messages:
+ *
+ * announce_control_structs
+ *
+ * The other two clear and re-balance them:
+ *
+ * clear_control_structs_to_limit
+ * clear_control_structs
+ *
+ **************************************************************************** */
+
+/* **************************************************************************
+ *
+ * Still to be done:
+ * Correct analysis of Return-Stack usage around Flow-Control
+ * constructs, including within Do-Loops or before Loop
+ * Elements like I and J or UNLOOP or LEAVE.
+ * Similarly, Return-Stack usage around IF ... ELSE ... THEN
+ * statements needs analysis. For instance, the following:
+ *
+ * blablabla >R yadayada IF R> gubble ELSE flubble R> THEN
+ *
+ * is, in fact, correct, while something like:
+ *
+ * blablabla >R yadayada IF R> gubble THEN
+ *
+ * is an error.
+ *
+ * Implementing an analysis that would be sufficiently accurate
+ * to justify reporting an ERROR with certainty (rather than
+ * a mere WARNING speculatively) would probably require full
+ * coordination with management of Flow-Control constructs,
+ * and so is noted here.
+ *
+ **************************************************************************** */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "types.h"
+#include "toke.h"
+#include "emit.h"
+#include "vocabfuncts.h"
+#include "scanner.h"
+#include "stack.h"
+#include "errhandler.h"
+#include "flowcontrol.h"
+#include "stream.h"
+
+/* **************************************************************************
+ *
+ * Global Variables Imported
+ * opc FCode Output Buffer Position Counter
+ * noerrors "Ignore Errors" flag, set by "-i" switch
+ * do_loop_depth How deep we are inside DO ... LOOP variants
+ * incolon State of tokenization; TRUE if inside COLON
+ * statbuf The word just read from the input stream
+ * iname Name of input file currently being processed
+ * lineno Current line-number being processed
+ *
+ **************************************************************************** */
+
+/* **************************************************************************
+ *
+ * Global Variables Exported
+ * control_stack_depth Number of items on "Control-Stack"
+ *
+ **************************************************************************** */
+
+int control_stack_depth = 0;
+
+
+/* **************************************************************************
+ *
+ * Internal Static Functions:
+ * push_cstag Push an item onto the Control-Stack
+ * pop_cstag Pop one item from the Control-Stack
+ * control_stack_size_test Test C-S depth; report if error
+ * control_structure_mismatch Print error-message
+ * offset_too_large Print error-message
+ * matchup_control_structure Error-check Control-Stack
+ * matchup_two_control_structures Error-check two Control-Stack entries
+ * emit_fc_offset Error-check and output FCode-Offset
+ * control_structure_swap Swap control-struct branch-markers
+ * mark_backward_target Mark target of backward-branch
+ * resolve_backward Resolve backward-target for branch
+ * mark_forward_branch Mark forward-branch
+ * resolve_forward Resolve forward-branch at target
+ *
+ **************************************************************************** */
+
+/* **************************************************************************
+ *
+ * Internal Named Constants
+ * Note: These control-structure identifier tags -- a.k.a. cstags --
+ * are used to identify the matching components of particular
+ * control-structures. They are passed as parameters, and either
+ * "Pushed" onto the "Control-Stack", or compared with what is on
+ * "Top" of the "Control-Stack", as an error-check.
+ *
+ * name used by forth words:
+ * BEGIN_CSTAG BEGIN AGAIN UNTIL REPEAT
+ * IF_CSTAG IF ELSE THEN
+ * WHILE_CSTAG WHILE REPEAT THEN
+ * DO_CSTAG DO ?DO LOOP +LOOP
+ * CASE_CSTAG CASE OF ENDCASE
+ * OF_CSTAG OF ENDOF
+ * ENDOF_CSTAG ENDOF ENDCASE
+ *
+ * The numbers assigned are arbitrary; they were selected for a
+ * high unlikelihood of being encountered in normal usage,
+ * and constructed with a hint of mnemonic value in mind.
+ *
+ **************************************************************************** */
+ /* Mnemonic: */
+#define BEGIN_CSTAG 0xC57be916 /* CST BEGIN */
+#define IF_CSTAG 0xC57A901f /* CSTAG (0) IF */
+#define WHILE_CSTAG 0xC573412e /* CST WHILE */
+#define DO_CSTAG 0xC57A90d0 /* CSTAG (0) DO */
+#define CASE_CSTAG 0xC57Aca5e /* CSTA CASE */
+#define OF_CSTAG 0xC57A90f0 /* CSTAG OF (0) */
+#define ENDOF_CSTAG 0xC57e6d0f /* CST ENDOF */
+
+
+/* **************************************************************************
+ *
+ * Control-Structure identification, matching, completion and error
+ * messaging will be supported by a data structure, which we
+ * will call a CSTAG-Group
+ *
+ * It consists of one "Data-item" and several "Marker" items, thus:
+ *
+ * The Data-item in most cases will be a value of OPC (the Output
+ * Buffer Position Counter) which will be used in calculating
+ * an offset or placing an offset or both, as the case may be,
+ * for the control structure in question. The one exception
+ * is for a CSTAG-Group generated by a CASE statement; its
+ * Data-item will be an integer count of the number of "OF"s
+ * to be resolved when the ENDCASE statement is reached.
+ *
+ * The CSTAG for the FORTH word, as described above
+ * The name of the input file in which the word was encountered
+ * (actually, a pointer to a mem-alloc'ed copy of the filename)
+ * The line number, within the input file, of the word's invocation
+ * The Absolute Token Number in all Source Input of the word
+ * The FORTH word that started the structure, (used in error messages)
+ * A flag to indicate when two CSTAG-Groups are created together,
+ * which will be used to prevent duplicate error messages when,
+ * for instance, a DO is mismatched with a REPEAT .
+ *
+ **************************************************************************** */
+
+/* **************************************************************************
+ *
+ * "Control-Stack" Diagram Notation
+ *
+ * The CSTAG-Groups will be kept in an order resembling a data-stack,
+ * (even though it won't be the data-stack itself). We will refer
+ * to this list of structures as the "Control Stack", and in our
+ * comments we will show their arrangement in a format resembling
+ * stack-diagram remarks.
+ *
+ * In these "Control-Stack Diagrams", we will use the notation:
+ * <Stmt>_{FOR|BACK}w_<TAGNAM>
+ * to represent a CSTAG-Group generated by a <Stmt> -type of
+ * statement, with a "FORw"ard or "BACKw"ard branch-marker and
+ * a CSTAG of the <TAGNAM> type.
+ *
+ * A CASE-CSTAG-Group will have a different notation:
+ * N_OFs...CASE_CSTAG
+ *
+ * In all cases, a CSTAG-Group will be manipulated as a unit.
+ *
+ * The notation for Control-Stack Diagram remarks will largely resemble
+ * the classic form used in FORTH, i.e., enclosed in parentheses,
+ * lowest item to the left, top item on the right, with a double-
+ * hyphen to indicate "before" or "after".
+ *
+ * Enclosure in {curly-braces} followed by a subscript-range indicates
+ * that the Stack-item or Group is repeated.
+ *
+ **************************************************************************** */
+
+/* **************************************************************************
+ *
+ * We are not keeping the "Control Stack" structures on the regular
+ * data stack because a sneaky combination of user-inputs could
+ * throw things into chaos were we to use that scheme. Consider
+ * what would happen if a number were put on the stack, say, in
+ * tokenizer-escape mode, in between elements of a flow-control
+ * structure... Theoretically, there is no reason to prohibit
+ * that, but it would be unexpectedly problematical for most
+ * FORTH-based tokenizers.
+ *
+ * Maintaining the "Control Stack" structures in a linked-list would
+ * be a more nearly bullet-proof approach. The theory of operation
+ * would be the same, broadly speaking, and there would be no need
+ * to check for NOT_CSTAG and no risk of getting the elements of
+ * the control-structures out of sync.
+ *
+ **************************************************************************** */
+
+/* **************************************************************************
+ *
+ * Structure Name: cstag_group_t
+ * Synopsis: Control-Structure Tag Group
+ *
+ * Fields:
+ * cs_tag Control-structure identifier tag
+ * cs_inp_fil Name of input file where C-S was started
+ * cs_line_num Line-number in Current Source when C-S was started
+ * cs_abs_token_num "Absolute" Token Number when C-S was started
+ * cs_word The FORTH word that started the C-S
+ * cs_not_dup FALSE if second "Control Stack" entry for same word
+ * cs_datum Data-Item of the Group
+ * prev Pointer to previous CSTAG-Group in linked-list
+ *
+ * All data using this structure will remain private to this file,
+ * so we declare it here rather than in the .h file
+ *
+ **************************************************************************** */
+
+typedef struct cstag_group {
+ unsigned long cs_tag;
+ char *cs_inp_fil;
+ unsigned int cs_line_num;
+ unsigned int cs_abs_token_num;
+ char *cs_word;
+ bool cs_not_dup;
+ unsigned long cs_datum;
+ struct cstag_group *prev;
+} cstag_group_t;
+
+/* **************************************************************************
+ *
+ * Internal Static Variables
+ * control_stack "Thread" Pointer to the linked-list of
+ * "Control Stack" structure entries
+ * not_cs_underflow Flag used to prevent duplicate messages
+ * not_consuming_two Flag used to prevent loss of messages
+ * didnt_print_otl Flag used to prevent duplicate messages
+ *
+ **************************************************************************** */
+
+static cstag_group_t *control_stack = NULL; /* "Top" of the "Stack" */
+
+/* **************************************************************************
+ *
+ * not_cs_underflow is used only by routines that make two calls to
+ * resolve a marker. It is set TRUE before the first call; if
+ * that call had a control-stack underflow, the error-message
+ * routine resets it to FALSE. The calling routine can then
+ * test it as the condition for the second call.
+ * Routines that make only one call to resolve a marker can ignore it.
+ *
+ **************************************************************************** */
+
+static bool not_cs_underflow; /* No need to initialize. */
+
+/* **************************************************************************
+ *
+ * not_consuming_two is also used only by routines that make two calls
+ * to resolve a marker, but for this case, those routines only need
+ * to reset it to FALSE and not to test it; that will be done by
+ * the control_structure_mismatch() routine when it looks at
+ * the cs_not_dup field. If the mismatch occurred because of
+ * a combination of control-structures that consume one each,
+ * the message will be printed even for the second "Control Stack"
+ * entry. The routine that changed it will have to set it back to
+ * TRUE when it's done with it.
+ *
+ * didnt_print_otl is used similarly, but only for the offset-too-large
+ * error in the DO ... LOOP type of control-structures.
+ *
+ **************************************************************************** */
+
+static bool not_consuming_two = TRUE;
+static bool didnt_print_otl = TRUE;
+
+
+/* **************************************************************************
+ *
+ * Function name: push_cstag
+ * Synopsis: Push a new CSTAG-Group onto the front ("Top")
+ * of the (notional) Control-Stack.
+ *
+ * Inputs:
+ * Parameters:
+ * cstag ID Tag for Control-Structure to "Push"
+ * datum The Data-Item for the new CSTAG-Group
+ * Global Variables:
+ * iname Name of input file currently being processed
+ * lineno Current-Source line-number being processed
+ * abs_tokenno "Absolute"Token Number of word being processed
+ * statbuf The word just read, which started the C-S
+ * Local Static Variables:
+ * control_stack Will become the new entry's "prev"
+ *
+ * Outputs:
+ * Returned Value: None
+ * Global Variables:
+ * control_stack_depth Incremented
+ * Local Static Variables:
+ * control_stack Will become the "previous" entry in the list
+ * Items Pushed onto Control-Stack:
+ * Top: A new CSTAG-Group, params as given
+ * Memory Allocated
+ * New CSTAG-Group structure
+ * Duplicate of name of current input file
+ * Duplicate of word just read
+ * When Freed?
+ * When Removing a CSTAG-Group, in pop_cstag()
+ *
+ **************************************************************************** */
+
+static void push_cstag( unsigned long cstag, unsigned long datum)
+{
+ cstag_group_t *cs_temp;
+
+ cs_temp = control_stack;
+ control_stack = safe_malloc( sizeof(cstag_group_t), "pushing CSTag");
+
+ control_stack->cs_tag = cstag;
+ control_stack->cs_inp_fil = strdup(iname);
+ control_stack->cs_line_num = lineno;
+ control_stack->cs_abs_token_num = abs_token_no;
+ control_stack->cs_word = strdup(statbuf);
+ control_stack->cs_not_dup = TRUE;
+ control_stack->cs_datum = datum;
+ control_stack->prev = cs_temp;
+
+ control_stack_depth++;
+
+}
+
+/* **************************************************************************
+ *
+ * Function name: pop_cstag
+ * Synopsis: Remove a CSTAG-Group from the front ("Top") of the
+ * (notional) Control-Stack.
+ *
+ * Inputs:
+ * Parameters: NONE
+ * Global Variables:
+ * Local Static Variables:
+ * control_stack CSTAG-Group on "Top"
+ *
+ * Outputs:
+ * Returned Value: NONE
+ * Global Variables:
+ * control_stack_depth Decremented
+ * Local Static Variables:
+ * control_stack "Previous" entry will become current
+ * Memory Freed
+ * mem-alloc'ed copy of input filename
+ * mem-alloc'ed copy of Control-structure FORTH word
+ * CSTAG-Group structure
+ * Control-Stack, # of Items Popped: 1
+ *
+ * Process Explanation:
+ * The calling routine might not check for empty Control-Stack,
+ * so we have to be sure and check it here.
+ *
+ **************************************************************************** */
+
+static void pop_cstag( void)
+{
+
+ if ( control_stack != NULL )
+ {
+ cstag_group_t *cs_temp;
+
+ cs_temp = control_stack->prev;
+ free( control_stack->cs_word );
+ free( control_stack->cs_inp_fil );
+ free( control_stack );
+ control_stack = cs_temp;
+
+ control_stack_depth--;
+ }
+}
+
+/* **************************************************************************
+ *
+ * Function name: control_stack_size_test
+ * Synopsis: Detect Control Stack underflow; report if an ERROR.
+ *
+ * Inputs:
+ * Parameters:
+ * min_depth Minimum depth needed
+ * Global Variables:
+ * control_stack_depth Current depth of Control Stack
+ * statbuf Word to name in error message
+ *
+ * Outputs:
+ * Returned Value: TRUE if adequate depth
+ * Local Static Variables:
+ * not_cs_underflow Reset to FALSE if underflow detected.
+ * Printout:
+ * Error message is printed.
+ * Identify the colon definition if inside one.
+ *
+ * Process Explanation:
+ * Some statements need more than one item on the Control Stack;
+ * they will do their own control_stack_depth testing and
+ * make a separate call to this routine.
+ *
+ **************************************************************************** */
+
+static bool control_stack_size_test( int min_depth )
+{
+ bool retval = TRUE;
+
+ if ( control_stack_depth < min_depth )
+ {
+ retval = FALSE;
+ tokenization_error ( TKERROR,
+ "Control-Stack underflow at %s", strupr(statbuf) );
+ in_last_colon();
+
+ not_cs_underflow = FALSE; /* See expl'n early on in this file */
+ }
+
+ return( retval );
+}
+
+/* **************************************************************************
+ *
+ * Function name: control_structure_mismatch
+ * Synopsis: Report an ERROR after a Control Structure mismatch
+ * was detected.
+ *
+ * Inputs:
+ * Parameters: NONE
+ * Global Variables:
+ * statbuf Word encountered, to name in error message
+ * Local Static Variables:
+ * control_stack "Pushed" Control-Structure Tag Group
+ * not_consuming_two See explanation early on in this file
+ * Control-Stack Items:
+ * Top: "Current" Control-Structure Tag Group
+ * Some of its "Marker" information
+ * will be used in the error message
+ *
+ * Outputs:
+ * Returned Value: NONE
+ * Printout:
+ * Error message is printed
+ *
+ * Process Explanation:
+ * This routine is called after a mismatch is detected, and
+ * before the CSTAG-Group is "Popped" from the notional
+ * Control-Stack.
+ * If the control_stack pointer is NULL, print a different
+ * Error message
+ * Don't print if the "Control Stack" entry is a duplicate and
+ * we're processing a statement that consumes two entries.
+ *
+ **************************************************************************** */
+
+static void control_structure_mismatch( void )
+{
+ if ( control_stack->cs_not_dup || not_consuming_two )
+ {
+ tokenization_error ( TKERROR,
+ "The %s is mismatched with the %s" ,
+ strupr(statbuf), strupr(control_stack->cs_word));
+ where_started( control_stack->cs_inp_fil, control_stack->cs_line_num );
+ }
+}
+
+
+/* **************************************************************************
+ *
+ * Function name: offset_too_large
+ * Synopsis: Report an ERROR after a too-large fcode-offset
+ * was detected.
+ *
+ * Inputs:
+ * Parameters:
+ * too_large_for_16 TRUE if the offset is too large to be
+ * expressed as a 16-bit signed number.
+ * Global Variables:
+ * statbuf Word encountered, to name in error message
+ * offs16 Whether we are using 16-bit offsets
+ * Local Static Variables:
+ * control_stack "Pushed" Control-Structure Tag Group
+ * didnt_print_otl Switch to prevent duplicate message
+ * Control-Stack Items:
+ * Top: "Current" Control-Structure Tag Group
+ * Some of its "Marker" information
+ * will be used in the error message
+ *
+ * Outputs:
+ * Returned Value: NONE
+ * Local Static Variables:
+ * didnt_print_otl Will be reset to FALSE
+ *
+ * Printout:
+ * Error message:
+ * Branch offset too large between <here> and <there>
+ * Advisory message, if we are using 8-bit offsets, will
+ * indicate whether switching to 16-bit offsets would help
+ *
+ * Process Explanation:
+ * Two branches are involved in a DO ... LOOP structure: an "outer"
+ * forward-branch and a slightly smaller "inner" backward-branch.
+ * In the majority of cases, if one offset exceeds the limit,
+ * both will. There is, however, a very small but distinct
+ * possibility that the offset for the smaller branch will not
+ * exceed the limit while the larger one does. To prevent two
+ * messages from being printed in the routine instance, but still
+ * assure that one will be printed in the rare eventuality, we
+ * utilize the flag called didnt_print_otl in conjunction
+ * with the cs_not_dup field.
+ *
+ **************************************************************************** */
+
+static void offset_too_large( bool too_large_for_16 )
+{
+ if ( control_stack->cs_not_dup || didnt_print_otl )
+ {
+ tokenization_error( TKERROR,
+ "Branch offset is too large between %s and the %s" ,
+ strupr(statbuf), strupr(control_stack->cs_word));
+ where_started( control_stack->cs_inp_fil, control_stack->cs_line_num );
+ if ( INVERSE( offs16 ) )
+ {
+ if ( too_large_for_16 )
+ {
+ tokenization_error ( INFO,
+ "Offset would be too large even if 16-bit offsets "
+ "were in effect.\n");
+ }else{
+ tokenization_error ( INFO,
+ "Offset might fit if 16-bit offsets "
+ "(e.g., fcode-version2) were used.\n" );
+ }
+ }
+ }
+ didnt_print_otl = FALSE;
+}
+
+/* **************************************************************************
+ *
+ * Function name: emit_fc_offset
+ * Synopsis: Test whether the given FCode-Offset is out-of-range;
+ * before placing it into the FCode Output Buffer.
+ *
+ * Inputs:
+ * Parameters:
+ * fc_offset The given FCode-Offset
+ * Global Variables:
+ * offs16 Whether we are using 16-bit offsets
+ * noerrors "Ignore Errors" flag
+ *
+ * Outputs:
+ * Returned Value: NONE
+ *
+ * Error Detection:
+ * Error if the given FCode-Offset exceeds the range that can
+ * be expressed by the size (i.e., 8- or 16- -bits) of the
+ * offsets we are using. Call offset_too_large() to print
+ * the Error message; also, if noerrors is in effect, issue
+ * a Warning showing the actual offset and how it will be coded.
+ *
+ * Process Explanation:
+ * For forward-branches, the OPC will have to be adjusted to
+ * indicate the location that was reserved for the offset
+ * to be written, rather than the current location. That
+ * will all be handled by the calling routine.
+ * We will rely on "C"'s type-conversion (type-casting) facilities.
+ * Look at the offset value both as an 8-bit and as a 16-bit offset,
+ * then determine the relevant course of action.
+ *
+ **************************************************************************** */
+
+static void emit_fc_offset( int fc_offset)
+{
+ int fc_offs_s16 = (s16)fc_offset;
+ int fc_offs_s8 = (s8)fc_offset;
+ bool too_large_for_8 = BOOLVAL( fc_offset != fc_offs_s8 );
+ bool too_large_for_16 = BOOLVAL( fc_offset != fc_offs_s16);
+
+ if ( too_large_for_16 || ( INVERSE(offs16) && too_large_for_8 ) )
+ {
+ offset_too_large( too_large_for_16 );
+ if ( noerrors )
+ {
+ int coded_as = offs16 ? (int)fc_offs_s16 : (int)fc_offs_s8 ;
+ tokenization_error( WARNING,
+ "Actual offset is 0x%x (=dec %d), "
+ "but it will be coded as 0x%x (=dec %d).\n",
+ fc_offset, fc_offset, coded_as, coded_as );
+ }
+ }
+
+ emit_offset( fc_offs_s16 );
+}
+
+
+/* **************************************************************************
+ *
+ * Function name: matchup_control_structure
+ * Synopsis: Error-check. Compare the given control-structure
+ * identifier tag with the one in the CSTAG-Group
+ * on "Top" of the "Control Stack".
+ * If they don't match, report an error, and, if not
+ * "Ignoring Errors", return Error indication.
+ * If no error, pass the Data-item back to the caller.
+ * Do not consume the CSTAG-Group; that will be the
+ * responsibility of the calling routine.
+ *
+ * Inputs:
+ * Parameters:
+ * cstag Control-struc ID Tag expected by calling function
+ * Global Variables:
+ * noerrors "Ignore Errors" flag
+ * Local Static Variables:
+ * control_stack "Pushed" (current) Control-Structure Tag Group
+ * Control-Stack Items:
+ * Top: Current CSTAG-Group
+ *
+ * Outputs:
+ * Returned Value: TRUE = Successful match, no error.
+ *
+ * Error Detection:
+ * Control Stack underflow or cstag mismatch. See below for details.
+ *
+ * Process Explanation:
+ * If the expected cstag does not match the cs_tag from the CSTAG
+ * Group on "Top" of the "Control Stack", print an ERROR message,
+ * and, unless the "Ignore Errors" flag is in effect, prepare
+ * to return FALSE.
+ * However, if we've "underflowed" the "Control Stack", we dare not
+ * ignore errors; that could lead to things like attempting to
+ * write a forward-branch FCode-offset to offset ZERO, over the
+ * FCODE- or PCI- -header block. We don't want that...
+ * So, if the control_stack pointer is NULL, we will print an
+ * ERROR message and immediately return FALSE.
+ * Since we will not consume the CSTAG-Group, the calling routine
+ * can access the Data-Item and any "Marker" information it may
+ * still require via the local control_stack pointer. The caller
+ * will be responsible for removing the CSTAG-Group.
+ *
+ * Special Exception to "Ignore Errors":
+ * At the last usage of the CASE_CSTAG , for the ENDCASE statement,
+ * this routine will be called to control freeing-up memory, etc.
+ * For the OF statement, it will be called to control incrementing
+ * the OF-count datum.
+ * Processing an ENDCASE statement with the datum from any other
+ * CSTAG-Group can lead to a huge loop.
+ * Processing any other "resolver" with the datum from an ENDCASE
+ * CSTAG-Group can lead to mistaking a very low number for an
+ * offset into the Output Buffer and attempting to write to it.
+ * Incrementing the datum from any other CSTAG-Group can lead to
+ * a variety of unacceptable errors, too many to guess.
+ * So, if either the given cstag or the cs_tag field of the "Top"
+ * CSTAG-Group is a CASE_CSTAG , we will not ignore errors.
+ *
+ **************************************************************************** */
+
+static bool matchup_control_structure( unsigned long cstag )
+{
+ bool retval = FALSE;
+
+ if ( control_stack_size_test( 1) )
+ {
+ retval = TRUE;
+
+ if ( control_stack->cs_tag != cstag )
+ {
+ control_structure_mismatch();
+
+ if ( ( INVERSE(noerrors) )
+ || ( cstag == CASE_CSTAG )
+ || ( control_stack->cs_tag == CASE_CSTAG )
+ )
+ {
+ retval = FALSE;
+ }
+ }
+
+ }
+ return ( retval );
+}
+
+/* **************************************************************************
+ *
+ * Function name: control_structure_swap
+ * Synopsis: Swap control-structure branch-marker Groups
+ *
+ * Inputs:
+ * Parameters: NONE
+ * Local Static Variables:
+ * control_stack Pointer to "Control Stack" linked-list
+ * Control-Stack Items:
+ * Top: CSTAG-Group_0
+ * Next: CSTAG-Group_1
+ *
+ * Outputs:
+ * Returned Value: NONE
+ * Local Static Variables:
+ * control_stack Points to former "previous" and vice-versa
+ * Items on Control-Stack:
+ * Top: CSTAG-Group_1
+ * Next: CSTAG-Group_0
+ *
+ * Error Detection:
+ * If control-stack depth is not at least 2, CS underflow ERROR.
+ * This might trigger other routines' error detections also...
+ *
+ * Extraneous Remarks:
+ * Before control-structure identification was implemented, offsets
+ * were kept on the data-stack, and this was a single SWAP.
+ * When CSTAGs were added, the "Group" was only a pair kept on the
+ * data-stack -- the CSTAG and the Data-item -- and this
+ * became a TWO_SWAP()
+ * For a while, when I tried keeping the CSTAG-Group on the stack,
+ * this became a FOUR_SWAP()
+ * That turned out to be unacceptably brittle; this way is much
+ * more robust.
+ * I am so glad I called this functionality out into a separate
+ * routine, early on in the development process.
+ *
+ * This is the function called 1 CSROLL in section A.3.2.3.2
+ * of the ANSI Forth spec, which likewise corresponds to the
+ * modifier that Wil Baden, in his characteristically elegant
+ * nomenclature, dubbed: BUT
+ *
+ **************************************************************************** */
+
+static void control_structure_swap( void )
+{
+ if ( control_stack_size_test( 2) )
+ {
+ cstag_group_t *cs_temp;
+
+ cs_temp = control_stack->prev;
+
+ control_stack->prev = cs_temp->prev;
+ cs_temp->prev = control_stack;
+ control_stack = cs_temp;
+ }
+}
+
+/* **************************************************************************
+ *
+ * Function name: matchup_two_control_structures
+ * Synopsis: For functions that resolve two CSTAG-Groups, both
+ * matchup both "Top of Control Stack" entries
+ * before processing them...
+ *
+ * Inputs:
+ * Parameters:
+ * top_cstag Control-struc ID Tag expected on "Top" CS entry
+ * next_cstag Control-struc ID Tag expected on "Next" CS entry
+ * Local Static Variables:
+ * not_cs_underflow Used for underflow detection.
+ * Control-Stack Items:
+ * Top: Current CSTAG-Group
+ * Next: Next CSTAG-Group
+ *
+ * Outputs:
+ * Returned Value: TRUE = Successful matches, no error.
+ * Global Variables:
+ * noerrors "Ignore Errors" flag; cleared, then restored
+ * Local Static Variables:
+ * not_consuming_two Cleared, then restored
+ * Control-Stack, # of Items Popped: 2 (if matches unsuccessful)
+ *
+ * Error Detection:
+ * Control Stack underflow detected by control_structure_swap()
+ * Control Structure mismatch detected by control_structure_mismatch()
+ *
+ * Process Explanation:
+ * We will use matchup_control_structure() to do the "heavy lifting".
+ * We will not be ignoring errors in these cases.
+ * Save the results of a match of top_cstag
+ * Swap the top two CS entries.
+ * If an underflow was detected, there's no more matching to be done.
+ * Otherwise:
+ * Save the results of a match of next_cstag
+ * Swap the top two CS entries again, to their original order.
+ * The result is TRUE if both matches were successful.
+ * If the matches were not successful, consume the top two entries
+ * (unless there's only one, in which case consume it).
+ *
+ **************************************************************************** */
+
+static bool matchup_two_control_structures( unsigned long top_cstag,
+ unsigned long next_cstag)
+{
+ bool retval;
+ bool topmatch;
+ bool nextmatch = FALSE;
+ bool sav_noerrors = noerrors;
+ noerrors = FALSE;
+ not_consuming_two = FALSE;
+
+ not_cs_underflow = TRUE;
+ topmatch = matchup_control_structure( top_cstag);
+ if ( not_cs_underflow )
+ {
+ control_structure_swap();
+ if ( not_cs_underflow )
+ {
+ nextmatch = matchup_control_structure( next_cstag);
+ control_structure_swap();
+ }
+ }
+
+ retval = BOOLVAL( topmatch && nextmatch);
+
+ if ( INVERSE( retval) )
+ {
+ pop_cstag();
+ pop_cstag();
+ }
+
+ not_consuming_two = TRUE;
+ noerrors = sav_noerrors;
+ return ( retval );
+}
+
+/* **************************************************************************
+ *
+ * Function name: mark_backward_target
+ * Synopsis: Mark the target of an expected backward-branch
+ *
+ * Associated FORTH words: BEGIN DO ?DO
+ *
+ * Inputs:
+ * Parameters:
+ * cstag Control-structure ID tag for calling function
+ * Global Variables:
+ * opc Output Buffer Position Counter
+ *
+ * Outputs:
+ * Returned Value: NONE
+ * Items Pushed onto Control-Stack:
+ * Top: <Stmt>_BACKw_<TAGNAM>
+ *
+ * Process Explanation:
+ * Just before this function is called, the token that begins the
+ * control-structure was written to the FCode Output buffer.
+ * OPC, the FCode Output Buffer Position Counter, is at the
+ * destination to which the backward-branch will be targeted.
+ * Create a CSTAG-Group with the given C-S Tag, and OPC as its datum;
+ * push it onto the Control-Stack.
+ * Later, when the backward-branch is installed, the FCode-offset
+ * will be calculated as the difference between the OPC at
+ * that time and the target-OPC we saved here.
+ *
+ **************************************************************************** */
+
+static void mark_backward_target(unsigned long cstag )
+{
+ push_cstag( cstag, (unsigned long)opc);
+}
+
+/* **************************************************************************
+ *
+ * Function name: mark_forward_branch
+ * Synopsis: Mark the location of, and reserve space for, the
+ * FCode-offset associated with a forward branch.
+ *
+ * Associated FORTH words: IF WHILE ELSE
+ *
+ * Inputs:
+ * Parameters:
+ * cstag Control-structure ID tag for calling function
+ *
+ * Outputs:
+ * Returned Value: NONE
+ * Items Pushed onto Control-Stack:
+ * Top: <Stmt>_FORw_<TAGNAM>
+ * FCode Output buffer:
+ * Place-holder FCode-offset of zero.
+ *
+ * Process Explanation:
+ * Just before this function is called, the forward-branch token
+ * that begins the control-structure was written to the FCode
+ * Output buffer.
+ * It will need an FCode-offset to the destination to which it will
+ * be targeted, once that destination is known.
+ * Create a CSTAG-Group with the given C-S Tag, and OPC as its datum;
+ * push it onto the Control-Stack. (This is the same action as
+ * for marking a backward-target.)
+ * Then write a place-holder FCode-offset of zero to the FCode
+ * Output buffer.
+ * Later, when the destination is known, the FCode-offset will be
+ * calculated as the difference between the OPC at that time
+ * and the FCode-offset location we're saving now. That offset
+ * will be over-written onto the place-holder offset of zero at
+ * the location in the Output buffer that we saved on the
+ * Control-Stack in this routine.
+ *
+ **************************************************************************** */
+
+static void mark_forward_branch(unsigned long cstag )
+{
+ mark_backward_target(cstag );
+ emit_offset(0);
+}
+
+/* **************************************************************************
+ *
+ * Function name: resolve_backward
+ * Synopsis: Resolve backward-target when a backward branch
+ * is reached. Write FCode-offset to reach saved
+ * target from current location.
+ *
+ * Associated FORTH words: AGAIN UNTIL REPEAT
+ * LOOP +LOOP
+ *
+ * Inputs:
+ * Parameters:
+ * cstag Control-structure ID tag for calling function
+ * Global Variables:
+ * opc Output Buffer Position Counter
+ * Control-Stack Items:
+ * Top: <Stmt>_BACKw_<TAGNAM>
+ *
+ * Outputs:
+ * Returned Value: NONE
+ * Global Variables:
+ * opc Incremented by size of an FCode-offset
+ * Control-Stack, # of Items Popped: 1
+ * FCode Output buffer:
+ * FCode-offset to reach backward-target
+ *
+ * Error Detection:
+ * Test for Control-structure ID tag match.
+ *
+ * Process Explanation:
+ * Just before this function is called, the backward-branch token
+ * that ends the control-structure was written to the FCode
+ * Output buffer.
+ * The current OPC is at the point from which the FCode-offset
+ * is to be calculated, and at which it is to be written.
+ * The top of the Control-Stack should have the CSTAG-Group from
+ * the statement that prepared the backward-branch target that
+ * we expect to resolve. Its datum is the OPC of the target
+ * of the backward branch.
+ * If the supplied Control-structure ID tag does not match the one
+ * on top of the Control-Stack, announce an error. We will
+ * still write an FCode-offset, but it will be a place-holder
+ * of zero.
+ * Otherwise, the FCode-offset we will write will be the difference
+ * between the target-OPC and our current OPC.
+ *
+ **************************************************************************** */
+
+static void resolve_backward( unsigned long cstag)
+{
+ unsigned long targ_opc;
+ int fc_offset = 0;
+
+ if ( matchup_control_structure( cstag) )
+ {
+ targ_opc = control_stack->cs_datum;
+ fc_offset = targ_opc - opc;
+ }
+
+ emit_fc_offset( fc_offset );
+ pop_cstag();
+}
+
+/* **************************************************************************
+ *
+ * Function name: resolve_forward
+ * Synopsis: Resolve a forward-branch when its target has been
+ * reached. Write the FCode-offset into the space
+ * that was reserved.
+ *
+ * Associated FORTH words: ELSE THEN REPEAT
+ * LOOP +LOOP
+ *
+ * Inputs:
+ * Parameters:
+ * cstag Control-structure ID tag for calling function
+ * Global Variables:
+ * opc Output Buffer Position Counter
+ * Control-Stack Items:
+ * Top: <Stmt>_FORw_<TAGNAM>
+ *
+ * Outputs:
+ * Returned Value: NONE
+ * Global Variables:
+ * opc Changed, then restored.
+ * Control-Stack, # of Items Popped: 1
+ * FCode Output buffer:
+ * FCode-offset is written to location where space was reserved
+ * when the forward-branch was marked.
+ *
+ * Error Detection:
+ * Test for Control-structure ID tag match.
+ *
+ * Process Explanation:
+ * Just before this function is called, the last token -- and
+ * possibly, FCode-offset -- that is within the scope of
+ * what the branch might skip was written to the FCode
+ * Output buffer.
+ * The current OPC is at the point from which the FCode-offset
+ * is to be calculated, but not at which it is to be written.
+ * The top of the Control-Stack should have the CSTAG-Group from
+ * the statement that prepared the forward-branch we expect
+ * to resolve, and for which our current OPC is the target.
+ * Its datum is the OPC of the space that was reserved for
+ * the forward-branch whose target we have just reached.
+ * If the supplied Control-structure ID tag does not match the one
+ * on top of the Control-Stack, announce an error and we're done.
+ * Otherwise, the datum is used both as part of the calculation of
+ * the FCode-offset we are about to write, and as the location
+ * to which we will write it.
+ * The FCode-offset is calculated as the difference between our
+ * current OPC and the reserved OPC location.
+ * We will not be ignoring errors in these cases, because we would
+ * be over-writing something that might not be a place-holder
+ * for a forward-branch at an earlier location in the FCode
+ * Output buffer.
+ *
+ **************************************************************************** */
+
+static void resolve_forward( unsigned long cstag)
+{
+ unsigned long resvd_opc;
+ bool sav_noerrors = noerrors;
+ bool cs_match_result;
+ noerrors = FALSE;
+ /* Restore the "ignore-errors" flag before we act on our match result
+ * because we want it to remain in effect for emit_fc_offset()
+ */
+ cs_match_result = matchup_control_structure( cstag);
+ noerrors = sav_noerrors;
+
+ if ( cs_match_result )
+ {
+ int saved_opc;
+ int fc_offset;
+
+ resvd_opc = control_stack->cs_datum;
+ fc_offset = opc - resvd_opc;
+
+ saved_opc = opc;
+ opc = resvd_opc;
+
+
+ emit_fc_offset( fc_offset );
+ opc = saved_opc;
+ }
+ pop_cstag();
+}
+
+
+/* **************************************************************************
+ *
+ * The functions that follow are the exported routines that
+ * utilize the preceding support-routines to effect their
+ * associated FORTH words.
+ *
+ * The routines they call will take care of most of the Error
+ * Detection via stack-depth checking and Control-structure
+ * ID tag matching, so those will not be called-out in the
+ * prologues.
+ *
+ **************************************************************************** */
+
+
+/* **************************************************************************
+ *
+ * Function name: emit_if
+ * Synopsis: All the actions when IF is encountered
+ *
+ * Associated FORTH word: IF
+ *
+ * Inputs:
+ * Parameters: NONE
+ *
+ * Outputs:
+ * Returned Value: NONE
+ * Items Pushed onto Control-Stack:
+ * Top: If_FORw_IF
+ * FCode Output buffer:
+ * Token for conditional branch -- b?branch -- followed by
+ * place-holder of zero for FCode-offset
+ *
+ *
+ **************************************************************************** */
+
+void emit_if( void )
+{
+ emit_token("b?branch");
+ mark_forward_branch( IF_CSTAG );
+}
+
+/* **************************************************************************
+ *
+ * Function name: emit_then
+ * Synopsis: All the actions when THEN is encountered; also
+ * part of another forward-branch resolver's action.
+ *
+ * Associated FORTH words: THEN ELSE
+ *
+ * Inputs:
+ * Parameters: NONE
+ * Local Static Variables:
+ * control_stack Points to "Top" Control-Structure Tag Group
+ * Control-Stack Items:
+ * Top: If_FORw_IF | While_FORw_WHILE
+ *
+ * Outputs:
+ * Returned Value: NONE
+ * Control-Stack, # of Items Popped: 1
+ * FCode Output buffer:
+ * Token for forward-resolve -- b(>resolve) -- then the space
+ * reserved for the forward-branch FCode-offset is filled
+ * in so that it reaches the token after the b(>resolve) .
+ *
+ * Process Explanation:
+ * The THEN statement or the ELSE statement must be able to resolve
+ * a WHILE statement, in order to implement the extended flow-
+ * -control structures as described in sec. A.3.2.3.2 of the
+ * ANSI Forth Spec.
+ * But we must prevent the sequence IF ... BEGIN ... REPEAT from
+ * compiling as though it were: IF ... BEGIN ... AGAIN THEN
+ * We do this by having a separate CSTAG for WHILE and allowing
+ * it here but not allowing the IF_CSTAG when processing REPEAT.
+ *
+ **************************************************************************** */
+
+void emit_then( void )
+{
+ emit_token("b(>resolve)");
+ if ( control_stack != NULL )
+ {
+ if ( control_stack->cs_tag == WHILE_CSTAG )
+ {
+ control_stack->cs_tag = IF_CSTAG;
+ }
+ }
+ resolve_forward( IF_CSTAG );
+}
+
+
+/* **************************************************************************
+ *
+ * Function name: emit_else
+ * Synopsis: All the actions when ELSE is encountered
+ *
+ * Associated FORTH word: ELSE
+ *
+ * Inputs:
+ * Parameters: NONE
+ * Global Variables:
+ * control_stack_depth Current depth of Control Stack
+ * Local Static Variables:
+ * not_cs_underflow If this is FALSE after the c-s swap, it
+ * means an underflow resulted; skip
+ * the call to resolve the first marker.
+ * Control-Stack Items:
+ * Top: {If_FORw_IF}1
+ * (Datum is OPC of earlier forward-branch; must be resolved.)
+ *
+ * Outputs:
+ * Returned Value: NONE
+ * Control-Stack, # of Items Popped: 1
+ * Items Pushed onto Control-Stack:
+ * Top: {If_FORw_IF}2
+ * (Datum is current OPC, after forward-branch is placed.)
+ * FCode Output buffer:
+ * Token for unconditional branch -- bbranch-- followed by
+ * place-holder of zero for FCode-offset. Then, token
+ * for forward-resolve -- b(>resolve) -- and the space
+ * reserved earlier for the conditional forward-branch
+ * FCode-offset is filled in to reach the token after
+ * the b(>resolve) .
+ *
+ * Error Detection:
+ * If the "Control-Stack" is empty, bypass the forward branch
+ * and let the call to control_structure_swap() report
+ * the underflow error. Then use not_cs_underflow to
+ * control whether to resolve the forward-branch.
+ *
+ * Process Explanation:
+ * The final item needed within the scope of what the earlier
+ * conditional branch might skip is an unconditional branch
+ * over the "else"-clause to follow. After that, the earlier
+ * conditional branch needs to be resolved. This last step
+ * is identical to the action of THEN .
+ *
+ **************************************************************************** */
+
+void emit_else( void )
+{
+ if ( control_stack_depth > 0 )
+ {
+ emit_token("bbranch");
+ mark_forward_branch( IF_CSTAG );
+ }
+ not_cs_underflow = TRUE;
+ control_structure_swap();
+ if ( not_cs_underflow )
+ {
+ emit_then();
+ }
+}
+
+
+/* **************************************************************************
+ *
+ * Function name: emit_begin
+ * Synopsis: All the actions when BEGIN is encountered
+ *
+ * Associated FORTH word: BEGIN
+ *
+ * Inputs:
+ * Parameters: NONE
+ *
+ * Outputs:
+ * Returned Value: NONE
+ * Items Pushed onto Control-Stack:
+ * Top: Begin_BACKw_BEGIN
+ * (Datum is current OPC, target of future backward-branch)
+ * FCode Output buffer:
+ * Token for target of backward branch -- b(<mark)
+ *
+ **************************************************************************** */
+
+void emit_begin( void )
+{
+ emit_token("b(<mark)");
+ mark_backward_target( BEGIN_CSTAG );
+}
+
+
+/* **************************************************************************
+ *
+ * Function name: emit_again
+ * Synopsis: All the actions when AGAIN is encountered
+ *
+ * Associated FORTH words: AGAIN REPEAT
+ *
+ * Inputs:
+ * Parameters: NONE
+ * Control-Stack Items:
+ * Top: Begin_BACKw_BEGIN
+ * (Datum is OPC of backward-branch target at BEGIN)
+ *
+ * Outputs:
+ * Returned Value: NONE
+ * Control-Stack, # of Items Popped: 1
+ * FCode Output buffer:
+ * Token for unconditional branch -- bbranch -- followed by
+ * FCode-offset that reaches just after the b(<mark)
+ * token at the corresponding BEGIN statement.
+ *
+ * Process Explanation:
+ * The FCode-offset is calculated as the difference between our
+ * current OPC and the target-OPC saved on the Control-Stack.
+ *
+ **************************************************************************** */
+
+void emit_again( void )
+{
+ emit_token("bbranch");
+ resolve_backward( BEGIN_CSTAG );
+}
+
+/* **************************************************************************
+ *
+ * Function name: emit_until
+ * Synopsis: All the actions when UNTIL is encountered
+ *
+ * Associated FORTH word: UNTIL
+ *
+ * Process Explanation:
+ * Same as AGAIN except token is conditional branch -- b?branch --
+ * instead of unconditional.
+ *
+ **************************************************************************** */
+
+void emit_until( void )
+{
+ emit_token("b?branch");
+ resolve_backward( BEGIN_CSTAG );
+}
+
+/* **************************************************************************
+ *
+ * Function name: emit_while
+ * Synopsis: All the actions when WHILE is encountered
+ *
+ * Associated FORTH word: WHILE
+ *
+ * Inputs:
+ * Parameters: NONE
+ * Global Variables:
+ * control_stack_depth Number of items on "Control-Stack"
+ * Control-Stack Items:
+ * Top: Begin_BACKw_BEGIN
+ * (Datum is OPC of backward-branch target)
+ *
+ * Outputs:
+ * Returned Value: NONE
+ * Control-Stack: 1 item added below top item.
+ * Items on Control-Stack:
+ * Top: Begin_BACKw_BEGIN
+ * Next: While_FORw_WHILE
+ * FCode Output buffer:
+ * Token for conditional branch -- b?branch -- followed by
+ * place-holder of zero for FCode-offset
+ *
+ * Error Detection:
+ * If the "Control-Stack" is empty, bypass creating the branch
+ * and let the call to control_structure_swap() report
+ * the underflow error.
+ *
+ * Process Explanation:
+ * Output a conditional forward-branch sequence, similar to IF
+ * (except with a WHILE CSTAG), but be sure to leave the
+ * control-structure branch-marker that was created by the
+ * preceding BEGIN on top of the one just generated:
+ * the BEGIN needs to be resolved first in any case, and
+ * doing this here is the key to implementing the extended
+ * control-flow structures as described in sec. A.3.2.3.2
+ * of the ANSI Forth Spec.
+ *
+ * Extraneous Remarks:
+ * It was for the use of this function that Wil Baden coined the
+ * name BUT for the control-structure swap routine. The idea
+ * was that the implementation of WHILE could be boiled down
+ * to: IF BUT (couldn't quite fit an AND in there...;-} )
+ * Naturally, this implementation is a smidgeon more complicated...
+ *
+ **************************************************************************** */
+
+void emit_while( void )
+{
+ if ( control_stack_depth > 0 )
+ {
+ emit_token("b?branch");
+ mark_forward_branch( WHILE_CSTAG );
+ }
+ control_structure_swap();
+}
+
+/* **************************************************************************
+ *
+ * Function name: emit_repeat
+ * Synopsis: All the actions when REPEAT is encountered
+ *
+ * Associated FORTH word: REPEAT
+ *
+ * Inputs:
+ * Parameters: NONE
+ * Local Static Variables:
+ * not_cs_underflow If FALSE after first call to resolve marker,
+ * an underflow resulted; skip second call.
+ * Control-Stack Items:
+ * Top: Begin_BACKw_BEGIN
+ * (Datum is OPC of backward-branch target at BEGIN)
+ * Next: If_FORw_IF
+ * (Datum is OPC of FCode-offset place-holder)
+ *
+ * Outputs:
+ * Returned Value: NONE
+ * Local Static Variables:
+ * not_consuming_two Cleared, then restored
+ * Control-Stack, # of Items Popped: 2
+ * FCode Output buffer:
+ * Token for unconditional branch -- bbranch -- followed by
+ * FCode-offset that reaches just after the b(<mark)
+ * token at the corresponding BEGIN statement. Then
+ * the token for forward-resolve -- b(>resolve) -- and
+ * the space reserved for the conditional forward-branch
+ * FCode-offset is filled in so that it reaches the token
+ * after the b(>resolve) .
+ *
+ * Process Explanation:
+ * The action is identical to that taken for AGAIN followed
+ * by the action for THEN.
+ * The Local Static Variable not_consuming_two gets cleared
+ * and restored by this routine.
+ *
+ **************************************************************************** */
+
+void emit_repeat( void )
+{
+ if ( matchup_two_control_structures( BEGIN_CSTAG, WHILE_CSTAG ) )
+ {
+ not_cs_underflow = TRUE;
+ not_consuming_two = FALSE;
+ emit_again();
+ if ( not_cs_underflow )
+ {
+ emit_token("b(>resolve)");
+ resolve_forward( WHILE_CSTAG );
+ }
+ not_consuming_two = TRUE;
+ }
+}
+
+/* **************************************************************************
+ *
+ * Function name: mark_do
+ * Synopsis: Common routine for marking the branches for
+ * the "do" variants
+ *
+ * Associated FORTH words: DO ?DO
+ *
+ * Inputs:
+ * Parameters: NONE
+ *
+ * Outputs:
+ * Returned Value: NONE
+ * Global Variables:
+ * do_loop_depth Incremented
+ * Items Pushed onto Control-Stack:
+ * Top: Do_FORw_DO
+ * Next: Do_BACKw_DO
+ * FCode Output buffer:
+ * Place-holder of zero for FCode-offset
+ *
+ * Error Detection:
+ * The do_loop_depth counter will be used by other routines
+ * to detect misplaced "LEAVE", "UNLOOP", "I" and suchlike.
+ * (Imbalanced "LOOP" statements are detected by the CSTag
+ * matching mechanism.)
+ *
+ * Process Explanation:
+ * Just before this function is called, the forward-branching token
+ * for the "DO" variant that begins the control-structure was
+ * written to the FCode Output buffer.
+ * It needs an FCode-offset for a forward-branch to just after
+ * its corresponding "LOOP" variant and the FCode-offset
+ * associated therewith.
+ * That "LOOP" variant's associated FCode-offset is targeted
+ * to the token that follows the one for this "DO" variant
+ * and its FCode-offset.
+ * Mark the forward-branch with the C-S Tag for DO and write a
+ * place-holder FCode-offset of zero to FCode Output.
+ * Indicate that the mark that will be processed second (but which
+ * was made first) is a duplicate of the one that will be
+ * processed first.
+ * Then mark the backward-branch target, also with the DO C-S Tag.
+ * Finally, increment the do_loop_depth counter.
+ *
+ * Extraneous Remarks:
+ * This is more complicated to describe than to code... ;-)
+ *
+ **************************************************************************** */
+
+void mark_do( void )
+{
+ mark_forward_branch( DO_CSTAG);
+ control_stack->cs_not_dup = FALSE;
+ mark_backward_target( DO_CSTAG);
+ do_loop_depth++;
+}
+
+
+/* **************************************************************************
+ *
+ * Function name: resolve_loop
+ * Synopsis: Common routine for resolving the branches for
+ * the "loop" variants.
+ *
+ * Associated FORTH words: LOOP +LOOP
+ *
+ * Inputs:
+ * Parameters: NONE
+ * Global Variables:
+ * statbuf Word read from input stream (either "loop"
+ * or "+loop"), used for Error Message.
+ * Local Static Variables:
+ * not_cs_underflow If FALSE after first call to resolve marker,
+ * an underflow resulted; skip second call.
+ * Control-Stack Items:
+ * Top: Do_FORw_DO
+ * Next: Do_BACKw_DO
+ *
+ * Outputs:
+ * Returned Value: NONE
+ * Global Variables:
+ * do_loop_depth Decremented
+ * Local Static Variables:
+ * not_consuming_two Cleared, then restored
+ * didnt_print_otl Set, then set again at end.
+ * Control-Stack, # of Items Popped: 2
+ * FCode Output buffer:
+ * FCode-offset that reaches just after the token of the
+ * corresponding "DO" variant. Then the space reserved
+ * for the FCode-offset of the forward-branch associated
+ * with the "DO" variant is filled in so that it reaches
+ * the token just after the "DO" variant's FCode-offset.
+ *
+ * Error Detection:
+ * A value of zero in do_loop_depth before it's decremented
+ * indicates a DO ... LOOP imbalance, which is an ERROR,
+ * but our other error-reporting mechanisms will catch it,
+ * so we don't check or report it here.
+ *
+ * Process Explanation:
+ * Just before this function is called, the backward-branching
+ * token for the "LOOP" variant that ends the control-structure
+ * was written to the FCode Output buffer.
+ * It needs an FCode-offset for a backward-branch targeted just
+ * after its corresponding "DO" variant and the FCode-offset
+ * associated therewith.
+ * That "DO" variant's associated FCode-offset is targeted to
+ * the token that follows the one for this "LOOP" variant
+ * and its FCode-offset.
+ * Make sure there are two DO C-S Tag entries on the Control Stack.
+ * Resolve the backward-branch, matching your target to the first
+ * C-S Tag for DO
+ * Then resolve the forward-branch, targeting to your new OPC
+ * position, and also making sure you match the DO C-S Tag.
+ * We keep track of do_loop_depth for other error-detection
+ * by decrementing it; make sure it doesn't go below zero.
+ * Don't bother resolving the forward-branch if we underflowed
+ * the "Control Stack" trying to resolve the backward-branch.
+ * If the two top C-S Tag entries are not for a DO statement, the
+ * matchup_two_control_structures() routine will consume both
+ * or up to two of them, and we will place a dummy offset of
+ * zero to follow-up the backward-branching token that has
+ * already been written.
+ *
+ * Extraneous Remarks:
+ * This is only a little more complicated to describe
+ * than to code... ;-)
+ *
+ **************************************************************************** */
+
+void resolve_loop( void )
+{
+ if ( INVERSE( matchup_two_control_structures( DO_CSTAG, DO_CSTAG) ) )
+ {
+ emit_offset( 0 );
+ }else{
+ not_cs_underflow = TRUE;
+ didnt_print_otl = TRUE;
+ not_consuming_two = FALSE;
+ resolve_backward( DO_CSTAG);
+ if ( not_cs_underflow )
+ {
+ resolve_forward( DO_CSTAG);
+ }
+ if ( do_loop_depth > 0 ) do_loop_depth--;
+ not_consuming_two = TRUE;
+ didnt_print_otl = TRUE; /* Might have gotten cleared */
+ }
+}
+
+/* **************************************************************************
+ *
+ * Function name: emit_case
+ * Synopsis: All the actions when CASE is encountered
+ *
+ * Associated FORTH word: CASE
+ *
+ * Inputs:
+ * Parameters: NONE
+ *
+ * Outputs:
+ * Returned Value: NONE
+ * Items Pushed onto Control-Stack:
+ * Top: N_OFs=0...CASE_CSTAG
+ * (Datum is 0 , Initial count of OF .. ENDOF pairs)
+ * FCode Output buffer:
+ * Token for start of a CASE structure -- b(case)
+ * Does not require an FCode-offset.
+ *
+ **************************************************************************** */
+
+void emit_case( void )
+{
+ push_cstag( CASE_CSTAG, 0);
+ emit_token("b(case)");
+}
+
+
+/* **************************************************************************
+ *
+ * Function name: emit_of
+ * Synopsis: All the actions when OF is encountered
+ *
+ * Associated FORTH word: OF
+ *
+ * Inputs:
+ * Parameters: NONE
+ * Control-Stack Items:
+ * Top: N_OFs...CASE_CSTAG
+ * (Datum is OF-count, number of OF .. ENDOF pairs)
+ * {Next and beyond}: {Endof_FORw_ENDOF}1..n_ofs
+ * { Repeat for OF-count number of times }
+ *
+ * Outputs:
+ * Returned Value: NONE
+ * Control-Stack, 1 Item Pushed, 1 modified:
+ * Top: Of_FORw_OF
+ * Next: N_OFs+1...CASE_CSTAG
+ * (Datum has been incremented)
+ * {3rd and beyond}: {Endof_FORw_ENDOF}1..n_ofs
+ * { Repeat for 1 through the un-incremented OF-count }
+ * (Same as Next etcetera at input-time.)
+ * FCode Output buffer:
+ * Token for OF statement -- b(of) -- followed by
+ * place-holder FCode-offset of zero
+ *
+ * Error Detection:
+ * Matchup CASE-cstag before incrementing OF-count
+ *
+ * Process Explanation:
+ * Main difference between this implementation and that outlined
+ * in "the book" (see below) is that we do not directly use
+ * the routine for the IF statement's flow-control; we will
+ * use a different CSTAG for better mismatch detection.
+ *
+ * Extraneous Remarks:
+ * This is a "by the book" (ANSI Forth spec, section A.3.2.3.2)
+ * implementation (mostly). Incrementing the OF-count here,
+ * after we've matched up the CSTAG, gives us (and the user)
+ * just a little bit more protection...
+ *
+ **************************************************************************** */
+
+void emit_of( void )
+{
+
+ if ( matchup_control_structure( CASE_CSTAG ) )
+ {
+ emit_token("b(of)");
+
+ /*
+ * See comment-block about "Control-Stack" Diagram Notation
+ * early on in this file.
+ *
+ */
+
+ /* ( {Endof_FORw_ENDOF}1..n_ofs N_OFs...CASE_CSTAG -- ) */
+
+ /* Increment the OF-count . */
+ (control_stack->cs_datum)++;
+
+ /* ( {Endof_FORw_ENDOF}1..n_ofs N_OFs+1...CASE_CSTAG -- ) */
+
+ mark_forward_branch( OF_CSTAG );
+ /* ( -- {Endof_FORw_ENDOF}1..n_ofs N_OFs+1...CASE_CSTAG Of_FORw_OF )
+ */
+ }
+ /* Leave the CSTAG-Group on the "Control-Stack" . */
+}
+
+
+/* **************************************************************************
+ *
+ * Function name: emit_endof
+ * Synopsis: All the actions when ENDOF is encountered
+ *
+ * Associated FORTH word: ENDOF
+ *
+ * Inputs:
+ * Parameters: NONE
+ * Control-Stack Items:
+ * Top: Of_FORw_OF
+ * Next: N_OFs+1...CASE_CSTAG
+ * (Datum has been incremented)
+ * {3rd and beyond}: {Endof_FORw_ENDOF}1..n_ofs
+ * { Repeat for 1 through the un-incremented OF-count )
+ *
+ * Outputs:
+ * Returned Value: NONE
+ * Control-Stack, 1 Item Popped, 1 new Item Pushed.
+ * Top: N_OFs...CASE_CSTAG
+ * (The count itself is unchanged from input-time, but
+ * the number of {Endof_FORw_ENDOF} CSTAG-Groups
+ * has caught up with this number, so it is
+ * no longer notated as " + 1 ").
+ * {Next and beyond}: {Endof_FORw_ENDOF}1..n_ofs
+ * { Repeat for 1 through the updated OF-count )
+ * FCode Output buffer:
+ * Token for ENDOF statement -- b(endof) -- followed by
+ * place-holder FCode-offset of zero. Then the space reserved
+ * for the FCode-offset of the forward-branch associated
+ * with the "OF" statement is filled in so that it reaches
+ * the token just after the "ENDOF" statement's FCode-offset.
+ *
+ * Error Detection:
+ * If control-stack depth is not at least 2, CS underflow ERROR
+ * and no further action.
+ * Routine that resolves the forward-branch checks for matchup error.
+ *
+ **************************************************************************** */
+
+void emit_endof( void )
+{
+ if ( control_stack_size_test( 2) )
+ {
+ emit_token("b(endof)");
+
+ /* See "Control-Stack" Diagram Notation comment-block */
+
+ /* Stack-diagrams might need to be split across lines. */
+
+ /* ( {Endof_FORw_ENDOF}1..n_ofs N_OFs+1...CASE_CSTAG ...
+ * ... Of_FORw_OF -- )
+ */
+ mark_forward_branch(ENDOF_CSTAG);
+ /* ( -- {Endof_FORw_ENDOF}1..n_ofs N_OFs+1...CASE_CSTAG ...
+ * ... Of_FORw_OF {Endof_FORw_ENDOF}n_ofs+1 )
+ */
+
+ control_structure_swap();
+ /* ( -- {Endof_FORw_ENDOF}1..n_ofs N_OFs+1...CASE_CSTAG ...
+ * ... {Endof_FORw_ENDOF}n_ofs+1 Of_FORw_OF )
+ */
+
+ resolve_forward( OF_CSTAG );
+ /* ( -- {Endof_FORw_ENDOF}1..n_ofs N_OFs+1...CASE_CSTAG ...
+ * ... {Endof_FORw_ENDOF}n_ofs+1 )
+ */
+
+ control_structure_swap();
+ /* ( -- {Endof_FORw_ENDOF}1..n_ofs ...
+ * ... {Endof_FORw_ENDOF}n_ofs+1 ...
+ * ... N_OFs+1...CASE_CSTAG )
+ */
+
+ /* The number of ENDOF-tagged Forward-Marker pairs has now
+ * caught up with the incremented OF-count; therefore,
+ * we can notate the above as:
+ *
+ * ( {Endof_FORw_ENDOF}1..n_ofs N_OFs CASE_CSTAG )
+ *
+ * and we are ready for another OF ... ENDOF pair,
+ * or for the ENDCASE statement.
+ */
+ }
+
+}
+
+/* **************************************************************************
+ *
+ * Function name: emit_endcase
+ * Synopsis: All the actions when ENDCASE is encountered
+ *
+ * Associated FORTH word: ENDCASE
+ *
+ * Inputs:
+ * Parameters: NONE
+ * Control-Stack Items:
+ * Top: N_OFs...CASE_CSTAG
+ * (Datum is OF-count, number of OF .. ENDOF pairs)
+ * {Next and beyond}: {Endof_FORw_ENDOF}1..n_ofs
+ * { Repeat for OF-count number of times }
+ *
+ * Outputs:
+ * Returned Value: NONE
+ * Control-Stack, # of Items Popped: OF-count + 1
+ * FCode Output buffer:
+ * Token for ENDCASE statement -- b(endcase)
+ * Then the spaces reserved for the FCode-offsets of all the
+ * forward-branches associated with the OF-count number
+ * of ENDOF statements are filled in so that they reach
+ * the token just after this "ENDCASE" statement.
+ *
+ * Error Detection:
+ * Routine that resolves the forward-branch checks for matchup error
+ * for each forward-branch filled in, plus the matchup routine
+ * checks before the OF-count is retrieved.
+ *
+ * Process Explanation:
+ * Retrieve the OF-count and resolve that number of ENDOF statements
+ *
+ * Extraneous Remarks:
+ * The setup makes coding this routine appear fairly simple... ;-}
+ *
+ **************************************************************************** */
+
+void emit_endcase( void )
+{
+ unsigned long n_endofs ;
+ if ( matchup_control_structure( CASE_CSTAG) )
+ {
+ int indx;
+
+ emit_token("b(endcase)");
+ n_endofs = control_stack->cs_datum;
+ for ( indx = 0 ; indx < n_endofs ; indx++ )
+ {
+ /* Because matchup_control_structure doesn't pop the
+ * control-stack, we have the N_OFs...CASE_CSTAG
+ * item on top of the Endof_FORw_ENDOF item we
+ * want to resolve. We need to keep it there so
+ * the POP is valid for the other path as well
+ * as at the end of this one.
+ * So we SWAP to get at the Endof_FORw_ENDOF item.
+ */
+ control_structure_swap();
+ resolve_forward( ENDOF_CSTAG);
+ }
+ }
+ pop_cstag();
+}
+
+
+/* **************************************************************************
+ *
+ * Function name: control_struct_incomplete
+ * Synopsis: Print a Message of given severity with origin info for
+ * a control-structure that has not been completed.
+ *
+ * Inputs:
+ * Parameters:
+ * c_s_entry Control-structure about which to display
+ * severity Severity of the messages to display.
+ * call_cond String identifying Calling Condition;
+ * used in the message.
+ *
+ * Outputs:
+ * Returned Value: NONE
+ *
+ * Printout:
+ * Message of given severity...
+ *
+ * Process Explanation:
+ * The calling routine will be responsible for all filtering of
+ * duplicate structures and the like. This routine will
+ * simply display a message.
+ *
+ **************************************************************************** */
+
+static void control_struct_incomplete(
+ int severity,
+ char *call_cond,
+ cstag_group_t *c_s_entry)
+{
+ tokenization_error ( severity,
+ "%s before completion of %s" ,
+ call_cond, strupr(c_s_entry->cs_word));
+ where_started( c_s_entry->cs_inp_fil, c_s_entry->cs_line_num );
+}
+
+/* **************************************************************************
+ *
+ * Function name: announce_control_structs
+ * Synopsis: Print a series of Messages (of severity as specified)
+ * announcing that the calling event is occurring
+ * in the context of Control-Flow structure(s),
+ * back to the given limit. Leave the control
+ * structures in effect.
+ *
+ * Inputs:
+ * Parameters:
+ * severity Severity of the messages to display.
+ * call_cond String identifying Calling Condition;
+ * used in the message.
+ * abs_token_limit Limit, in terms of abs_token_no
+ * Local Static Variables:
+ * control_stack Pointer to "Top" of "Control-Stack"
+ *
+ * Outputs:
+ * Returned Value: NONE
+ * Printout:
+ * A Message for each unresolved Control-Flow structure.
+ *
+ **************************************************************************** */
+
+void announce_control_structs( int severity, char *call_cond,
+ unsigned int abs_token_limit)
+{
+ cstag_group_t *cs_temp = control_stack;
+ while ( cs_temp != NULL )
+ {
+ if ( cs_temp->cs_abs_token_num < abs_token_limit )
+ {
+ break;
+ }
+ if ( cs_temp->cs_not_dup )
+ {
+ control_struct_incomplete( severity, call_cond, cs_temp );
+ }
+ cs_temp = cs_temp->prev;
+ }
+}
+
+/* **************************************************************************
+ *
+ * Function name: clear_control_structs_to_limit
+ * Synopsis: Clear items from the "Control-Stack" back to the given
+ * limit. Print error-messages with origin info for
+ * control-structures that have not been completed.
+ *
+ * Inputs:
+ * Parameters:
+ * call_cond String identifying Calling Condition;
+ * used in the Error message.
+ * abs_token_limit Limit, in terms of abs_token_no
+ * Global Variables:
+ * control_stack_depth Number of items on "Control-Stack"
+ * control_stack Pointer to "Top" of "Control-Stack"
+ * Control-Stack Items:
+ * The cs_inp_fil and cs_line_num tags of any item cleared
+ * from the "Control-Stack" are used in error-messages.
+ *
+ * Outputs:
+ * Returned Value:
+ * Global Variables:
+ * do_loop_depth Decremented when "DO" item cleared.
+ * control_stack_depth Decremented by called routine.
+ * Control-Stack, # of Items Popped: As many as go back to given limit
+ * Memory Freed
+ * By called routine.
+ *
+ * Error Detection:
+ * Any item on the "Control-Stack" represents a Control-Structure
+ * that was not completed when the Calling Condition was
+ * encountered. Error; identify the origin of the structure.
+ * No special actions if noerrors is set.
+ *
+ * Process Explanation:
+ * The given limit corresponds to the value of abs_token_no at
+ * the time the colon-definition (or whatever...) was created.
+ * Any kind of Control-Structure imbalance at the end of the
+ * colon-definition is an error and the entries must be cleared,
+ * but the colon-definition may have been created inside nested
+ * interpretation-time Control-Structures, and those must be
+ * preserved.
+ *
+ * Of course, if this routine is called with a given limit of zero,
+ * that would mean all the entries are to be cleared. That will
+ * be the way clear_control_structs() is implemented.
+ * We control the loop by the cs_abs_token_num field, but also
+ * make sure we haven't underflowed control_stack_depth
+ * We skip messages and other processing for items that are duplicates
+ * of others, based on the cs_not_dup field.
+ * If the cs_tag field is DO_CSTAG we decrement do_loop_depth
+ * The pop_cstag() routine takes care of the rest.
+ *
+ * Extraneous Remarks:
+ * This is a retrofit; necessary because we now permit definitions
+ * to occur inside interpretation-time Control-Structures. Calls
+ * to clear_control_structs() are already scattered around...
+ *
+ **************************************************************************** */
+
+void clear_control_structs_to_limit( char *call_cond,
+ unsigned int abs_token_limit)
+{
+ while ( control_stack_depth > 0 )
+ {
+ if ( control_stack->cs_abs_token_num < abs_token_limit )
+ {
+ break;
+ }
+ if ( control_stack->cs_not_dup )
+ {
+ control_struct_incomplete( TKERROR, call_cond, control_stack );
+ if ( control_stack->cs_tag == DO_CSTAG) do_loop_depth--;
+ }
+ pop_cstag();
+ }
+}
+
+/* **************************************************************************
+ *
+ * Function name: clear_control_structs
+ * Synopsis: Make sure the "Control-Stack" is cleared, and print
+ * error-messages (giving origin information) for
+ * control-structures that have not been completed.
+ *
+ * Inputs:
+ * Parameters:
+ * call_cond String identifying Calling Condition;
+ * used in the Error message.
+ * Global Variables:
+ * control_stack_depth Number of items on "Control-Stack"
+ * control_stack Pointer to "Top" of "Control-Stack"
+ * Control-Stack Items:
+ * The cs_inp_fil and cs_line_num tags of any item found on
+ * the "Control-Stack" are used in error-messages.
+ *
+ * Outputs:
+ * Returned Value: NONE
+ * Global Variables:
+ * control_stack_depth Reset to zero.
+ * do_loop_depth Reset to zero.
+ * Control-Stack, # of Items Popped: All of them
+ *
+ * Error Detection:
+ * Any item on the "Control-Stack" represents a Control-Structure
+ * that was not completed when the Calling Condition was
+ * encountered. Error; identify the origin of the structure.
+ * No special actions if noerrors is set.
+ *
+ * Process Explanation:
+ * Filter the duplicate messages caused by structures (e.g., DO)
+ * that place two entries on the "Control-Stack" by testing
+ * the cs_not_dup field of the "Top" "Control-Stack" item,
+ * which would indicate double-entry...
+ *
+ * Extraneous Remarks:
+ * This is called before a definition of any kind, and after a
+ * colon-definition. Flow-control constructs should *never*
+ * be allowed to cross over between immediate-execution mode
+ * and compilation mode. Likewise, not between device-nodes.
+ * Also, at the end of tokenization, there should not be any
+ * unresolved flow-control constructs.
+ *
+ **************************************************************************** */
+
+void clear_control_structs( char *call_cond)
+{
+ clear_control_structs_to_limit( call_cond, 0);
+}
Added: fcode-utils/toke/flowcontrol.h
===================================================================
--- fcode-utils/toke/flowcontrol.h (rev 0)
+++ fcode-utils/toke/flowcontrol.h 2006-08-18 12:47:12 UTC (rev 76)
@@ -0,0 +1,74 @@
+#ifndef _TOKE_FLOWCONTROL_H
+#define _TOKE_FLOWCONTROL_H
+
+/*
+ * OpenBIOS - free your system!
+ * ( FCode tokenizer )
+ *
+ * This program is part of a free implementation of the IEEE 1275-1994
+ * Standard for Boot (Initialization Configuration) Firmware.
+ *
+ * Copyright (C) 2001-2005 Stefan Reinauer, <stepan(a)openbios.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA, 02110-1301 USA
+ *
+ */
+
+/* **************************************************************************
+ *
+ * External Variables and Function Prototypes for Support Functions
+ * used in tokenizing FORTH Flow-Control structures.
+ *
+ * (C) Copyright 2005 IBM Corporation. All Rights Reserved.
+ * Module Author: David L. Paktor dlpaktor(a)us.ibm.com
+ *
+ **************************************************************************** */
+
+
+/* ************************************************************************** *
+ *
+ * Global Variables Exported
+ *
+ **************************************************************************** */
+
+extern int control_stack_depth;
+
+/* ************************************************************************** *
+ *
+ * Function Prototypes / Functions Exported:
+ *
+ **************************************************************************** */
+
+void emit_if( void );
+void emit_then( void );
+void emit_else( void );
+void emit_begin( void );
+void emit_again( void );
+void emit_until( void );
+void emit_while( void );
+void emit_repeat( void );
+void mark_do( void );
+void resolve_loop( void );
+void emit_case( void );
+void emit_of( void );
+void emit_endof( void );
+void emit_endcase( void );
+
+void announce_control_structs( int severity, char *call_cond,
+ unsigned int abs_token_limit);
+void clear_control_structs_to_limit( char *call_cond,
+ unsigned int abs_token_limit);
+void clear_control_structs( char *call_cond);
+
+#endif /* _TOKE_FLOWCONTROL_H */
Modified: fcode-utils/toke/macros.c
===================================================================
--- fcode-utils/toke/macros.c 2006-08-18 09:45:11 UTC (rev 75)
+++ fcode-utils/toke/macros.c 2006-08-18 12:47:12 UTC (rev 76)
@@ -24,6 +24,31 @@
*
*/
+/* **************************************************************************
+ * Modifications made in 2005 by IBM Corporation
+ * (C) Copyright 2005 IBM Corporation. All Rights Reserved.
+ * Modifications Author: David L. Paktor dlpaktor(a)us.ibm.com
+ **************************************************************************** */
+
+/* **************************************************************************
+ *
+ * Support functions for the MACROS vocabulary, implemented
+ * as a TIC-Headerlist type of data structure, and linked in
+ * to the Global Vocabulary.
+ *
+ **************************************************************************** */
+
+/* **************************************************************************
+ *
+ * Functions Exported:
+ * init_macros Initialize the link-pointers in the
+ * initial "Built-In" portion of
+ * the macros vocabulary
+ * add_user_macro Add an entry to the macros vocabulary
+ * skip_user_macro Consume a Macro definition if Ignoring
+ *
+ **************************************************************************** */
+
#include <stdio.h>
#include <stdlib.h>
#if defined(__linux__) && ! defined(__USE_BSD)
@@ -32,107 +57,489 @@
#include <string.h>
#include <errno.h>
-#include "toke.h"
+#include "errhandler.h"
+#include "ticvocab.h"
+#include "stream.h"
+#include "scanner.h"
+#include "dictionary.h"
+#include "devnode.h"
+#include "macros.h"
-typedef struct macro {
- u8 *name;
- u8 *alias;
- struct macro *next;
-} macro_t;
+/* **************************************************************************
+ *
+ * Internal Static Variables
+ * macros_tbl Initial array of "Built-In" Macros
+ * number_of_builtin_macros Number of "Built-In" Macro entries.
+ *
+ **************************************************************************** */
-static macro_t *macros=NULL;
+/* **************************************************************************
+ *
+ * Revision History:
+ * Thu, 27 Oct 2005 by David L. Paktor
+ * Identify the macros that resolve to a single word.
+ * Remove them from here and enter them as synonymous entries
+ * in the Tokens, Specials or Shared-words vocabularies.
+ * Wed, 30 Nov 2005 by David L. Paktor
+ * Allow user-definition of macros.
+ * Fri, 06 Jan 2006 by David L. Paktor
+ * Re-define the Macros as a TIC-Headerlist, and make them
+ * part of the Global Vocabulary
+ *
+ **************************************************************************** */
-char *lookup_macro(char *name)
+
+
+/* **************************************************************************
+ *
+ * Function name: macro_recursion_error
+ * Synopsis: Function that will go temporarily into the FUNCT
+ * field of a Macro's TIC-entry, to protect against
+ * recursive macro invocations.
+ *
+ * Inputs:
+ * Parameters:
+ * pfield Param field of the TIC-entry; unused.
+ * Global Variables:
+ * statbuf The name being invoked erroneously.
+ *
+ * Outputs:
+ * Returned Value: NONE
+ * Printout:
+ * Error Message.
+ *
+ * Error Detection:
+ * If this function is called, it is an ERROR
+ *
+ * Extraneous Remarks:
+ * This Tokenizer does not have the early-binding characterisitics
+ * of FORTH; its Macros are strings, evaluated when invoked
+ * rather than when they are defined. A reference to a name
+ * that matches the macro would cause recursion, possibly
+ * infinite. We will not allow that.
+ *
+ **************************************************************************** */
+
+static void macro_recursion_error( tic_param_t pfield)
{
- macro_t *curr;
-
- for (curr=macros; curr!=NULL; curr=curr->next)
- if (!strcasecmp(name,(char *)curr->name))
- break;
+ tokenization_error( TKERROR,
+ "Recursive invocation of macro named %s\n", statbuf);
+}
- return curr?(char *)curr->alias:NULL;
+
+/* **************************************************************************
+ *
+ * Function name: eval_mac_string
+ * Synopsis: Function that goes into FUNCT field of a TIC-entry
+ * in the Macros list. Protect against recursion.
+ *
+ * Inputs:
+ * Parameters:
+ * pfield Param field of the TIC-entry
+ * Global Variables:
+ * tic_found The TIC-entry that has just been found;
+ * it's the entry for this Macro.
+ *
+ * Outputs:
+ * Returned Value: NONE
+ * Global Variables:
+ * report_multiline Cleared to FALSE
+ * Global Behavior:
+ * The Macro will be evaluated as string input.
+ *
+ * Error Detection:
+ * An attempt at recursion will be detected because the FUNCT field
+ * of the Macro entry will have been temporarily be replaced by
+ * macro_recursion_error()
+ *
+ * Process Explanation:
+ * Save the address of the routine that is in the FUNCT field
+ * of the entry for this Macro. (Hey! It's this routine...)
+ * Replace the FUNCT field of the Macro entry with the Macro
+ * Recursion Error Detection routine
+ * Pass the address of the "resumption" routine and its argument
+ * (the entry for this Macro), to push_source()
+ * Recast the type of the parameter field to a string
+ * Make it the new Input Source Buffer.
+ * Suspend multi-line warning; see comment in body of add_user_macro()
+ * The multi-line warning flag is kept by push_source()
+ *
+ * Still to be done:
+ * If an error is encountered during Macro evaluation, display
+ * supplemental information giving the name of the Macro
+ * being run, and the file and line number in which it was
+ * defined.
+ * This will require changes to the way user Macros are added
+ * and retained, and to the way error messages are displayed.
+ *
+ * Revision History:
+ * Updated Thu, 23 Feb 2006 by David L. Paktor
+ * Do not process Macros (or, for that matter, User-defined
+ * Symbols or FLOADed files) with a routine that calls
+ * its own instance of tokenize(), because the Macro
+ * (etc.) might contain a phrase (such as the start of
+ * a conditional) that must be terminated within the
+ * body of a file, thus causing an undeserved Error.
+ * Instead, they need to be handled in a more sophis-
+ * ticated way, tied in with the operation of get_word()
+ * perhaps, that will make a smooth transition between
+ * the body of the Macro and the resumption of processing
+ * the source file. The end-of-file will only be seen
+ * at the end of an actual input file or when getting
+ * a delimited string.
+ * Updated Fri, 24 Feb 2006 by David L. Paktor
+ * Re-integrate Recursion Error Detection with the above.
+ *
+ **************************************************************************** */
+
+/* **************************************************************************
+ *
+ * In order to integrate Recursion Error Detection with the smooth
+ * transition to resumption of processing the source file, we
+ * need to create a "resumption" routine that will restore the
+ * normal behavior of the macro after it's completed, by re-
+ * instating the address of the normal Macro-invocation routine;
+ * that routine, of course, is the one that passes the address
+ * of the "resumption" routine to push_source(). In order to
+ * get around this chicken-and-egg dilemma, we will create a
+ * local static variable into which the address of the normal
+ * Macro-invocation routine will be stored. We actually only
+ * need it once, but we'd rather avoid the overhead of checking,
+ * every time, whether it has already been set; since it's always
+ * the same, there's no harm in storing it every time.
+ *
+ **************************************************************************** */
+
+typedef void (*vfunct)(); /* Pointer to function returning void */
+static vfunct sav_mac_funct ;
+
+
+/* **************************************************************************
+ *
+ * This "resumption" routine will be called by pop_source()
+ * The parameter is the Macro dictionary-entry whose behavior
+ * is to be restored.
+ *
+ **************************************************************************** */
+
+static void mac_string_recovery( tic_hdr_t *macro_entry)
+{
+ (*macro_entry).funct = sav_mac_funct;
+ (*macro_entry).ign_func = sav_mac_funct;
}
-int add_macro(char *name, char *alias)
+/* **************************************************************************
+ *
+ * The normal Macro-invocation routine, at last...
+ *
+ **************************************************************************** */
+static void eval_mac_string( tic_param_t pfield)
{
- macro_t *curr;
+ int mac_str_len = strlen(pfield.chr_ptr);
+ /* We can't use (*tic_found).pfld_size for the string length
+ * because, if this is an alias for a macro, it will be zero...
+ */
+ /* We can change that by de-coupling the decision to free the
+ * param-field from whether pfld_size is non-zero (by intro-
+ * ducing yet another field into the tic_param_t struct),
+ * but we're not doing that today...
+ */
- curr=malloc(sizeof(macro_t));
- if(!curr) {
- printf("Out of memory while adding macro.\n");
- exit(-ENOMEM);
- }
+ sav_mac_funct = *tic_found->funct;
+ (*tic_found).funct = macro_recursion_error;
+ (*tic_found).ign_func = macro_recursion_error;
+ push_source( mac_string_recovery, tic_found, FALSE);
+ report_multiline = FALSE; /* Must be done AFTER call to push_source()
+ * because report_multiline is part of
+ * the state that push_source() saves.
+ */
+ init_inbuf( pfield.chr_ptr, mac_str_len);
+}
- curr->next=macros;
- curr->name=(u8 *)name;
- curr->alias=(u8 *)alias;
+/* **************************************************************************
+ *
+ * Builtin Macros do not need Recursion Error Detection.
+ * Intermediate routine to convert parameter type.
+ *
+ **************************************************************************** */
+static void eval_builtin_mac( tic_param_t pfield)
+{
+ eval_string( pfield.chr_ptr);
+}
+/* **************************************************************************
+ *
+ * Make a macro, because we might eliminate this layer later on.
+ *
+ **************************************************************************** */
+#define EVAL_MAC_FUNC eval_mac_string
+#define BUILTIN_MAC_FUNC eval_builtin_mac
- macros=curr;
- return 0;
+/* **************************************************************************
+ *
+ * Initialization macro definition
+ *
+ **************************************************************************** */
+
+#define BUILTIN_MACRO(nam, alias) BUILTIN_MAC_TIC(nam, BUILTIN_MAC_FUNC, alias )
+
+static tic_mac_hdr_t macros_tbl[] = {
+ BUILTIN_MACRO( "(.)", "dup abs <# u#s swap sign u#>") ,
+
+
+ BUILTIN_MACRO( "?", "@ .") ,
+ BUILTIN_MACRO( "1+", "1 +") ,
+ BUILTIN_MACRO( "1-", "1 -") ,
+ BUILTIN_MACRO( "2+", "2 +") ,
+ BUILTIN_MACRO( "2-", "2 -") ,
+
+ BUILTIN_MACRO( "accept", "span @ -rot expect span @ swap span !") ,
+ BUILTIN_MACRO( "allot", "0 max 0 ?do 0 c, loop") ,
+ BUILTIN_MACRO( "blank", "bl fill") ,
+ BUILTIN_MACRO( "carret", "h# d") ,
+ BUILTIN_MACRO( ".d", "base @ swap h# a base ! . base !") ,
+ BUILTIN_MACRO( "decode-bytes", ">r over r@ + swap r@ - rot r>") ,
+ BUILTIN_MACRO( "3drop", "drop 2drop") ,
+ BUILTIN_MACRO( "3dup", "2 pick 2 pick 2 pick") ,
+ BUILTIN_MACRO( "erase", "0 fill") ,
+ BUILTIN_MACRO( ".h", "base @ swap h# 10 base ! . base !") ,
+ BUILTIN_MACRO( "linefeed", "h# a") ,
+
+ BUILTIN_MACRO( "s.", "(.) type space") ,
+ BUILTIN_MACRO( "space", "bl emit") ,
+ BUILTIN_MACRO( "spaces", "0 max 0 ?do space loop") ,
+ BUILTIN_MACRO( "(u.)", "<# u#s u#>") ,
+ BUILTIN_MACRO( "?leave", "if leave then"),
+};
+
+static const int number_of_builtin_macros =
+ sizeof(macros_tbl)/sizeof(tic_mac_hdr_t);
+
+/* **************************************************************************
+ *
+ * Function name: init_macros
+ * Synopsis: Initialize the link-pointers in the "Built-In"
+ * portion of the macros vocabulary, dynamically.
+ *
+ * Inputs:
+ * Parameters:
+ * tic_vocab_ptr Pointer to Global Vocab Pointer
+ * Global Variables:
+ * macros_tbl Initial "Built-In" Macros array
+ * number_of_builtin_macros Number of "Built-In" Macro entries
+ *
+ * Outputs:
+ * Returned Value: NONE
+ * Global Variables:
+ * The link-fields of the initial "Built-In" Macros array entries
+ * will be filled in.
+ * Supplied Pointers:
+ * *tic_vocab_ptr Updated to "tail" of Macros array
+ *
+ **************************************************************************** */
+
+void init_macros( tic_hdr_t **tic_vocab_ptr )
+{
+ init_tic_vocab( (tic_hdr_t *)macros_tbl,
+ number_of_builtin_macros,
+ tic_vocab_ptr );
}
-void init_macros(void)
+
+/* **************************************************************************
+ *
+ * Function name: print_if_mac_err
+ * Synopsis: Report a user-macro definition error, if so be.
+ *
+ * Inputs:
+ * Parameters:
+ * failure TRUE if error was detected
+ * func_cpy STRDUP() of function name, for error message
+ *
+ * Outputs:
+ * Returned Value: NONE
+ * Memory Freed
+ * Contents of func_cpy, error or not.
+ * Printout:
+ * Error message, if failure is TRUE.
+ *
+ **************************************************************************** */
+static void print_if_mac_err( bool failure, char *func_cpy)
{
- add_macro( "eval", "evaluate");
- add_macro( "(.)", "dup abs <# u#s swap sign u#>");
- add_macro( "<<", "lshift");
- add_macro( ">>", "rshift");
- add_macro( "?", "@ .");
- add_macro( "1+", "1 +");
- add_macro( "1-", "1 -");
- add_macro( "2+", "2 +");
- add_macro( "2-", "2 -");
- /* add_macro( "abort\"", "-2 throw"); */
- add_macro( "accept", "span @ -rot expect span @ swap span !");
- add_macro( "allot", "0 max 0 ?do 0 c, loop");
- add_macro( "blank", "bl fill");
- add_macro( "/c*", "chars");
- add_macro( "ca1+", "char+");
- add_macro( "carret", "h# d");
- add_macro( ".d", "base @ swap h# a base ! . base !");
- add_macro( "decode-bytes", ">r over r@ + swap r@ - rot r>");
- add_macro( "3drop", "drop 2drop");
- add_macro( "3dup", "2 pick 2 pick 2 pick");
- add_macro( "erase", "0 fill");
- add_macro( "false", "0");
- add_macro( ".h", "base @ swap h# 10 base ! . base !");
- add_macro( "linefeed", "h# a");
- add_macro( "/n*", "cells");
- add_macro( "na1+", "cell+");
- add_macro( "not", "invert");
- add_macro( "s.", "(.) type space");
- add_macro( "space", "bl emit");
- add_macro( "spaces", "0 max 0 ?do space loop");
- add_macro( "struct", "0");
- add_macro( "true", "-1");
- add_macro( "(u.)", "<# u#s u#>");
+ if ( failure )
+ {
+ tokenization_error( TKERROR,
+ "%s directive expects name and definition on the same line\n",
+ strupr(func_cpy));
+ }
+ free( func_cpy);
+}
- /* H.7 FCode name changes */
- add_macro( "decode-2int", "parse-2int");
- add_macro( "delete-attribute", "delete-property");
- add_macro( "get-inherited-attribute", "get-inherited-property");
- add_macro( "get-my-attribute", "get-my-property");
- add_macro( "get-package-attribute", "get-package-property");
- add_macro( "attribute", "property");
- add_macro( "flip", "wbflip");
- add_macro( "is", "to");
- add_macro( "lflips", "lwflips");
- add_macro( "map-sbus", "map-low");
- add_macro( "u*x", "um*");
- add_macro( "version", "fcode-revision");
- add_macro( "wflips", "wbflips");
- add_macro( "x+", "d+");
- add_macro( "x-", "d-");
- add_macro( "xdr+", "encode+");
- add_macro( "xdrbytes", "encode-bytes");
- add_macro( "xdrint", "encode-int");
- add_macro( "xdrphys", "encode-phys");
- add_macro( "xdrstring", "encode-string");
- add_macro( "xdrtoint", "decode-int");
- add_macro( "xdrtostring", "decode-string");
- add_macro( "xu/mod", "um/mod");
+
+/* **************************************************************************
+ *
+ * Function name: add_user_macro
+ * Synopsis: Parse input and add a user-defined Macro.
+ *
+ * Associated Tokenizer directive: [MACRO]
+ *
+ * Inputs:
+ * Parameters: NONE
+ * Global Variables:
+ * pc Input-source Scanning pointer
+ * statbuf Symbol retrieved from input stream.
+ * in_tokz_esc TRUE if in "Tokenizer-Escape" mode
+ * current_definitions Pointer to Current Vocabulary pointer,
+ * either Global or Current Device-Node
+ * tokz_esc_vocab "Tokenizer Escape" Vocab pointer
+ *
+ * Outputs:
+ * Returned Value: NONE
+ * Global Variables:
+ * *current_definitions { One of these will point }
+ * tokz_esc_vocab { to the new entry }
+ * Memory Allocated:
+ * Copy of directive, for error message
+ * Copy of Macro name
+ * Copy of Macro body
+ * Memory for the new entry will be allocated by support routine.
+ * When Freed?
+ * Copy of directive: When error might be reported.
+ * Macro name, body and entry: Upon end of tokenization, or when
+ * RESET-SYMBOLS is issued in the same mode and Scope as when
+ * the Macro was defined.
+ *
+ * Error Detection:
+ * At least two words in the input stream are expected to be on
+ * the same line as the directive. The get_word_in_line()
+ * and get_rest_of_line() routines will check for that;
+ * we will issue the Error Message for either condition.
+ * Check if the Macro name is a duplicate; warn_if_duplicate()
+ * routine will issue message.
+ *
+ * Process Explanation:
+ * We start just after the directive has been recognized.
+ * Get one word in line -- this is the macro name
+ * Get input to end of line. This is the "body" of the macro.
+ * Add the Macro to the Current vocab, using support routine.
+ * Set the definer field to MACRO_DEF and the Function to the
+ * same one that's used for the built-in macros.
+ * User-defined Macros may need to be processed while ignoring
+ * (because they might include conditional-operators, etc.)
+ * We will set the ign_func the same as the active function.
+ *
+ * To be considered:
+ * Do we want to do further filtration?
+ * Remove comments?
+ * Compress whitespace?
+ * Allow backslash at end of line to continue to next line?
+ *
+ * Extraneous Remarks:
+ * The scope of User-Macro definitions will follow the same rules
+ * as all other definition types: if Device-Definitions are
+ * in effect, the scope of the new Macro definition will be
+ * confined to the current Device-Node; if Global-Definitions
+ * are in effect when it is defined, its scope will be Global;
+ * if it was declared when we were in "Tokenizer Escape" mode,
+ * then its scope will be limited to "Tokenizer Escape" mode.
+ *
+ **************************************************************************** */
+
+/* This pointer is exported to this file only */
+extern tic_hdr_t *tokz_esc_vocab ;
+
+void add_user_macro( void)
+{
+ char *macroname;
+ char *macrobody;
+ bool failure = TRUE;
+
+ /* Copy of function name, for error message */
+ char *func_cpy = strdup( statbuf);
+
+ if ( get_word_in_line( NULL ) )
+ {
+ /* This is the Macro name */
+ macroname = strdup( statbuf);
+
+ if ( INVERSE(get_rest_of_line() ) )
+ {
+ /* No body on line */
+ free( macroname);
- /* non standard but often used macros */
- add_macro( "name", "device-name");
- add_macro( "endif", "then");
+ }else{
+ /* We have valid Macro body on line */
+ int mac_body_len = 0;
+
+ tic_hdr_t **target_vocab = current_definitions;
+ if ( in_tokz_esc ) target_vocab = &tokz_esc_vocab ;
+
+ warn_if_duplicate( macroname);
+ trace_creation( MACRO_DEF, macroname);
+
+ /* Tack on a new-line, so that a remark will appear
+ * to be properly terminated. This might trigger
+ * an undeserved multi-line warning if the Macro
+ * is an improperly terminated quote; we will work
+ * around that problem by temporarily suspending
+ * multi-line warnings during macro processing.
+ */
+ strcat( statbuf, "\n");
+ macrobody = strdup( statbuf);
+ mac_body_len = strlen(macrobody);
+
+ add_tic_entry( macroname, EVAL_MAC_FUNC,
+ (TIC_P_DEFLT_TYPE)macrobody,
+ MACRO_DEF, mac_body_len,
+ EVAL_MAC_FUNC, target_vocab );
+ failure = FALSE;
+ }
+ }
+
+ print_if_mac_err( failure, func_cpy);
}
+
+/* **************************************************************************
+ *
+ * Function name: skip_user_macro
+ * Synopsis: Consume the text of a user-defined Macro from the
+ * Input Stream, with no processing. (Called when
+ * a user-Macro definer occurs in a segment that
+ * is being Ignored.)
+ *
+ * Inputs:
+ * Parameters:
+ * pfield "Parameter field" pointer, to satisfy
+ * the calling convention, but not used
+ * Global Variables:
+ * statbuf Word currently being processed.
+ *
+ * Outputs:
+ * Returned Value: NONE
+ *
+ * Error Detection:
+ * At least two words in the input stream are expected to be on
+ * the same line as the user-Macro definer, same as when the
+ * directives occurs in a segment that is not being Ignored.
+ * The get_word_in_line() and get_rest_of_line() routines
+ * will check for condition., we will issue the Error Message.
+ *
+ * Process Explanation:
+ * We need to protect against the case of a macro-definition that
+ * invokes a directive that alters Conditional processing...
+ *
+ **************************************************************************** */
+void skip_user_macro( tic_bool_param_t pfield )
+{
+ bool failure = TRUE;
+ char *func_cpy = strdup( statbuf);
+ if ( get_word_in_line( NULL ) )
+ {
+ if ( get_rest_of_line() )
+ {
+ failure = FALSE;
+ }
+ }
+
+ print_if_mac_err( failure, func_cpy);
+
+}
Added: fcode-utils/toke/macros.h
===================================================================
--- fcode-utils/toke/macros.h (rev 0)
+++ fcode-utils/toke/macros.h 2006-08-18 12:47:12 UTC (rev 76)
@@ -0,0 +1,58 @@
+#ifndef _TOKE_MACROS_H
+#define _TOKE_MACROS_H
+
+/*
+ * OpenBIOS - free your system!
+ * ( FCode tokenizer )
+ *
+ * This program is part of a free implementation of the IEEE 1275-1994
+ * Standard for Boot (Initialization Configuration) Firmware.
+ *
+ * Copyright (C) 2001-2005 Stefan Reinauer, <stepan(a)openbios.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA, 02110-1301 USA
+ *
+ */
+
+/* **************************************************************************
+ *
+ * Prototypes for functions that operate on the MACROS vocabulary,
+ * which is implemented as a String-Substitution-type vocab.
+ *
+ * (C) Copyright 2005 IBM Corporation. All Rights Reserved.
+ * Module Author: David L. Paktor dlpaktor(a)us.ibm.com
+ *
+ **************************************************************************** */
+
+
+#include "types.h"
+#include "ticvocab.h"
+
+/* ************************************************************************** *
+ *
+ * Function Prototypes / Functions Exported:
+ *
+ **************************************************************************** */
+
+void init_macros( tic_hdr_t **tic_vocab_ptr );
+void add_user_macro( void);
+void skip_user_macro( tic_bool_param_t pfield );
+#if 0 /* What's this doing here? */
+char *lookup_macro(char *name);
+bool exists_as_macro(char *name);
+bool create_macro_alias( char *new_name, char *old_name );
+void reset_macros_vocab( void );
+#endif /* What's this doing here? */
+
+#endif /* _TOKE_MACROS_H */
Added: fcode-utils/toke/nextfcode.c
===================================================================
--- fcode-utils/toke/nextfcode.c (rev 0)
+++ fcode-utils/toke/nextfcode.c 2006-08-18 12:47:12 UTC (rev 76)
@@ -0,0 +1,708 @@
+/*
+ * OpenBIOS - free your system!
+ * ( FCode tokenizer )
+ *
+ * This program is part of a free implementation of the IEEE 1275-1994
+ * Standard for Boot (Initialization Configuration) Firmware.
+ *
+ * Copyright (C) 2001-2005 Stefan Reinauer, <stepan(a)openbios.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA, 02110-1301 USA
+ *
+ */
+
+/* **************************************************************************
+ *
+ * Functions for Managing FCode Assignment Pointer and for
+ * Detection of Overlapping-FCode Error in Tokenizer
+ *
+ * (C) Copyright 2006 IBM Corporation. All Rights Reserved.
+ * Module Author: David L. Paktor dlpaktor(a)us.ibm.com
+ *
+ **************************************************************************** */
+
+/* **************************************************************************
+ *
+ * The fact that the user is able to specify, at any time, the
+ * next FCode number to be assigned introduces the risk that
+ * a symbol might inadvertently be assigned an FCode that is
+ * still in use by another symbol, which could lead to bizarre
+ * and hard-to-trace failures at run-time.
+ *
+ * This module will support a means whereby to detect and report,
+ * as an Error, overlapping FCode assignments.
+ *
+ * The task is further complicated by the fact that, under some
+ * circumstances, "recycling" a range of FCodes can be done
+ * safely, and the programmer may do so intentionally.
+ *
+ * We will define a way for the programmer to specify that FCode
+ * assignments are being intentionally "recycled", and that
+ * overlaps with previously-assigned FCodes are not to be
+ * treated as Errors. We will not attempt to analyze whether
+ * it is, indeed, safe to do so; the programmer who does this
+ * is presumed to be sufficiently responsible.
+ *
+ **************************************************************************** */
+
+
+/* **************************************************************************
+ *
+ * Functions Exported:
+ * reset_fcode_ranges (Re-)Initialize the range of assignable
+ * FCode numbers and clear the records
+ * of prevously-assigned ranges of FCodes
+ * list_fcode_ranges Display a final report of assigned FCode
+ * ranges at end of tokenization or when
+ * the reset_fcodes() routine is called.
+ * set_next_fcode Set the start of a new Range of FCode
+ * numbers to be assigned.
+ * assigning_fcode The next FCode number is about to be assigned;
+ * test for out-of-bounds, overlap, etc.
+ * errors.
+ * bump_fcode Increment the next FCode number prior to the
+ * next assignment.
+ *
+ **************************************************************************** */
+
+/* **************************************************************************
+ *
+ * Revision History:
+ * 06 Jun 06 -- Need became apparent after verification test
+ * against existing device-drivers.
+ *
+ *
+ **************************************************************************** */
+
+
+/* **************************************************************************
+ *
+ * Still to be done:
+ * Detect and report when the Current Range stops overlapping
+ * one particular Range and starts overlapping another.
+ *
+ * Detect and report when the Current Range overlaps more than
+ * one Range at a time (e.g., if other Ranges themselves
+ * overlap, and the Current Range is stepping through them)
+ * but, again, only display one message per overlapped Range.
+ *
+ **************************************************************************** */
+
+
+
+/* **************************************************************************
+ *
+ * Global Variables Imported
+ * iname Name of current input file
+ * lineno Line Number within current input file
+ *
+ **************************************************************************** */
+
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "toke.h"
+#include "nextfcode.h"
+#include "errhandler.h"
+#include "stream.h"
+#include "scanner.h"
+
+
+/* **************************************************************************
+ *
+ * Global Variables Exported
+ * nextfcode The next FCode-number to be assigned
+ *
+ **************************************************************************** */
+
+u16 nextfcode; /* The next FCode-number to be assigned */
+
+/* **************************************************************************
+ *
+ * Internal (Static) Structure:
+ * fcode_range_t The record of a Range of assigned FCodes
+ *
+ * Fields:
+ * fcr_start FCode number at the start of a this Range
+ * fcr_end Last FCode number in this Range that has
+ * actually been assigned. 0 if none made yet.
+ * fcr_infile File name of where this Range was started
+ * fcr_linenum Line number where this Range was started
+ * fcr_not_lapped TRUE if an overlap error has not been reported
+ * against this Range. Use this to prevent
+ * issuing an Error message every time an
+ * overlapping FCode is assigned; once per
+ * Range is sufficient.
+ * fcr_next Pointer to following entry in linked-list.
+ *
+ * We will keep the list of assigned FCode Ranges as a forward-linked,
+ * rather than the more usual backward-linked, list for convenience
+ * at listing-time. Otherwise, it doesn't make much difference.
+ *
+ **************************************************************************** */
+
+typedef struct fcode_range
+ {
+ u16 fcr_start;
+ u16 fcr_end ;
+ char *fcr_infile;
+ int fcr_linenum;
+ bool fcr_not_lapped;
+ struct fcode_range *fcr_next;
+ } fcode_range_t ;
+
+
+/* **************************************************************************
+ *
+ * Internal Static Variables
+ * ranges_exist TRUE if FCode Ranges have been created;
+ * Prevents unnecessary overlap checking.
+ * changes_listed TRUE if no changes to any of the Ranges
+ * have taken place since the last time
+ * a Listing was displayed. Prevents
+ * unnecessary repetions (e.g., if a
+ * reset_fcode_ranges() was called
+ * right after an operation that causes
+ * a Listing
+ *
+ * These four apply if no FCode Ranges have been created:
+ *
+ * range_start First FCode in the current first (only) range.
+ * range_end Last FCode in current first (only) range that
+ * has actually been assigned. 0 if none yet.
+ * first_fcr_infile File name of where first (only) range started.
+ * first_fcr_linenum Line number where first (only) range started.
+ *
+ * These two apply after FCode Ranges have been created:
+ *
+ * first_fc_range Pointer to the first entry in the linked
+ * list of FCode Ranges.
+ * current_fc_range Pointer to the entry in the linked list of
+ * Ranges that contains the Current Range.
+ *
+ **************************************************************************** */
+
+static bool ranges_exist = FALSE;
+static bool changes_listed = FALSE;
+
+static u16 range_start = FCODE_START;
+static u16 range_end = 0;
+static char *first_fcr_infile = NULL;
+static int first_fcr_linenum = 0;
+
+static fcode_range_t *first_fc_range = NULL;
+static fcode_range_t *current_fc_range = NULL;
+
+/* **************************************************************************
+ *
+ * Function name: reset_fcode_ranges
+ * Synopsis: (Re-)Initialize the range of assignable FCode numbers
+ * and clear the records of prevously-assigned Ranges
+ *
+ * Inputs:
+ * Parameters: NONE
+ * Global Variables:
+ * iname Name of current input file
+ * lineno Line Number within current input file
+ * Local Static Variables:
+ * ranges_exist TRUE if FCode Ranges have been created
+ * first_fc_range Pointer to First FCode Range
+ * current_fc_range Pointer to the current Range
+ *
+ * Outputs:
+ * Returned Value: NONE
+ * Global Variables:
+ * nextfcode Initialized to Standard start value
+ * for user-assigned FCodes
+ * Local Static Variables:
+ * ranges_exist Cleared to FALSE
+ * changes_listed Reset to FALSE
+ * range_start Reset to Standard start value
+ * range_end Reset to 0
+ * first_fcr_infile Copy of iname
+ * first_fcr_linenum Copy of lineno
+ * first_fc_range Reset to NULL
+ * current_fc_range Reset to NULL
+ * Memory Allocated
+ * For first_fcr_infile , which will have a copy of iname
+ * When Freed?
+ * The next time this routine is called.
+ * Memory Freed
+ * Any FCode Ranges that were in effect will be freed, and the
+ * memory for their fcr_infile fields will be freed.
+ * If iname has changed, memory for first_fcr_infile will
+ * be freed before the new copy is made.
+ *
+ * Process Explanation:
+ * This will be called either as part of normal initialization
+ * or in response to a User-issued directive.
+ * In the former case, it may be called twice: once before any
+ * Source is examined, and once again in response to the first
+ * (and only to the first) invocation of an FCode-Starter, at
+ * which time the input file name and line number will be updated.
+ * In the latter case, the calling routine will be responsible for
+ * displaying any Advisory Messages and listings of previously
+ * assigned FCode Ranges.
+ *
+ **************************************************************************** */
+
+void reset_fcode_ranges( void)
+{
+ if ( ranges_exist )
+ {
+ while ( current_fc_range != NULL )
+ {
+ current_fc_range = first_fc_range->fcr_next;
+ free( first_fc_range->fcr_infile);
+ free( first_fc_range);
+ first_fc_range = current_fc_range;
+ }
+ ranges_exist = FALSE;
+ }else{
+ if ( first_fcr_infile != NULL )
+ {
+ if ( strcmp( first_fcr_infile, iname) != 0 )
+ {
+ free( first_fcr_infile);
+ first_fcr_infile = NULL;
+ }
+ }
+ }
+
+ changes_listed = FALSE;
+ range_start = FCODE_START;
+ range_end = 0;
+
+ if ( first_fcr_infile == NULL )
+ {
+ first_fcr_infile = strdup( iname);
+ }
+ first_fcr_linenum = lineno;
+ nextfcode = FCODE_START;
+}
+
+/* **************************************************************************
+ *
+ * Function name: list_fcode_ranges
+ * Synopsis: Display an Advisory of assigned FCode ranges at
+ * end of tokenization or upon reset_fcodes()
+ *
+ * Inputs:
+ * Parameters:
+ * final_tally TRUE if printing a final tally at
+ * end of tokenization.
+ * Global Variables:
+ * verbose Do not print anything if not set.
+ * nextfcode FCode next after last-assigned
+ * Local Static Variables:
+ * changes_listed If TRUE, only print new-line.
+ * ranges_exist TRUE if more than one Range exists.
+ * range_start FCode at start of only range
+ * range_end Last FCode in only range; 0 if none.
+ * first_fc_range Ptr to start of FCode Ranges list
+ *
+ * Outputs:
+ * Returned Value: NONE
+ * Local Static Variables:
+ * changes_listed Set to TRUE.
+ * Printout:
+ * Printed to Standard Out on final tally, or to STDERR otherwise.
+ * One of three formats:
+ * 1 No FCodes assigned.
+ * 2 Last assigned FCode = 0xXXX
+ * 3 FCodes assigned:
+ * [ No FCodes assigned in the range that started ... ]
+ * [ From 0xXXX to 0xYYY ** in the range that started ... ]
+ * (** = Indicator if the Range has an Overlap Error.)
+ *
+ * Process Explanation:
+ * This is called to complete an Advisory or Standard-Out Message
+ * that doesn't end in a new-line.
+ *
+ * Extraneous Remarks:
+ * If we ever decide not to keep entries for Ranges in which no
+ * assignments were made, let's not remove the code that lists
+ * them. It's harmless to keep it around, and we remain ready...
+ *
+ **************************************************************************** */
+
+void list_fcode_ranges( bool final_tally)
+{
+ if ( verbose )
+ {
+ FILE *message_dest = ( final_tally ? stdout : ERRMSG_DESTINATION );
+ if ( changes_listed )
+ {
+ fprintf(message_dest, "\n");
+ }else{
+ changes_listed = TRUE;
+
+ if ( INVERSE(ranges_exist) )
+ { /* List the first and only range */
+ if ( range_end == 0 )
+ {
+ fprintf(message_dest, "No FCodes assigned.\n");
+ }else{
+ if ( range_start == FCODE_START )
+ {
+ fprintf(message_dest,
+ "Last assigned FCode = 0x%x\n", range_end);
+ }else{
+ fprintf(message_dest,
+ "FCodes assigned: 0x%x to 0x%x\n",
+ range_start, range_end);
+ }
+ }
+ /* We are done listing the first and only range */
+ }else{ /* List the collection of Ranges */
+
+ /* Pionter to function returning void */
+ typedef void (*vfunct)();
+
+ /* Function for the started_at() part of the message */
+ vfunct start_at_funct =
+ ( final_tally ? print_started_at : started_at );
+
+
+ fcode_range_t *next_range = first_fc_range;
+
+ fprintf(message_dest, "FCodes assigned:\n");
+
+ while ( next_range != NULL )
+ {
+ if ( next_range->fcr_end == 0 )
+ {
+ fprintf(message_dest, " None assigned");
+ }else{
+ fprintf(message_dest, " From 0x%x to 0x%x",
+ next_range->fcr_start, next_range->fcr_end );
+ if ( INVERSE( next_range->fcr_not_lapped) )
+ {
+ fprintf(message_dest, " ***Overlap***" );
+ }
+ }
+ fprintf(message_dest, " in the range");
+ (*start_at_funct)(
+ next_range->fcr_infile, next_range->fcr_linenum );
+
+ next_range = next_range->fcr_next;
+ }
+ }
+ }
+ }
+}
+
+
+/* **************************************************************************
+ *
+ * Function name: set_next_fcode
+ * Synopsis: Set the start of a new Range of FCode numbers
+ *
+ * Inputs:
+ * Parameters:
+ * new_fcode Start of the new range of FCodes
+ * Global Variables:
+ * nextfcode The next FCode-number to be assigned
+ * iname Name of current input file
+ * lineno Line Number within current input file
+ * Local Static Variables:
+ * ranges_exist TRUE if FCode Ranges have been created
+ * range_start First FCode in the current (first
+ * and only) range
+ * range_end Last FCode in only range; 0 if none.
+ * current_fc_range Pointer to the current Range if there
+ * are more than one.
+ *
+ * Outputs:
+ * Returned Value: NONE
+ * Global Variables:
+ * nextfcode Set to the start of the new range
+ * Local Static Variables:
+ * ranges_exist May be set to TRUE
+ * first_fc_range May be initialized
+ * current_fc_range May be initialized or moved
+ * first_fcr_infile May be updated, may be made NULL
+ * first_fcr_linenum May be updated, may be made irrelevant
+ * range_start May be set to start of the new range
+ * or rendered irrelevant
+ * range_end Reset to 0 (by reset_fcode_ranges() )
+ * changes_listed Reset to FALSE
+ * Memory Allocated
+ * For new Range data structure; for copy of iname
+ * When Freed?
+ * By reset_fcode_ranges()
+ *
+ * Error Detection:
+ * Not here.
+ * The calling routine will detect and report attempts to set an
+ * illegal new range.
+ * Overlap with earlier Ranges will be detected and reported when
+ * the FCode is actually Assigned.
+ *
+ * Process Explanation:
+ * The calling routine will not call this routine with a new starting
+ * FCode that is not legal per the Standard.
+ * It may call with a new starting FCode that is equal to nextfcode
+ * If no Ranges exist yet, and the new starting FCode is equal to
+ * the current value of nextfcode , this is a continuation of
+ * the first and only range; do not change the file name or line
+ * number; just go away.
+ * If no Ranges exist yet, and no FCode assignments have been made
+ * in the current range, then this is a new start for the first
+ * and only range; detect the latter condition by range_end == 0
+ * Call the reset_fcode_ranges() routine to update the file name
+ * and line number, then update the remaining variables for the
+ * current (first and only) range, and you are done here.
+ * If no Ranges exist yet, and if FCode assignments _have_ been made
+ * in the current (first and only) range, create a data structure
+ * for the first (and now no longer only) Range and point both
+ * the first_fc_range and current_fc_range pointers at it.
+ * Set the ranges_exist flag to TRUE.
+ * If Ranges exist, whether from being newly-created, above, or from
+ * earlier, create a data structure for the new Current Range
+ * and move the current_fc_range pointer to point at it. If
+ * the new starting FCode is equal to nextfcode we still want
+ * to create a new Range that will be listed separately.
+ * If no assignments were made within the Current Range, we will not
+ * overwrite or delete it; it will be listed at the appropriate
+ * time, and will be harmless in the overlap test.
+ *
+ * Extraneous Remarks:
+ * We will trade off the strict rules of structured code here,
+ * in exchange for ease of coding.
+ *
+ **************************************************************************** */
+
+void set_next_fcode( u16 new_fcode)
+{
+ if ( INVERSE( ranges_exist) )
+ { /* The current range is the first and only. */
+
+ if ( new_fcode == nextfcode )
+ {
+ /* Do nothing here */
+ return;
+ }
+
+ if ( range_end == 0 )
+ { /* No FCode assignments have been made in the current range */
+ /* This is still the first and only range. */
+
+ reset_fcode_ranges(); /* Update file name and line number */
+ range_start = new_fcode;
+ nextfcode = new_fcode;
+
+ /* We are done here */
+ return;
+
+ }else{ /* Create the data structure for the first Range */
+ first_fc_range = safe_malloc( sizeof( fcode_range_t),
+ "creating first FCode Range" );
+ first_fc_range->fcr_start = range_start;
+ first_fc_range->fcr_end = range_end;
+ first_fc_range->fcr_infile = first_fcr_infile;
+ first_fc_range->fcr_linenum = first_fcr_linenum;
+ first_fc_range->fcr_not_lapped = TRUE;
+ first_fc_range->fcr_next = NULL;
+
+ first_fcr_infile = NULL;
+ first_fcr_linenum = 0;
+ range_start = FCODE_START;
+ range_end = 0;
+
+ current_fc_range = first_fc_range;
+
+ ranges_exist = TRUE;
+ }
+ }
+
+ /* Previous Ranges exist now for sure! */
+ current_fc_range->fcr_next = safe_malloc( sizeof( fcode_range_t),
+ "creating new FCode Range" );
+ current_fc_range = current_fc_range->fcr_next;
+
+ nextfcode = new_fcode;
+ current_fc_range->fcr_start = nextfcode;
+ current_fc_range->fcr_end = 0;
+ /* Will be filled in by first assignment */
+ current_fc_range->fcr_infile = strdup( iname);
+ current_fc_range->fcr_linenum = lineno;
+ current_fc_range->fcr_not_lapped = TRUE;
+ current_fc_range->fcr_next = NULL;
+
+ changes_listed = FALSE;
+}
+
+
+/* **************************************************************************
+ *
+ * Function name: find_overlap
+ * Synopsis: Compare the FCode under test against existing
+ * FCode Ranges and return a pointer to the
+ * Range against which it overlaps, if any.
+ *
+ * Inputs:
+ * Parameters:
+ * test_fcode FCode to be tested
+ * Global Variables:
+ *
+ * Local Static Variables:
+ * ranges_exist If not TRUE, no need to test
+ * first_fc_range Start of Ranges to test
+ * current_fc_range Do not test Current Range
+ *
+ * Outputs:
+ * Returned Value: Pointer to FCode Range in which an
+ * overlap exists, or NULL if none.
+ *
+ * Error Detection:
+ * The calling routine will treat any findings as it deems appropriate.
+ *
+ * Process Explanation:
+ * A Range within which no assignments were made will never "hit"
+ * the overlap test because its fcr_end field will be zero
+ * and its fcr_start field will be non-zero; there's no
+ * number that will be "between" them!
+ *
+ **************************************************************************** */
+
+static fcode_range_t *find_overlap( u16 test_fcode)
+{
+ fcode_range_t *retval = NULL;
+ if ( ranges_exist )
+ {
+ fcode_range_t *test_range = first_fc_range;
+ while ( test_range != current_fc_range )
+ {
+ if ( ( test_fcode <= test_range->fcr_end ) &&
+ ( test_fcode >= test_range->fcr_start ) )
+ {
+ retval = test_range;
+ break;
+ }
+ test_range = test_range->fcr_next;
+ }
+ }
+
+ return( retval);
+}
+
+
+/* **************************************************************************
+ *
+ * Function name: assigning_fcode
+ * Synopsis: Commit the next FCode number to be assigned;
+ * test for out-of-bounds, overlap, etc. errors.
+ *
+ * Inputs:
+ * Parameters:
+ *
+ * Global Variables:
+ * nextfcode
+ * Local Static Variables:
+ * ranges_exist TRUE if FCode Ranges have been created
+ * first_fc_range First entry in linked list of Ranges.
+ * current_fc_range List entry for Current Range.
+ *
+ * Outputs:
+ * Returned Value: NONE
+ * Global Variables:
+ * Local Static Variables:
+ * changes_listed Reset to FALSE
+ * One of these two will be set to nextfcode
+ * range_end ... if ranges_exist is FALSE
+ * current_fc_range->fcr_end ... if ranges_exist is TRUE
+ *
+ * Error Detection:
+ * FATAL if the value of nextfcode is larger than the legal
+ * maximum for an FCode
+ * ERROR if the value of nextfcode falls within one of the
+ * existing Ranges (other than the current one, of course)
+ *
+ **************************************************************************** */
+
+void assigning_fcode( void)
+{
+ if ( nextfcode > FCODE_LIMIT )
+ {
+ /* Let's give a last summarization before we crap out */
+ tokenization_error( INFO, "");
+ list_fcode_ranges( FALSE);
+
+ tokenization_error( FATAL,
+ "Too many definitions. "
+ "Assigned FCode exceeds limit "
+ "specified by IEEE-1275.");
+ /*
+ * No need to return() from here.
+ * FATAL error exits program.
+ */
+ }
+
+ changes_listed = FALSE;
+
+ if ( INVERSE(ranges_exist) )
+ { /* No Overlap Error checking needed here. */
+ range_end = nextfcode;
+ }else{
+ current_fc_range->fcr_end = nextfcode;
+
+ /* Detect and report Overlap Error only once per Range */
+ if ( current_fc_range->fcr_not_lapped )
+ {
+ fcode_range_t *found_lap = find_overlap( nextfcode);
+ if ( found_lap != NULL )
+ {
+ tokenization_error( TKERROR,
+ "Assigning FCode of 0x%x, "
+ "which overlaps the range", nextfcode);
+ started_at( found_lap->fcr_infile, found_lap->fcr_linenum);
+
+ current_fc_range->fcr_not_lapped = FALSE;
+ }
+ }
+ }
+
+}
+
+
+/* **************************************************************************
+ *
+ * Function name: bump_fcode
+ * Synopsis: Increment the next assignable FCode number
+ * prior to the next assignment.
+ *
+ * Inputs:
+ * Parameters: NONE
+ * Global Variables:
+ * nextfcode The next FCode-number to be assigned
+ *
+ * Outputs:
+ * Returned Value: NONE
+ * Global Variables:
+ * nextfcode Incremented
+ *
+ * Extraneous Remarks:
+ * This looks like a no-brainer now, but if we ever need this
+ * function to perform any more sophisticated background
+ * activity, we can limit the scope of our modifications
+ * to this routine.
+ *
+ **************************************************************************** */
+
+void bump_fcode( void)
+{
+ nextfcode++;
+}
Added: fcode-utils/toke/nextfcode.h
===================================================================
--- fcode-utils/toke/nextfcode.h (rev 0)
+++ fcode-utils/toke/nextfcode.h 2006-08-18 12:47:12 UTC (rev 76)
@@ -0,0 +1,80 @@
+#ifndef _TOKE_NEXTFCODE_H
+#define _TOKE_NEXTFCODE_H
+
+/*
+ * OpenBIOS - free your system!
+ * ( FCode tokenizer )
+ *
+ * This program is part of a free implementation of the IEEE 1275-1994
+ * Standard for Boot (Initialization Configuration) Firmware.
+ *
+ * Copyright (C) 2001-2005 Stefan Reinauer, <stepan(a)openbios.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA, 02110-1301 USA
+ *
+ */
+
+/* **************************************************************************
+ *
+ * Function Prototypes for Managing FCode Assignment Pointer
+ * and for Detection of Overlapping-FCode Error in Tokenizer
+ *
+ * (C) Copyright 2006 IBM Corporation. All Rights Reserved.
+ * Module Author: David L. Paktor dlpaktor(a)us.ibm.com
+ *
+ **************************************************************************** */
+
+#include "types.h"
+
+
+/* ************************************************************************** *
+ *
+ * Global Variables Exported
+ *
+ **************************************************************************** */
+
+extern u16 nextfcode; /* The next FCode-number to be assigned */
+
+
+/* ************************************************************************** *
+ *
+ * Function Prototypes / Functions Exported:
+ *
+ **************************************************************************** */
+
+void reset_fcode_ranges( void);
+void list_fcode_ranges( bool final_tally);
+void set_next_fcode( u16 new_fcode);
+void assigning_fcode( void);
+void bump_fcode( void);
+
+/* **************************************************************************
+ *
+ * Macros:
+ *
+ * FCODE_START Standard-specified starting number for
+ * user-generated FCodes.
+ *
+ * FCODE_LIMIT Standard-specified maximum number for
+ * FCodes of any origin.
+ *
+ * I know these are not likely to change, but I still feel better
+ * making them named symbols, just on General Principles...
+ *
+ **************************************************************************** */
+
+#define FCODE_START 0x0800
+#define FCODE_LIMIT 0x0fff
+
+#endif /* _TOKE_NEXTFCODE_H */
Added: fcode-utils/toke/parselocals.c
===================================================================
--- fcode-utils/toke/parselocals.c (rev 0)
+++ fcode-utils/toke/parselocals.c 2006-08-18 12:47:12 UTC (rev 76)
@@ -0,0 +1,944 @@
+/*
+ * OpenBIOS - free your system!
+ * ( FCode tokenizer )
+ *
+ * This program is part of a free implementation of the IEEE 1275-1994
+ * Standard for Boot (Initialization Configuration) Firmware.
+ *
+ * Copyright (C) 2001-2005 Stefan Reinauer, <stepan(a)openbios.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA, 02110-1301 USA
+ *
+ */
+
+/* **************************************************************************
+ *
+ * Parsing functions for IBM-style Local Values
+ *
+ * (C) Copyright 2005 IBM Corporation. All Rights Reserved.
+ * Module Author: David L. Paktor dlpaktor(a)us.ibm.com
+ *
+ **************************************************************************** */
+
+/* **************************************************************************
+ *
+ * Functions Exported:
+ * declare_locals Pick up the Locals' names after the {
+ * handle_local Insert the code to access a Local
+ * exists_as_local Confirm whether a name is in the Locals vocab
+ * assign_local Process the "Assign to a Local" operator ( -> )
+ * finish_locals Insert the code for exiting a routine
+ * that uses locals
+ * forget_locals Remove the locals' names from the search
+ *
+ **************************************************************************** */
+
+/* **************************************************************************
+ *
+ * These are the names of the three routines that will be invoked
+ * when Locals are used. Their definitions exist in a separate
+ * Local Values Support FCode source-file that must be FLOADed
+ * into the user's tokenization source.
+ *
+ **************************************************************************** */
+
+/* Note that the enclosing curly-braces are part of the name */
+static const char* push_locals = "{push-locals}"; /* ( #ilocals #ulocals -- ) */
+static const char* pop_locals = "{pop-locals}"; /* ( #locals -- ) */
+static const char* local_addr = "_{local}"; /* ( local# -- addr ) */
+
+/* Switchable Fetch or Store operator to apply to local_addr. */
+static const char* local_op = "@"; /* Initially Fetch */
+
+
+/* **************************************************************************
+ *
+ * Revision History:
+ * Updated Wed, 13 Jul 2005 by David L. Paktor
+ * Command-line control for:
+ * Support for Locals in general
+ * Whether to accept the "legacy" separator (semicolon)
+ * Whether to issue a message for the "legacy" separator
+ * Updated Tue, 10 Jan 2006 by David L. Paktor
+ * Convert to tic_hdr_t type vocabulary.
+ *
+ **************************************************************************** */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "ticvocab.h"
+#include "dictionary.h"
+#include "scanner.h"
+#include "parselocals.h"
+#include "errhandler.h"
+#include "clflags.h"
+#include "stream.h"
+#include "devnode.h"
+#include "flowcontrol.h"
+
+/* **************************************************************************
+ *
+ * Global Variables Imported
+ * statbuf
+ * pc
+ * opc
+ * incolon
+ * lastcolon
+ * ibm_locals_legacy_separator Accept ; as the "legacy" separator
+ * ibm_legacy_separator_message Issue a message for "legacy" sep'r
+ *
+ **************************************************************************** */
+
+/* **************************************************************************
+ *
+ * Internal Static Variables
+ * local_names Vocabulary for new local-names
+ * num_ilocals Number of initialized local variables
+ * num_ulocals Number of uninitialized local variables
+ * localno Running Local-Number to be assigned
+ * eval_buf Internally-generated string to be parsed
+ * l_d_lineno Locals Declaration Line Number
+ *
+ **************************************************************************** */
+
+static tic_hdr_t *local_names = NULL;
+static int num_ilocals = 0;
+static int num_ulocals = 0;
+static int localno = 0;
+static char eval_buf[64];
+static unsigned int l_d_lineno; /* For Error Messages */
+
+/* **************************************************************************
+ *
+ * The local_names vocabulary follows the same tic_hdr_t structure
+ * as the dictionaries of tokens, special-functions, etcetera. Its
+ * "parameter field" is an integer, used to store the Local's number,
+ * an its "function" is invoke_local(), defined further below.
+ *
+ * The vocabulary is initially empty, so there's no need for an "init"
+ * or a "reset" routine.
+ *
+ **************************************************************************** */
+
+/* **************************************************************************
+ *
+ * Function name: int_to_str
+ * Synopsis: Convert an integer into a compilable string.
+ * Suport routine for invoke_local().
+ *
+ * Inputs:
+ * Parameters:
+ * num The number to convert
+ * bufr The buffer into which to place it.
+ * Needn't be very long:
+ * five at least, ten is enough
+ *
+ * Outputs:
+ * Returned Value: Pointer to bufr
+ * bufr Contents are changed.
+ *
+ * Process Explanation:
+ * Convert into decimal. If the number is greater than 8,
+ * prepend a d# in front of it. If less, don't.
+ * We specifically want to avoid a d# in front of
+ * the numbers 0 1 2 and 3, which are also named constants;
+ * there's no need to treat 'em as literals.
+ * The calling routine will be responsible for allocating
+ * and freeing the buffer.
+ *
+ * Extraneous Remarks:
+ * Too bad atoi() isn't a Standard C function; I could convert
+ * using the current base, and be guaranteed that it would be
+ * interpreted in the same base.
+ * Instead, I have to fiddle-faddle around with d# ...
+ *
+ **************************************************************************** */
+
+static char *int_to_str( int num, char *bufr)
+{
+ char* prefix = "d# ";
+ if ( num < 8 ) prefix = "";
+ sprintf(bufr,"%s%d",prefix, num);
+ return (bufr);
+}
+
+
+
+/* **************************************************************************
+ *
+ * Function name: invoke_local
+ * Synopsis: Compile-in the code to access the Local whose
+ * assigned Number is given. This function is
+ * entered into the Local-Names Vocabulary entry.
+ *
+ * Inputs:
+ * Parameters:
+ * pfield The Vocabulary entry's Param field, taken
+ * from the Assigned Number of the Local.
+ * Local Static Variables:
+ * local_addr Name of _{local} routine, invoked
+ * when a Local is used
+ * local_op Fetch or Store operator to apply.
+ *
+ * Outputs:
+ * Returned Value: None
+ * Local Static Variables:
+ * eval_buf Phrase constructed here; will become new
+ * Source Input Buffer, temporarily
+ *
+ * Error Detection:
+ * If the Local Values Support FCode source-file was not
+ * FLOADed into the user's tokenization source, then
+ * the function _{local} will be an "unknown name".
+ *
+ * Process Explanation:
+ * We are going to generate a string of the form:
+ * " #local _{local} OP"
+ * and pass it to the Parser for evaluation.
+ * The call to _{local} is preceded by its parameter, which is
+ * its Assigned Local-Number, and followed by the appropriate
+ * OPerator, which will be "Fetch" if the Local's name was
+ * invoked by itself, or "Store" if its invocation was made
+ * in conjuction with the -> operator.
+ * The string-buffer may be local, but it must be stable.
+ *
+ * Revision History:
+ * Updated Thu, 24 Mar 2005 by David L. Paktor
+ * Factored-out to permit lookup_local() to be a "pure"
+ * function that can be used for duplicate-name detection.
+ * Updated Tue, 10 Jan 2006 by David L. Paktor
+ * Accommodate conversion to tic_hdr_t type vocabulary.
+ *
+ **************************************************************************** */
+
+static void invoke_local( tic_param_t pfield )
+{
+ char local_num_buf[10];
+ int loc_num = (int)pfield.deflt_elem;
+
+ int_to_str(loc_num, local_num_buf);
+ sprintf( eval_buf, "%s %s %s", local_num_buf, local_addr, local_op );
+ eval_string( eval_buf);
+
+}
+
+
+/* **************************************************************************
+ *
+ * Function name: locals_separator
+ * Synopsis: Test whether the given character is the separator
+ * between initted and uninitted Local Names.
+ * Optionally, allow Semi-Colon as a separator and issue
+ * an optional Advisory.
+ *
+ * Inputs:
+ * Parameters:
+ * subj One-character "subject" of the test
+ * Global Variables:
+ * ibm_locals_legacy_separator Allow Semi-Colon as a separator?
+ * ibm_legacy_separator_message Issue an Advisory message?
+ *
+ * Outputs:
+ * Returned Value: TRUE if the character is the separator
+ *
+ * Error Detection:
+ * If the separator is Semi-Colon, and ibm_locals_legacy_separator
+ * is TRUE, then if ibm_legacy_separator_message is TRUE,
+ * issue an Advisory message.
+ * If the flag to allow Semi-Colon is FALSE, then simply do not
+ * acknowledge a valid separator. Other routines will report
+ * an erroneous attempt to use an already-defined symbol.
+ *
+ * Revision History:
+ * Updated Wed, 13 Jul 2005 by David L. Paktor
+ * Bring the questions of whether to accept semicolon as a separator
+ * -- and whether to issue a message for it -- under the control
+ * of external flags (eventually set by command-line switches),
+ * rather than being hard-compiled.
+ *
+ * Extraneous Remarks:
+ * In the interest of avoiding too deeply nested "IF"s, I will
+ * not be adhering strictly to the rules of structure.
+ *
+ **************************************************************************** */
+
+static bool locals_separator( char subj )
+{
+ bool retval = FALSE;
+ /* Is it the preferred (i.e., non-legacy) separator? */
+ if ( subj == '|' )
+ {
+ retval = TRUE;
+ return ( retval );
+ }
+
+ if ( ibm_locals_legacy_separator )
+ {
+ if ( subj == ';' )
+ {
+ retval = TRUE;
+ if ( ibm_legacy_separator_message )
+ {
+ tokenization_error ( WARNING , "Semicolon as separator in "
+ "Locals declaration is deprecated in favor of '|'\n");
+ }
+ }
+ }
+ return ( retval );
+}
+
+/* **************************************************************************
+ *
+ * Function name: add_local
+ * Synopsis: Given a pointer to a name and a number, enter
+ * them into the vocabulary for new Local names.
+ *
+ * Inputs:
+ * Parameters:
+ * lnum The assigned number
+ * lname Pointer to the name
+ * Local Static Variables:
+ * local_names The vocabulary for new Local names
+ *
+ * Outputs:
+ * Returned Value: NONE
+ * Local Static Variables:
+ * local_names Enter the new Local's name and number.
+ * Memory Allocated:
+ * A place into which the name will be copied
+ * When Freed?
+ * When forget_locals() routine frees up all memory
+ * allocations in the "Local Names" Vocabulary.
+ *
+ * Process Explanation:
+ * Allocate a stable place in memory for the name, via strdup().
+ * The entry's "action" will be the invoke_local() function,
+ * defined above. The "parameter field" size is zero.
+ *
+ **************************************************************************** */
+
+static void add_local( TIC_P_DEFLT_TYPE lnum, char *lname)
+{
+ char *lnamecopy ;
+
+ lnamecopy = strdup( lname);
+ add_tic_entry( lnamecopy, invoke_local, lnum,
+ LOCAL_VAL, 0, NULL, &local_names );
+ trace_creation( LOCAL_VAL, lname);
+}
+
+
+/* **************************************************************************
+ *
+ * Function name: gather_locals
+ * Synopsis: Collect Local names, for both initted and uninitted
+ * Return an indication as to whether to continue
+ * gathering Locals' names
+ *
+ * Inputs:
+ * Parameters:
+ * initted TRUE if we are gathering initted Local names.
+ * counter Pointer to variable that's counting names.
+ * Global Variables:
+ * statbuf The symbol just retrieved from the input stream.
+ * Local Static Variables:
+ * localno Running Local-Number to be assigned
+ * l_d_lineno Line # of Locals Declar'n start (for err mssg)
+ *
+ * Outputs:
+ * Returned Value: TRUE = Ended with initted/uninitted separator
+ * Local Static Variables:
+ * localno Incremented for each Local name declared
+ * local_names Enter the new locals' names into the Vocabulary.
+ * Numeric field is assigned local number.
+ *
+ * Error Detection:
+ * A Local-name that duplicates an existing name is an ERROR.
+ * Especially if that name is <Semicolon> and the flag
+ * called ibm_locals_legacy_separator was not set.
+ * Issue an Error if close-curly-brace terminator is not found,
+ * or if imbedded comment is not terminated, before end of file.
+ * If the Separator is found a second-or-more time, issue an Error
+ * and continue collecting uninitted Local names.
+ *
+ * Revision History:
+ * Updated Thu, 24 Mar 2005 by David L. Paktor
+ * Allow comments to be interspersed among the declarations.
+ * Error-check duplicate Local-name.
+ * Updated Wed, 30 Mar 2005 by David L. Paktor
+ * Warning when name length exceeds ANSI-specified max (31 chars).
+ * Updated Thu, 07 Jul 2005 by David L. Paktor
+ * Protect against PC pointer-overrun due to unterminated
+ * comment or declaration.
+ * Error-check for numbers.
+ * No name-length check; doesn't go into FCode anyway.
+ *
+ **************************************************************************** */
+
+static bool gather_locals( bool initted, int *counter )
+{
+ signed long wlen;
+ bool retval = FALSE;
+
+ while ( TRUE )
+ {
+ wlen = get_word();
+
+ if ( wlen <= 0 )
+ {
+ warn_unterm( TKERROR, "Local-Values Declaration", l_d_lineno);
+ break;
+ }
+
+ /* Allow comments to be interspersed among the declarations. */
+ if ( filter_comments( statbuf) )
+ {
+ /* Unterminated and Multi-line checking already handled */
+ continue;
+ }
+ /* Is this the terminator or the separator? */
+ if ( wlen == 1 ) /* Maybe */
+ {
+ /* Check for separator */
+ if (locals_separator( statbuf[0] ) )
+ {
+ /* If gathering initted Local names, separator is legit */
+ if ( initted )
+ {
+ retval = TRUE;
+ break;
+ }else{
+ tokenization_error ( TKERROR,
+ "Excess separator -- %s -- found "
+ "in Local-Values declaration", statbuf);
+ in_last_colon();
+ continue;
+ }
+ }
+ /* Haven't found the separator. Check for the terminator */
+ if ( statbuf[0] == '}' )
+ {
+ break;
+ }
+ }
+ /* It was not the terminator or the separator */
+ {
+ long tmp;
+ char *where_pt1; char *where_pt2;
+ /* Error-check for duplicated names */
+ if ( word_exists ( statbuf, &where_pt1, &where_pt2 ) )
+ {
+ tokenization_error ( TKERROR, "Cannot declare %s "
+ "as a Local-Name; it's already defined %s%s",
+ statbuf, where_pt1, where_pt2 );
+ show_node_start();
+ continue;
+ }
+ /* Error-check for numbers. */
+ if ( get_number(&tmp) )
+ {
+ tokenization_error ( TKERROR, "Cannot declare %s "
+ "as a Local-Name; it's a number.\n", statbuf );
+ continue;
+ }
+
+ /* We've got a valid new local-name */
+ /* Don't need to check name length; it won't go into the FCode */
+
+ /* Increment our counting-v'ble */
+ *counter += 1;
+
+ /* Define our new local-name in the Locals' vocabulary */
+ add_local( localno, statbuf );
+
+ /* Bump the running Local-Number */
+ localno++;
+
+ }
+ }
+ return ( retval );
+}
+
+
+/* **************************************************************************
+ *
+ * Function name: activate_locals
+ * Synopsis: Compile-in the call to {push-locals} that
+ * the new definition under construction will need,
+ * now that the Locals have been declared.
+ *
+ * Inputs:
+ * Parameters: NONE
+ * Global Variables:
+ * num_ilocals First argument to {push-locals}
+ * num_ulocals Second argument to {push-locals}
+ * push_locals Name of {push-locals} routine.
+ *
+ * Outputs:
+ * Returned Value: NONE
+ * Local Static Variables:
+ * eval_buf Phrase constructed here; will become
+ * new Source Input Buffer, temporarily
+ *
+ * Error Detection:
+ * If the Local Values Support FCode source-file was not
+ * FLOADed into the user's tokenization source, then
+ * the function {push-locals} will be an "unknown name".
+ *
+ * Process Explanation:
+ * We are going to generate a string of the form:
+ * " #ilocals #ulocals {push-locals}"
+ * and pass it to the Parser for evaluation.
+ * The string-buffer may be local, but it must be stable.
+ *
+ * Question under consideration.:
+ * Do we want to check if {push-locals} is an unknown name,
+ * and give the user a hint of what's needed? And, if so,
+ * do we do it only once, or every time?
+ *
+ **************************************************************************** */
+
+static void activate_locals( void )
+{
+ char ilocals_buf[10];
+ char ulocals_buf[10];
+
+ int_to_str(num_ilocals, ilocals_buf );
+ int_to_str(num_ulocals, ulocals_buf );
+ sprintf( eval_buf,"%s %s %s",ilocals_buf, ulocals_buf, push_locals);
+ eval_string( eval_buf);
+}
+
+/* **************************************************************************
+ *
+ * Function name: error_check_locals
+ * Synopsis: Indicate whether Locals declaration is erronious
+ *
+ * Inputs:
+ * Parameters: NONE
+ * Global Variables:
+ * incolon TRUE if colon def'n is in effect.
+ * opc FCode Output buffer Position Counter
+ * lastcolon Value of opc when Colon def'n was started
+ *
+ * Outputs:
+ * Returned Value: TRUE if found errors severe enough to
+ * preclude further processing of Decl'n
+ *
+ * Errors Detected:
+ * Colon definition not in effect. ERROR and return TRUE.
+ * Locals declaration inside body of colon-definition (i.e., after
+ * something has been compiled-in to it) is potentially risky,
+ * but may be valid, and is a part of legacy practice. It
+ * will not be treated as an outright ERROR, but it will
+ * generate a WARNING...
+ * Multiple locals declarations inside a single colon-definition
+ * are completely disallowed. ERROR and return TRUE.
+ * Locals declaration inside a control-structure is prohibited.
+ * Generate an ERROR, but return FALSE to allow processing
+ * of the declaration to continue.
+ *
+ **************************************************************************** */
+
+/* The value of lastcolon when Locals Declaration is made.
+ * If it's the same, that detects multiple locals declaration attempt.
+ */
+static int last_local_colon = 0;
+
+static bool error_check_locals ( void )
+{
+ bool retval = FALSE;
+
+ if ( ! incolon )
+ {
+ tokenization_error ( TKERROR,
+ "Can only declare Locals inside of a Colon-definition.\n");
+ retval = TRUE;
+ } else {
+ if ( last_local_colon == lastcolon )
+ {
+ tokenization_error ( TKERROR, "Excess Locals Declaration");
+ in_last_colon();
+ retval = TRUE;
+ }else{
+ last_local_colon = lastcolon;
+ if ( opc > lastcolon )
+ {
+ tokenization_error ( WARNING,
+ "Declaring Locals after the body of a Colon-definition "
+ "has begun is not recommended.\n");
+ }
+ announce_control_structs( TKERROR,
+ "Local-Values Declaration encountered",
+ last_colon_abs_token_no);
+ }
+ }
+ return ( retval );
+}
+
+/* **************************************************************************
+ *
+ * Function name: declare_locals
+ * Synopsis: Process (or Ignore) the Declaration of Locals,
+ * upon encountering Curly-brace ( { )
+ *
+ * Inputs:
+ * Parameters:
+ * ignoring TRUE if "Ignoring"
+ * Global Variables:
+ * statbuf Next symbol to process.
+ * lineno Current Line Number in Input File
+ * report_multiline FALSE to suspend multiline warning
+ *
+ * Outputs:
+ * Returned Value: NONE
+ * Global Variables:
+ * statbuf Advanced to end of Locals Declaration.
+ * pc Bumped past the close-curly-brace
+ * Local Static Variables:
+ * localno Init'd, then updated by gather_locals()
+ * l_d_lineno Line Number of start of Locals Declaration
+ *
+ * Error Detection:
+ * See error_check_locals()
+ * After Error messages, will bypass further processing until the
+ * terminating close-curly-brace of a Locals Declaration.
+ * If the terminating close-curly-brace missing under those
+ * circumstances, issue an Error
+ * If terminating close-curly-brace is missing when the Locals
+ * Declaration is otherwise valid, gather_locals() will
+ * detect and report the Error.
+ * Warning if multiline declaration. Because embedded comments
+ * may also supppress the multiline warning, we need to save
+ * and restore the state of the report_multiline switch...
+ *
+ **************************************************************************** */
+
+void declare_locals ( bool ignoring)
+{
+ num_ilocals = 0;
+ num_ulocals = 0;
+ localno = 0;
+
+ l_d_lineno = lineno;
+ bool sav_rep_mul_lin = report_multiline;
+ report_multiline = TRUE;
+
+ if ( ignoring || error_check_locals() )
+ {
+ if ( skip_until ( '}' ) )
+ {
+ warn_unterm(TKERROR,
+ "misplaced Local-Values Declaration", l_d_lineno);
+ }else{
+ pc++ ; /* Get past the close-curly-brace */
+ }
+ }else{
+ if (gather_locals( TRUE, &num_ilocals ) )
+ {
+ gather_locals( FALSE, &num_ulocals );
+ }
+ }
+
+ /* If PC has reached the END, gather_locals() will
+ * have already issued an "unterminated" Error;
+ * a "multiline" warning would be redundant
+ * repetitive, unnecessary, excessive, unaesthetic
+ * and -- did I already mention? -- redundant.
+ */
+ if ( pc < end )
+ {
+ report_multiline = sav_rep_mul_lin;
+ warn_if_multiline( "Local-Values declaration", l_d_lineno);
+ }
+
+ /* Don't do anything if no Locals were declared */
+ /* This could happen if the { } field is empty */
+ if ( localno != 0 )
+ {
+ activate_locals();
+ }
+}
+
+/* **************************************************************************
+ *
+ * Function name: handle_local
+ * Synopsis: Process the given name as a Local Name;
+ * indicate if it was a valid Local Name.
+ *
+ * Inputs:
+ * Parameters:
+ * lname The "Local" name for which to look
+ * Local Static Variables:
+ * local_names The vocabulary for Local names
+ *
+ * Outputs:
+ * Returned Value: TRUE if the name is a valid "Local Name"
+ *
+ **************************************************************************** */
+
+static bool handle_local( char *lname)
+{
+ bool retval = handle_tic_vocab( lname, local_names );
+ return ( retval ) ;
+}
+
+/* **************************************************************************
+ *
+ * Function name: lookup_local
+ * Synopsis: Return a pointer to the data-structure of the named
+ * word, only if it was a valid Local Name.
+ *
+ * Inputs:
+ * Parameters:
+ * lname The "Local" name for which to look
+ * Local Static Variables:
+ * local_names The vocabulary for Local names
+ *
+ * Outputs:
+ * Returned Value: Pointer to the data-structure, or
+ * NULL if not found.
+ *
+ **************************************************************************** */
+
+tic_hdr_t *lookup_local( char *lname)
+{
+ tic_hdr_t *retval = lookup_tic_entry( lname, local_names );
+ return ( retval ) ;
+}
+
+
+/* **************************************************************************
+ *
+ * Function name: create_local_alias
+ * Synopsis: Create an alias in the "Local Names" Vocabulary
+ *
+ * Associated FORTH word: ALIAS
+ *
+ * Inputs:
+ * Parameters:
+ * old_name Name of existing entry
+ * new_name New name for which to create an entry
+ *
+ * Outputs:
+ * Returned Value: TRUE if old_name found in "Locals" vocab
+ * Global Variables:
+ * local_names Will point to the new entry
+ * Memory Allocated:
+ * Memory for the new entry, by the support routine
+ * When Freed?
+ * When forget_locals() routine frees up all memory
+ * allocations in the "Local Names" Vocabulary.
+ *
+ **************************************************************************** */
+
+bool create_local_alias(char *new_name, char *old_name)
+{
+ bool retval = create_tic_alias( new_name, old_name, &local_names );
+ return ( retval );
+}
+
+/* **************************************************************************
+ *
+ * Function name: exists_as_local
+ * Synopsis: Simply confirm whether a given name exists
+ * within the Locals vocabulary.
+ *
+ * Inputs:
+ * Parameters:
+ * stat_name Name to look up
+ *
+ * Outputs:
+ * Returned Value: TRUE if stat_name was a Local
+ *
+ **************************************************************************** */
+
+bool exists_as_local( char *stat_name )
+{
+ bool retval = exists_in_tic_vocab(stat_name, local_names );
+ return ( retval );
+}
+
+
+/* **************************************************************************
+ *
+ * Function name: assign_local
+ * Synopsis: Process the "Assign to a Local" operator ( -> )
+ *
+ * Inputs:
+ * Parameters: NONE
+ * Global Variables:
+ * statbuf Next symbol to process
+ * pc Input-source Scanning pointer
+ * lineno Input-source Line Number. Used for Err Mssg.
+ *
+ * Outputs:
+ * Returned Value: NONE
+ * Global Variables:
+ * statbuf Advanced to next symbol
+ * pc Advanced; may be unchanged if error.
+ * lineno Advanced; may be unchanged if error
+ * local_op Will be set to Store and then reset to Fetch.
+ * Global Behavior:
+ * Construct a phrase and pass it to the Tokenizer.
+ *
+ * Error Detection:
+ * If next symbol is not a Local name, print ERROR message
+ * and restore pc so that the next symbol will be
+ * processed by ordinary means.
+ * In the extremely unlikely case that -> is last symbol in
+ * the source-file, report an ERROR.
+ *
+ * Process Explanation:
+ * Save the PC.
+ * Get the next symbol; check for end-of-file.
+ * Set Local Operator ( local_op ) to "Store", to prepare to apply it.
+ * Pass the next symbol to handle_local() .
+ * If handle_local() failed to find the name, you have
+ * detected an error; restore pc .
+ * Otherwise, you have invoked the local and applied "Store" to it.
+ * At the end, reset local_op to "Fetch".
+ *
+ **************************************************************************** */
+
+void assign_local ( void )
+{
+ signed long wlen;
+ bool is_okay;
+ u8 *savd_pc = pc;
+ unsigned int savd_lineno = lineno;
+
+ wlen = get_word();
+
+ if ( wlen <= 0 )
+ {
+ warn_unterm(TKERROR, "Locals Assignment", lineno);
+ return;
+ }
+
+ local_op = "!"; /* Set to Store */
+
+ is_okay = handle_local( statbuf);
+ if( INVERSE(is_okay) )
+ {
+ tokenization_error ( TKERROR,
+ "Cannot apply -> to %s, only to a declared Local.\n", statbuf );
+ pc = savd_pc;
+ lineno = savd_lineno;
+ }
+ local_op = "@"; /* Reset to Fetch */
+}
+
+/* **************************************************************************
+ *
+ * Function name: finish_locals
+ * Synopsis: Compile-in the call to {pop-locals} that the
+ * new definition under construction will need
+ * when it's about to complete execution, i.e.,
+ * before an EXIT or a SemiColon. But only if the
+ * current definition under construction is using Locals.
+ *
+ * Inputs:
+ * Parameters: NONE
+ *
+ * Local Static Variables:
+ * localno Total # of Locals.
+ * Both a param to {pop-locals}
+ * and an indicator that Locals are in use.
+ * pop_locals Name of {pop-locals} routine.
+ *
+ * Outputs:
+ * Returned Value: NONE
+ * Local Static Variables:
+ * eval_buf Phrase constructed here; will become new
+ * Source Input Buffer, temporarily
+ *
+ * Error Detection:
+ * If the Local Values Support FCode source-file was not
+ * FLOADed into the user's tokenization source, then
+ * the function {pop-locals} will be an "unknown name".
+ *
+ * Revision History:
+ * Updated Fri, 24 Feb 2006 by David L. Paktor
+ * The eval_string() routine no longer calls its own
+ * instance of tokenize() . In order to make a
+ * smooth transition between the processing the
+ * internally-generated string and the resumption
+ * of processing the source file, it simply sets
+ * up the string to be processed next.
+ * In this case, however, we need to have the string
+ * processed right away, as the calling routine
+ * emits a token that must follow those generated
+ * by this.
+ * Fortunately, we know the exact contents of the string.
+ * Two calls to tokenize_one_word() will satisfy the
+ * requirement.
+ *
+ **************************************************************************** */
+
+void finish_locals ( void )
+{
+ /* Don't do anything if Locals are not in use */
+ if ( localno > 0 )
+ {
+ char nlocals_buf[10];
+
+ int_to_str(localno, nlocals_buf );
+ sprintf( eval_buf,"%s %s",nlocals_buf, pop_locals);
+ eval_string( eval_buf);
+ tokenize_one_word( get_word() );
+ tokenize_one_word( get_word() );
+ }
+}
+
+/* **************************************************************************
+ *
+ * Function name: forget_locals
+ * Synopsis: Remove the Locals' names from the special Vocabulary
+ * free-up their allocated memory, and reset the Locals'
+ * counters (which are also the indication that Locals
+ * are in use). This is done at the time a SemiColon
+ * is processed. But only if the current definition
+ * under construction is using Locals.
+ *
+ * Inputs:
+ * Parameters: NONE
+ * Local Static Variables:
+ * local_names The vocabulary for new Local names
+ *
+ * Outputs:
+ * Returned Value: NONE
+ * Local Static Variables:
+ * local_names Emptied and pointing at NULL.
+ * num_ilocals Reset to zero
+ * num_ulocals ditto
+ * localno ditto
+ * Memory Freed
+ * All memory allocations in the "Local Names" Vocabulary.
+ *
+ **************************************************************************** */
+
+void forget_locals ( void )
+{
+ /* Don't do anything if Locals are not in use */
+ if ( localno != 0 )
+ {
+ reset_tic_vocab( &local_names, NULL ) ;
+
+ num_ilocals = 0;
+ num_ulocals = 0;
+ localno = 0;
+ }
+}
Added: fcode-utils/toke/parselocals.h
===================================================================
--- fcode-utils/toke/parselocals.h (rev 0)
+++ fcode-utils/toke/parselocals.h 2006-08-18 12:47:12 UTC (rev 76)
@@ -0,0 +1,48 @@
+#ifndef _TOKE_LOCALX_H
+#define _TOKE_LOCALX_H
+
+/*
+ * OpenBIOS - free your system!
+ * ( FCode tokenizer )
+ *
+ * This program is part of a free implementation of the IEEE 1275-1994
+ * Standard for Boot (Initialization Configuration) Firmware.
+ *
+ * Copyright (C) 2001-2005 Stefan Reinauer, <stepan(a)openbios.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA, 02110-1301 USA
+ *
+ */
+
+/* **************************************************************************
+ *
+ * Function Prototypes / External definitions for Parsing
+ * functions for IBM-style Local Values in Tokenizer
+ *
+ * (C) Copyright 2005 IBM Corporation. All Rights Reserved.
+ * Module Author: David L. Paktor dlpaktor(a)us.ibm.com
+ *
+ **************************************************************************** */
+
+#include "ticvocab.h"
+
+void declare_locals ( bool ignoring);
+tic_hdr_t *lookup_local( char *lname);
+bool exists_as_local( char *stat_name );
+bool create_local_alias(char *new_name, char *old_name);
+void assign_local ( void );
+void finish_locals ( void );
+void forget_locals ( void );
+
+#endif /* _TOKE_LOCALX_H */
Modified: fcode-utils/toke/scanner.c
===================================================================
--- fcode-utils/toke/scanner.c 2006-08-18 09:45:11 UTC (rev 75)
+++ fcode-utils/toke/scanner.c 2006-08-18 12:47:12 UTC (rev 76)
@@ -24,6 +24,12 @@
*
*/
+/* **************************************************************************
+ * Modifications made in 2005 by IBM Corporation
+ * (C) Copyright 2005 IBM Corporation. All Rights Reserved.
+ * Modifications Author: David L. Paktor dlpaktor(a)us.ibm.com
+ **************************************************************************** */
+
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
@@ -34,74 +40,596 @@
#include <time.h>
#include <ctype.h>
-#include "toke.h"
+#include "macros.h"
#include "stack.h"
#include "stream.h"
#include "emit.h"
+#include "toke.h"
#include "dictionary.h"
+#include "vocabfuncts.h"
+#include "scanner.h"
+#include "errhandler.h"
+#include "tokzesc.h"
+#include "conditl.h"
+#include "flowcontrol.h"
+#include "usersymbols.h"
+#include "clflags.h"
+#include "devnode.h"
+#include "tracesyms.h"
+#include "nextfcode.h"
-#define ERROR do { if (!noerrors) exit(-1); } while (0)
+#include "parselocals.h"
-extern u8 *start, *pc, *end, *opc, *ostart;
-extern int verbose, noerrors;
+/* **************************************************************************
+ *
+ * Some VERY IMPORTANT global variables follow
+ *
+ **************************************************************************** */
-u8 *statbuf=NULL;
-u16 nextfcode;
-u8 base=0x0a;
+u8 *statbuf=NULL; /* The word just read from the input stream */
+u8 base=0x0a; /* The numeric-interpretation base */
-/* header pointers */
-u8 *fcode_hdr=NULL;
-u8 *pci_hdr=NULL;
-
/* pci data */
bool pci_is_last_image=TRUE;
-bool pci_want_header=FALSE;
-u16 pci_revision=0x0001;
+u16 pci_image_rev=0x0001; /* Vendor's Image, NOT PCI Data Structure Rev */
u16 pci_vpd=0x0000;
-bool offs16=TRUE;
-static bool intok=FALSE, incolon=FALSE;
-bool haveend=FALSE;
-static u8 *skipws(u8 *str)
+/* Having to do with the state of the tokenization */
+bool offs16 = TRUE; /* We are using 16-bit branch- (etc) -offsets */
+bool in_tokz_esc = FALSE; /* TRUE if in "Tokenizer Escape" mode */
+bool incolon = FALSE; /* TRUE if inside a colon definition */
+bool haveend = FALSE; /* TRUE if the "end" code was read. */
+int do_loop_depth = 0; /* How deep we are inside DO ... LOOP variants */
+
+/* Used for error-checking of IBM-style Locals */
+int lastcolon; /* Location in output stream of latest colon-definition. */
+
+/* Used for error reporting */
+char *last_colon_defname = NULL; /* Name of last colon-definition */
+char *last_colon_filename = NULL; /* File where last colon-def'n made */
+unsigned int last_colon_lineno; /* Line number of last colon-def'n */
+bool report_multiline = TRUE; /* False to suspend multiline warning */
+unsigned int last_colon_abs_token_no;
+
+/* **************************************************************************
+ * Local variables
+ **************************************************************************** */
+static u16 last_colon_fcode; /* FCode-number assigned to last colon-def'n */
+ /* Used for RECURSE */
+
+static bool do_not_overload = TRUE ; /* False to suspend dup-name-test */
+static bool got_until_eof = FALSE ; /* TRUE to signal "unterminated" */
+
+static unsigned int last_colon_do_depth = 0;
+
+/* State of headered-ness for name-creation */
+typedef enum headeredness_t {
+ FLAG_HEADERLESS ,
+ FLAG_EXTERNAL ,
+ FLAG_HEADERS } headeredness ;
+static headeredness hdr_flag = FLAG_HEADERLESS ; /* Init'l default state */
+
+/* Local variables having to do with: */
+/* ... the state of the tokenization */
+static bool is_instance = FALSE; /* Is "instance" is in effect? */
+static char *instance_filename = NULL; /* File where "instance" invoked */
+static unsigned int instance_lineno; /* Line number of "instance" */
+static bool fcode_started = FALSE ; /* Only 1 fcode_starter per block. */
+static bool first_fc_starter = TRUE; /* Only once per tokenization... */
+
+/* ... with the state of the input stream, */
+static bool need_to_pop_source;
+
+/* ... with the use of the return stack, */
+static int ret_stk_depth = 0; /* Return-Stack-Usage-Depth counter */
+
+/* ... and with control of error-messaging. */
+ /* Should a warning about a dangling "instance"
+ * be issued at the next device-node change?
+ */
+static bool dev_change_instance_warning = TRUE;
+
+ /* Has a gap developed between "instance" and its application? */
+static bool instance_definer_gap = FALSE;
+
+ /* Shared phrases */
+static char *in_tkz_esc_mode = "in Tokenizer-Escape mode.\n";
+
+
+/* **************************************************************************
+ *
+ * Function name: skip_ws
+ * Synopsis: Advance the PC past all whitespace.
+ * Protect against pointer over-runs
+ *
+ * Inputs:
+ * Parameters: NONE
+ * Global Variables:
+ * pc Input-source Scanning pointer
+ * end End of input-source buffer
+ *
+ * Outputs:
+ * Returned Value: TRUE if PC reached END before non-blank char
+ * Global Variables:
+ * pc Advanced to first non-blank char, or to END
+ * lineno Incremented if encountered new-line along the way
+ *
+ * Error Detection:
+ * Return a TRUE if End of input-source buffer reached before
+ * non-blank character. Not necessarily an error; allow
+ * calling routine to decide...
+ *
+ **************************************************************************** */
+
+static bool skip_ws(void)
{
- while (str && (*str=='\t' || *str==' ' || *str=='\n' )) {
- if (*str=='\n')
- lineno++;
- str++;
+ bool retval = TRUE;
+ char ch_tmp;
+
+ for ( ; pc < end; pc++ )
+{
+ ch_tmp = *pc;
+ if ( (ch_tmp != '\t') && (ch_tmp != ' ') && (ch_tmp != '\n' ) )
+ {
+ retval = FALSE;
+ break;
}
+ if ( ch_tmp == '\n') lineno++;
+ }
+ return ( retval );
+}
+
+/* **************************************************************************
+ *
+ * Function name: skip_until
+ * Synopsis: Advance the PC to the given character.
+ * Do not copy anything into statbuf.
+ * Protect against pointer over-runs
+ *
+ * Inputs:
+ * Parameters:
+ * lim_ch Limiting Character
+ * Global Variables:
+ * pc Input-source Scanning pointer
+ * end End of input-source buffer
+ *
+ * Outputs:
+ * Returned Value: TRUE if PC reached END before finding LIM_CH
+ * Global Variables:
+ * pc Advanced to first occurrence of LIM_CH, or to END
+ * lineno Incremented if encountered new-line along the way
+ *
+ * Error Detection:
+ * Return a TRUE if End of input-source buffer reached before
+ * desired character. Not necessarily an error; allow calling
+ * routine to decide...
+ *
+ **************************************************************************** */
+
+bool skip_until( char lim_ch)
+{
+ bool retval = TRUE;
+ char ch_tmp;
+
+ for ( ; pc < end; pc++ )
+ {
+ ch_tmp = *pc;
+ if ( ch_tmp == lim_ch )
+ {
+ retval = FALSE;
+ break;
+ }
+ if ( ch_tmp == '\n') lineno++;
+ }
+ return ( retval );
+}
+
+
+/* **************************************************************************
+ *
+ * Function name: get_until
+ * Synopsis: Return, in statbuf, the string from PC to the first
+ * occurrence of the given delimiter-character..
+ *
+ * Inputs:
+ * Parameters:
+ * needle The given delimiter-character
+ * Global Variables:
+ * pc Input-source Scanning Pointer
+ *
+ * Outputs:
+ * Returned Value: Length of the string obtained
+ * Global Variables:
+ * statbuf The string obtained from the input stream;
+ * does not include the delimiter-character.
+ * pc Bumped past the delimiter-character, unless
+ * it's a new-line, in which case leave it
+ * to be handled by get_word()
+ * Local Static Variables:
+ * got_until_eof Pass this as a signal that the end of the
+ * buffer was reached before the delimiter;
+ * Testing whether PC has reached END is
+ * not a sufficient indication.
+ *
+ * Error Detection:
+ * If string overflows statbuf allocation, ERROR, and
+ * return "no string" (i.e., length = 0).
+ * Otherwise, if delimiter not found before eof, keep string.
+ * Protection against PC pointer-over-run past END is
+ * provided by skip_until() . Reaching END will be
+ * handled by calling routine; pass indication along
+ * via Local Static Variable.
+ *
+ * Process Explanation:
+ * Skip the delimiter-character from further input, unless it's a
+ * new-line which will be skipped anyway. Let skip_until()
+ * and get_word() handle incrementing line-number counters.
+ * If skip_until() indicated reaching end-of-file, don't bump PC
+ *
+ * Revision History:
+ * Updated Thu, 14 Jul 2005 by David L. Paktor
+ * More robust testing for when PC exceeds END
+ * Involved replacing firstchar()
+ *
+ **************************************************************************** */
- return str;
+static signed long get_until(char needle)
+{
+ u8 *safe;
+ unsigned long len = 0;
+
+ safe=pc;
+
+ got_until_eof = skip_until(needle);
+
+ len = pc - safe;
+ if (len >= GET_BUF_MAX )
+ {
+ tokenization_error( TKERROR,
+ "get_until buffer overflow. Max is %d.\n", GET_BUF_MAX-1 );
+ len = GET_BUF_MAX-1;
}
-static u8 *firstchar(u8 needle, u8 *str)
+ memcpy(statbuf, safe, len);
+ statbuf[len]=0;
+
+ if ( INVERSE(got_until_eof) )
{
- while (str && *str!=needle) {
- if (*str=='\n')
- lineno++;
- str++;
+ if ( needle != '\n' ) pc++;
}
+ return len;
+}
- return str;
+
+/* **************************************************************************
+ *
+ * We are going to use a fairly sophisticated mechanism to
+ * make a smooth transition between processing the body
+ * of a Macro, a User-defined Symbol or an FLOADed file
+ * and the resumption of processing the source file, so
+ * that the end-of-file will only be seen at the end of
+ * the primary input file (the one from the command-line).
+ * This mechanism will be tied in with the get_word() routine
+ *
+ * We are going to define a private data-structure in which
+ * we will save the state of the current source file,
+ * and from which, of course, we will recover it. Its
+ * fields will be:
+ * A pointer to the next structure in the list.
+ * The saved values of START END and PC
+ * The saved values of INAME and LINENO
+ * A flag indicating that get-word should "pause"
+ * before popping the source-stream because
+ * the input file will be changing.
+ * A place from which to save and recover the state of
+ * whether we're testing for "Multi-line" strings;
+ * to prevent undeserved "Multi-line" warnings
+ * during Macro processing.
+ * A pointer to a "resumption" routine, to call
+ * when resuming processing the source file;
+ * the routine takes a pointer parameter
+ * and has no return value. The pointer
+ * may be NULL if no routine is needed.
+ * The pointer to pass as the parameter to the
+ * resumption routine.
+ *
+ **************************************************************************** */
+
+typedef struct source_state
+ {
+ struct source_state *next;
+ u8 *old_start;
+ u8 *old_pc;
+ u8 *old_end;
+ char *old_iname;
+ unsigned int old_lineno;
+ bool pause_before_pop;
+ bool sav_rep_multlin;
+ void (*resump_func)();
+ _PTR resump_param;
+ } source_state_t ;
+
+static source_state_t *saved_source = NULL;
+
+
+/* **************************************************************************
+ *
+ * Function name: push_source
+ * Synopsis: Save the state of the current source file, in the
+ * source_state data-structure LIFO linked-list.
+ *
+ * Inputs:
+ * Parameters:
+ * res_func Pointer to routine to call when resuming
+ * processing the saved source file.
+ * res_param Parameter to pass to res_func.
+ * Either or both pointers may be NULL.
+ * file_chg TRUE if input file is going to change.
+ * Global Variables:
+ * start Points to current input buffer
+ * end Points to end of current input buffer
+ * pc Input point in current buffer
+ * iname Name of current source file
+ * lineno Line number in current source file
+ * report_multiline Whether we're testing for "Multi-line"
+ * Local Static Variables:
+ * saved_source Pointer to the source_state data-structure
+ *
+ * Outputs:
+ * Returned Value: NONE
+ * Local Static Variables:
+ * saved_source Points to new source_state entry
+ * Memory Allocated
+ * for the new source_state entry
+ * When Freed?
+ * When resuming processing the source file, by drop_source().
+ *
+ * Process Explanation:
+ * The calling routine will establish the new input buffer via
+ * a call to init_inbuf() or the like.
+ *
+ **************************************************************************** */
+
+void push_source( void (*res_func)(), _PTR res_parm, bool file_chg )
+{
+ source_state_t *new_sav_src;
+
+ new_sav_src = safe_malloc( sizeof(source_state_t), "pushing Source state");
+
+ new_sav_src->next = saved_source;
+ new_sav_src->old_start = start;
+ new_sav_src->old_pc = pc;
+ new_sav_src->old_end = end;
+ new_sav_src->old_iname = iname;
+ new_sav_src->old_lineno = lineno;
+ new_sav_src->pause_before_pop = file_chg;
+ new_sav_src->sav_rep_multlin = report_multiline;
+ new_sav_src->resump_func = res_func;
+ new_sav_src->resump_param = res_parm;
+
+ saved_source = new_sav_src;
}
-static unsigned long get_word(void)
+/* **************************************************************************
+ *
+ * Function name: drop_source
+ * Synopsis: Remove last saved state of source processing
+ * from the source_state LIFO linked-list,
+ * without (or after) restoring.
+ *
+ * Inputs:
+ * Parameters: NONE
+ * Local Static Variables:
+ * saved_source Pointer to the source_state data-structure
+ *
+ * Outputs:
+ * Returned Value: NONE
+ * Local Static Variables:
+ * saved_source Points to previous source_state entry
+ * Memory Freed
+ * Saved source_state entry that was just "dropped"
+ *
+ * Error Detection:
+ * None. Called only when linked-list is known not to be at end.
+ *
+ **************************************************************************** */
+
+static void drop_source( void)
{
+ source_state_t *former_sav_src = saved_source;
+
+ saved_source = saved_source->next ;
+ free( former_sav_src);
+}
+
+/* **************************************************************************
+ *
+ * Function name: pop_source
+ * Synopsis: Restore the state of source processing as it was
+ * last saved in the source_state linked-list.
+ *
+ * Inputs:
+ * Parameters: NONE
+ * Local Static Variables:
+ * saved_source Pointer to the source_state data-structure
+ * need_to_pop_source If TRUE, don't check before popping.
+ *
+ * Outputs:
+ * Returned Value: TRUE if reached end of linked-list
+ * Global Variables:
+ * start Points to restored input buffer
+ * end Points to end of restored input buffer
+ * pc Input point in restored buffer
+ * iname Name of restored source file
+ * lineno Line number in restored source file
+ * report_multiline Restored to saved value.
+ * Local Static Variables:
+ * saved_source Points to previous source_state entry
+ * need_to_pop_source TRUE if postponed popping till next time
+ * Memory Freed
+ * Saved source-state entry that was just "popped"
+ *
+ * Process Explanation:
+ * First check the need_to_pop_source flag.
+ * If it is set, we will clear it and go ahead and pop.
+ * If it is not set, we will check the pause_before_pop field
+ * of the top entry in the source_state linked-list.
+ * If the pause_before_pop field is set, we will set the
+ * need_to_pop_source flag and return.
+ * If it is not, we will go ahead and pop.
+ * If we are going to go ahead and pop, we will call the
+ * "Resume-Processing" routine (if it's not NULL) before
+ * we restore the saved source state.
+ *
+ **************************************************************************** */
+
+static bool pop_source( void )
+{
+ bool retval = TRUE;
+
+ if ( saved_source != NULL )
+ {
+ retval = FALSE;
+ if ( need_to_pop_source )
+ {
+ need_to_pop_source = FALSE;
+ }else{
+ if ( saved_source->pause_before_pop )
+ {
+ need_to_pop_source = TRUE;
+ return( retval);
+ }
+ }
+
+ if ( saved_source->resump_func != NULL )
+ {
+ saved_source->resump_func( saved_source->resump_param);
+ }
+ report_multiline = saved_source->sav_rep_multlin;
+ lineno = saved_source->old_lineno ;
+ iname = saved_source->old_iname ;
+ end = saved_source->old_end ;
+ pc = saved_source->old_pc ;
+ start = saved_source->old_start ;
+
+ drop_source();
+ }
+ return( retval);
+}
+
+
+/* **************************************************************************
+ *
+ * Function name: get_word
+ * Synopsis: Gather the next "word" (aka Forth Token) from the
+ * input stream.
+ * A Forth Token is, of course, a string of characters
+ * delimited by white-space (blank, tab or new-line).
+ * Do not increment line-number counters here; leave
+ * the delimiter after the word unconsumed.
+ *
+ * Inputs:
+ * Parameters: NONE
+ * Global Variables:
+ * pc Input-stream Scanning Pointer
+ * Local Static Variables:
+ * need_to_pop_source If TRUE, pop_source() as first step
+ *
+ * Outputs:
+ * Returned Value: Length of "word" gotten;
+ * 0 if reached end of file.
+ * -1 if reached end of primary input
+ * (I.e., end of all source)
+ * Global Variables:
+ * statbuf Copy of "gotten" word
+ * pc Advanced to end of "gotten" word,
+ * (i.e., the next word is "consumed")
+ * unless returning zero.
+ * abs_token_no Incremented, if valid "word" (token)
+ * was gotten.
+ *
+ * Process Explanation:
+ * Skip whitespace to the start of the token,
+ * then skip printable characters to the end of the token.
+ * That part's easy, but what about when skipping whitespace
+ * brings you to the end of the input stream?
+ * First, look at the need_to_pop_source flag. If it's set,
+ * we came to the end of the input stream the last time
+ * through. Now we need to pop_source() first.
+ * Next, we start skipping whitespace; this detects when we've
+ * reached the end of the input stream. If we have,
+ * then we need to pop_source() again.
+ * If pop_source() returned a TRUE, we've reached the end
+ * of the primary input file. Return -1.
+ * If pop_source() turned the need_to_pop_source flag
+ * to TRUE again, then we need to "pause" until the
+ * next time through; return zero.
+ * Otherwise, we proceed with collecting the token as described.
+ *
+ * Revision History:
+ * Updated Thu, 23 Feb 2006 by David L. Paktor
+ * Tied this routine in with a more sophisticated mechanism that
+ * makes a smooth transition between processing the body of
+ * a Macro, a User-defined Symbol or an FLOADed file, and
+ * the resumption of processing the source file, so that the
+ * end-of-file will only be seen at the end of the primary
+ * input file (the one that came from the command-line)
+ * Updated Fri, 24 Feb 2006 by David L. Paktor
+ * This is trickier than I thought. Added a global indicator
+ * of whether a file-boundary was crossed while getting
+ * the word; previously, that was indicated by a return
+ * value of zero, which now means something else...
+ * The flag, closed_stream , will be cleared every time this
+ * routine is entered, and set whenever close_stream() is
+ * entered.
+ * Updated Tue, 28 Feb 2006 at 10:13 PST by David L. Paktor
+ * Trickier still. On crossing a file-boundary, must not
+ * consume the first word in the resumed file, for one
+ * call; instead, return zero. Consume it on the next
+ * call. The closed_stream flag is now irrelevant and
+ * has gone away.
+ *
+ **************************************************************************** */
+
+signed long get_word( void)
+{
size_t len;
u8 *str;
+ bool keep_skipping;
+ bool pop_result;
- pc=skipws(pc);
- if (pc>=end)
+ if ( need_to_pop_source )
+ {
+ pop_result = pop_source();
+ }
+
+ do {
+ keep_skipping = skip_ws();
+ if ( keep_skipping )
+ {
+ pop_result = pop_source();
+ if ( pop_result || need_to_pop_source )
+ {
+ statbuf[0] = 0;
+ if ( pop_result )
+ {
+ return -1;
+ }
return 0;
+ }
+ }
+ } while ( keep_skipping );
str=pc;
- while (str && *str && *str!='\n' && *str!='\t' && *str!=' ')
+ while ( (str < end) && *str && *str!='\n' && *str!='\t' && *str!=' ')
str++;
len=(size_t)(str-pc);
- if (len>1023) {
- printf("%s:%d: error: buffer overflow.\n", iname, lineno);
- ERROR;
+ if (len >= GET_BUF_MAX )
+ {
+ tokenization_error ( FATAL,
+ "get_word buffer overflow. Max is %d.", GET_BUF_MAX-1 );
}
memcpy(statbuf, pc, len);
@@ -112,39 +640,297 @@
iname, lineno, statbuf, len);
#endif
pc+=len;
+ abs_token_no++;
return len;
}
-static unsigned long get_until(char needle)
+
+/* **************************************************************************
+ *
+ * Function name: get_word_in_line
+ * Synopsis: Get the next word on the same line as the current
+ * line of input. If the end of line was reached
+ * before a word was found, print an error message
+ * and return an indication.
+ *
+ * Inputs:
+ * Parameters:
+ * func_nam Name of the function expecting the same-line
+ * input; for use in the Error Message.
+ * If NULL, do not issue Error Message
+ * Global Variables:
+ * pc Input character pointer. Saved for comparison
+ * lineno Current input line number. Saved for comparison
+ *
+ * Outputs:
+ * Returned Value: TRUE = success. Word was acquired on same line.
+ * Global Variables:
+ * statbuf Advanced to the next word in the input stream.
+ * pc Advanced if no error; restored otherwise.
+ *
+ * Error Detection:
+ * If no next word is gotten (i.e., we're at end-of-file), or if
+ * one is gotten but not on the same line, the routine will
+ * return FALSE; if func_nam is not NULL, an ERROR Message
+ * will be issued.
+ * Also, the values of PC LINENO and ABS_TOKEN_NO will be reset
+ * to the positions they had when this routine was entered.
+ *
+ **************************************************************************** */
+
+bool get_word_in_line( char *func_nam)
{
- u8 *safe;
- unsigned long len;
+ signed long wlen;
+ bool retval = TRUE;
+ u8 *save_pc = pc;
+ unsigned int save_lineno = lineno;
+ unsigned int save_abs_token_no = abs_token_no;
- safe=pc;
- pc=firstchar(needle,safe);
- if (pc>=end)
- return 0;
+ /* Copy of function name, for error message */
+ char func_cpy[FUNC_CPY_BUF_SIZE+1];
- len=(unsigned long)pc-(unsigned long)safe;
- if (len>1023) {
- printf("%s:%d: error: buffer overflow\n", iname, lineno);
- ERROR;
+ /* Do this first, in the likely event that func_nam was statbuf */
+ if ( func_nam != NULL )
+ {
+ strncpy( func_cpy, func_nam, FUNC_CPY_BUF_SIZE);
+ func_cpy[FUNC_CPY_BUF_SIZE] = 0; /* Guarantee a null terminator */
+ }
+
+ wlen = get_word();
+ if ( ( lineno != save_lineno ) || ( wlen <= 0 ) )
+ {
+ abs_token_no = save_abs_token_no;
+ lineno = save_lineno;
+ pc = save_pc;
+ retval = FALSE;
+ if ( func_nam != NULL )
+ {
+ tokenization_error ( TKERROR,
+ "Operator %s expects its target on the same line\n",
+ strupr(func_cpy));
}
+ }
+ return ( retval );
+}
+
+
+/* **************************************************************************
+ *
+ * Function name: get_rest_of_line
+ * Synopsis: Get all the remaining text on the same line as
+ * the current line of input. If there is no text
+ * (not counting whitespace) before the end of line,
+ * return an indication.
+ *
+ * Inputs:
+ * Parameters: NONE
+ * Global Variables:
+ * pc Input character pointer. Saved for restoration
+ * lineno Current input line number. Saved for comparison
+ *
+ * Outputs:
+ * Returned Value: TRUE = success. Text was acquired on same line.
+ * Global Variables:
+ * statbuf Contains the text found in the input stream.
+ * pc Advanced to end of line or of whitespace, if
+ * no error; restored otherwise.
+ * lineno Preserved if no error; otherwise, restored.
+ * abs_token_no Restored if error; otherwise, advanced as normal.
+ *
+ * Error Detection:
+ * Routine will return FALSE if no text is gotten on the same line.
+ *
+ **************************************************************************** */
+
+bool get_rest_of_line( void)
+{
+ bool retval = FALSE;
+ u8 *save_pc = pc;
+ unsigned int save_lineno = lineno;
+ unsigned int save_abs_token_no = abs_token_no;
+
+ if ( INVERSE( skip_ws() ) )
+ {
+ if ( lineno == save_lineno )
+ {
+ signed long wlen = get_until('\n');
+ if ( wlen > 0 ) retval = TRUE;
+ }else{
+ abs_token_no = save_abs_token_no;
+ lineno = save_lineno;
+ pc = save_pc;
+ }
+ }
+ return( retval);
+}
+
+
+/* **************************************************************************
+ *
+ * Function name: warn_unterm
+ * Synopsis: Message for "Unterminated ..." something
+ * Show saved line-number, where the "something" started,
+ * and the definition, if any, in which it occurred.
+ *
+ * Inputs:
+ * Parameters:
+ * severity Type of error/warning message to display
+ * usually either WARNING or TKERROR
+ * something String to print after "Unterminated"
+ * saved_lineno Line-Number where the "something" started
+ * Global Variables:
+ * lineno Saved, then restored.
+ * last_colon_defname Used only if unterm_is_colon is TRUE;
+ * Local Static Variables:
+ * unterm_is_colon See 07 Mar 2006 entry under Rev'n History
+ *
+ * Outputs:
+ * Returned Value: NONE
+ * Global Variables:
+ * lineno Saved, then restored.
+ * Local Static Variables:
+ * unterm_is_colon Reset to FALSE
+ * Printout:
+ * Warning or Error message
+ *
+ * Revision History:
+ * Updated Mon, 06 Mar 2006 by David L. Paktor
+ * Added call to in_last_colon()
+ * Updated Tue, 07 Mar 2006 by David L. Paktor
+ * Call to in_last_colon() works okay in most cases except for
+ * when the "something" is a Colon Definition; there, it
+ * results in the phrase: ... Definition in definition of ...
+ * which is awkward. To eliminate that, I am introducing
+ * a Local Static Variable flag called unterm_is_colon
+ * which will be set only in the appropriate place and
+ * re-cleared here. It's a retro-fit, of course; it could
+ * have been a parameter had the need for it occurred when
+ * this routine was first constructed...
+ *
+ **************************************************************************** */
+
+static bool unterm_is_colon = FALSE;
+void warn_unterm( int severity, char *something, unsigned int saved_lineno)
+{
+ unsigned int tmp = lineno;
+ lineno = saved_lineno;
+ if ( unterm_is_colon )
+ {
+ tokenization_error( severity, "Unterminated %s of %s\n",
+ something, strupr( last_colon_defname) );
+ unterm_is_colon = FALSE;
+ }else{
+ tokenization_error( severity, "Unterminated %s", something);
+ in_last_colon();
+ }
+ lineno = tmp;
+}
+
+/* **************************************************************************
+ *
+ * Function name: warn_if_multiline
+ * Synopsis: Test for "Multi-line ..." something and issue WARNING
+ * Show saved line-number, where the "something" started
+ *
+ * Inputs:
+ * Parameters:
+ * something String to print after "Unterminated"
+ * start_lineno Line-Number where the "something" started
+ * Global Variables:
+ * lineno Line-Number where we are now
+ * iname Input file name, to satisfy ...where_started()
+ * (Not crossing any actual file boundary.)
+ * report_multiline TRUE = go ahead with the message
+ *
+ * Outputs:
+ * Returned Value: NONE
+ * Global Variables:
+ * report_multiline Restored to TRUE.
+ *
+ * Error Detection:
+ * Only issue message if the current lineno doesn't equal
+ * the start_lineno
+ *
+ * Process Explanation:
+ * The directive "multi-line" allows the user to specify that
+ * the next "Multi-line ..." something is intentional, and
+ * will cause its warning to be suppressed. It remains in
+ * effect until it's "used"; afterwards, it's reset.
+ *
+ **************************************************************************** */
+
+void warn_if_multiline( char *something, unsigned int start_lineno )
+{
+ if ( report_multiline && ( start_lineno != lineno ) )
+ {
+ tokenization_error( WARNING, "Multi-line %s, started", something);
+ where_started( iname, start_lineno);
+ }
+ report_multiline = TRUE;
+}
+
+
+/* **************************************************************************
+ *
+ * Function name: string_remark
+ * Synopsis: Suspend string parsing past end of line and
+ * whitespace at start of the new line.
+ *
+ * Inputs:
+ * Parameters:
+ * errmsg_txt Text to be used for error-message.
+ * Global Variables:
+ * pc Input-source Scanning pointer
+ *
+ * Outputs:
+ * Returned Value: NONE
+ * Global Variables:
+ * pc Will point to first non-blank in new line
+ *
+ * Error Detection:
+ * The return value of the skip_until() or skip_ws() routine
+ * will indicate if PC goes past END. Issue a WARNING.
+ * The calling routine will handle things from there.
+ *
+ **************************************************************************** */
+
+static void string_remark(char *errmsg_txt)
+{
+ unsigned int sav_lineno = lineno;
+ bool eof = skip_until('\n');
+ if ( ! eof )
+ {
+ eof = skip_ws();
+ }
+ if ( eof )
+ {
+ warn_unterm(WARNING, errmsg_txt, sav_lineno);
+ }
- memcpy(statbuf, safe, len);
- statbuf[len]=0;
- return len;
}
+
+/* Convert the given string to a number in the supplied base */
+/* Allow -- and ignore -- embedded periods. */
+/* The endptr param represents a pointer that will be updated
+ * with the address of the first non-numeric character encountered,
+ * (unless it is a NULL, in which case it is ignored).
+ */
+/* There is no test for a completely invalid string;
+ * the calling routine is responsible for ascertaining
+ * the validity of the string being passed.
+ */
static long parse_number(u8 *start, u8 **endptr, int lbase)
{
long val = 0;
- int negative = 0, curr;
+ bool negative = FALSE ;
+ int curr;
u8 *nptr=start;
curr = *nptr;
- if (curr == '-') {
- negative=1;
+ if (curr == '-')
+ {
+ negative = TRUE ;
nptr++;
}
@@ -177,265 +963,3486 @@
*endptr=nptr;
if (negative)
- return -val;
+ {
+ val = -val;
+ }
return val;
}
-static u8 *get_sequence(u8 *walk)
+/* **************************************************************************
+ *
+ * Function name: add_byte_to_string
+ * Synopsis: Add the given byte (or character) to the string
+ * being accumulated in statbuf, but protect
+ * against a buffer overflow.
+ *
+ * Inputs:
+ * Parameters:
+ * nu_byte The given character to be added
+ * walk Pointer to pointer to the position
+ * in statbuf where the character
+ * is to be placed
+ * Global Variables:
+ * statbuf Buffer where the string is accumulated
+ * Macros:
+ * GET_BUF_MAX Size of the buffer
+ *
+ * Outputs:
+ * Returned Value: NONE
+ * Supplied Pointers:
+ * **walk Given character is placed here
+ * *walk Incremented in any case
+ *
+ * Error Detection:
+ * If walk has reached end of string buffer, do not place
+ * the character, but continue to increment walk .
+ * Calling routine will detect overflow.
+ *
+ **************************************************************************** */
+
+static void add_byte_to_string( u8 nu_byte, u8 **walk )
{
- u8 val, pval[3];
+ if ( *walk - statbuf < GET_BUF_MAX )
+ {
+ **walk = nu_byte;
+ }
+ (*walk)++;
+}
+
+/* **************************************************************************
+ *
+ * Function name: c_string_escape
+ * Synopsis: Process C-style escape syntax in strings
+ *
+ * Inputs:
+ * Parameters:
+ * walk Pointer to pointer to area into
+ * which to put acquired values
+ * Global Variables:
+ * pc Input-source Scanning pointer
+ *
+ * Outputs:
+ * Returned Value: NONE
+ * Global Variables:
+ * pc Point to last character processed.
+ * Supplied Pointers:
+ * *walk Advanced by number of bytes acquired
+ *
+ * Error Detection:
+ * WARNING conditions. See under "Process Explanation" below.
+ *
+ * Process Explanation:
+ * Start with PC pointing to the first character to process
+ * i.e., after the backslash.
+ * We recognize newline, tab and numbers
+ * A digit-string in the current base can be converted to a number.
+ * The first non-numeric character ends the numeric sequence
+ * and gets swallowed up.
+ * If the number exceeds the size of a byte, use the truncated
+ * value and issue a WARNING.
+ * If the first character in the "digit"-string was non-numeric,
+ * use the character literally and issue a WARNING.
+ * If the character that ended the numeric sequence is a quote,
+ * it might be the end of the string, or the start of a
+ * special-character or even of an "( ... ) hex-sequence,
+ * so don't swallow it up.
+ *
+ * Still to be done:
+ * Better protection against PC pointer-over-run past END.
+ * Currently, this works, but it's held together by threads:
+ * Because init_stream forces a null-byte at the end of
+ * the input buffer, parse_number() exits immediately upon
+ * encountering it. This situation could be covered more
+ * robustly...
+ *
+ **************************************************************************** */
+
+static void c_string_escape( u8 **walk)
+{
+ char c = *pc;
+ u8 val;
+ /* We will come out of this "switch" statement
+ * with a value for val and a decision
+ * as to whether to write it.
+ */
+ bool write_val = TRUE;
- pc++; /* skip the ( */
+ switch (c)
+ {
+ case 'n':
+ /* newline */
+ val = '\n';
+ break;
+ case 't':
+ /* tab */
+ val = '\t';
+ break;
+ default:
+
+ /* Digit-string? Convert it to a number, using the current base.
+ * The first non-numeric character ends the numeric sequence
+ * and gets swallowed up.
+ * If the number exceeds the size of a byte, use the truncated
+ * value and issue a WARNING.
+ * If the first character in the "digit"-string was non-numeric,
+ * use the character literally and issue a WARNING.
+ */
+
+ /*
+ * If the sequence ender is a quote, it might be the end of
+ * the string, or the start of a special-character or even
+ * of an "( ... ) hex-sequence, so don't swallow it up.
+ */
+ {
+ long lval;
+ u8 *sav_pc = pc;
+ lval=parse_number(pc, &pc, base);
+ val = (u8)lval;
#ifdef DEBUG_SCANNER
- printf("%s:%d: debug: hex field:", iname, lineno);
+ if (verbose)
+ printf( "%s:%d: debug: escape code "
+ "0x%x\n",iname, lineno, val);
#endif
- pval[1]=0; pval[2]=0;
+ if ( lval > 0x0ff )
+ {
+ tokenization_error ( WARNING,
+ "Numeric String after \\ overflows byte. "
+ "Using 0x%02x.\n", val);
+ }
- for(;;) {
- while (!isxdigit(*pc) && (*pc) != ')')
- pc++;
+ if ( pc == sav_pc )
+ {
+ /* NOTE: Here, PC hasn't been advanced past its
+ * saved value, so we can count on C remaining
+ * unchanged since the start of the routine.
+ */
+ /* Don't use the null-byte at the end of the buffer */
+ if ( ( pc >= end )
+ /* or a sequence-ending quote. */
+ || ( c == '"' ) )
+ {
+ write_val = FALSE;
+ }else{
+ /* In the WARNING message, print the character
+ * if it's printable or show it in hex
+ * if it's not.
+ */
+ if ( (c > 0x20 ) && ( c <= 0x7e) )
+ {
+ tokenization_error ( WARNING,
+ "Unrecognized character, %c, "
+ "after \\ in string. "
+ "Using it literally.\n", c);
+ }else{
+ tokenization_error ( WARNING,
+ "Unrecognized character, 0x%02x, "
+ "after \\ in string. "
+ "Using it literally.\n", c);
+ }
+ val = c;
+ }
+ }
+ /* NOTE: Here, however, PC may have been advanced... */
+ /* Don't swallow the sequence-ender if it's a quote. */
+ if ( *pc == '"' )
+ {
+ pc--;
+ }
- pval[0]=*pc;
- if (pval[0]==')')
- break;
+ } /* End of the "default" clause */
+ } /* End of the "switch" statement */
- pc++; /* this cannot be a \n */
+ if ( write_val ) add_byte_to_string( val, walk );
- pval[1]=*pc;
- if ( *pc!=')' && *pc++=='\n' )
- lineno++;
-
- val=parse_number(pval, NULL, 16);
- *(walk++)=val;
+}
+
+/* **************************************************************************
+ *
+ * Function name: get_sequence
+ * Synopsis: Process the Hex-Number option in strings
+ * Protect against PC pointer-over-run past END.
+ *
+ * Inputs:
+ * Parameters:
+ * **walk Pointer to pointer to area into which
+ * to put acquired values
+ * Global Variables:
+ * pc Input-source Scanning pointer
+ * end End of input-source buffer
+ *
+ * Outputs:
+ * Returned Value: TRUE = "Normal Completion" (I.e., not EOF)
+ * Global Variables:
+ * pc Points at terminating close-paren, or END
+ * lineno Input File Line-Number Counter, may be incr'd
+ * Supplied Pointers:
+ * *walk Advanced by number of values acquired
+ *
+ * Error Detection:
+ * End-of-file encountered before end of hex-sequence:
+ * Issue a Warning, conclude processing, return FALSE.
+ *
+ * Process Explanation:
+ * SETUP and RULES:
+ * Start with PC pointing to the first character
+ * after the '(' (Open-Paren)
+ * Bytes are gathered from digits in pairs, except
+ * when separated they are treated singly.
+ * Allow a backslash in the middle of the sequence
+ * to skip to the end of the line and past the
+ * whitespace at the start of the next line,
+ * i.e., it acts as a comment-escape.
+ *
+ * INITIALIZE:
+ * PV_indx = 0
+ * Set return-indicator to "Abnormal Completion"
+ * Ready_to_Parse = FALSE
+ * Stuff NULL into PVAL[2]
+ * WHILE PC is less than END
+ * Pick up character at PC into Next_Ch
+ * IF Next_Ch is close-paren :
+ * Set return-indicator to "Normal Completion".
+ * Done! Break out of loop.
+ * ENDIF
+ * IF comment-escape behavior (controlled by means of a
+ * command-line switch) is allowed
+ * IF Next_Ch is backslash :
+ * Skip to end-of line, skip whitespace.
+ * If that makes PC reach END : WARNING message.
+ * (Don't need to break out of loop;
+ * normal test will terminate.)
+ * CONTINUE Loop.
+ * (Don't increment PC; PC is already at right place).
+ * ENDIF
+ * ENDIF
+ * IF Next_Ch is a valid Hex-Digit character :
+ * Stuff it into PVAL[PV_indx]
+ * IF (PV_indx is 0) :
+ * Increment PV_indx
+ * ELSE
+ * Set Ready_to_Parse to TRUE
+ * ENDIF
+ * ELSE
+ * IF Next_Ch is a New-Line, increment Line Number counter
+ * IF (PV_indx is 1) :
+ * Stuff NULL into PVAL[1]
+ * Set Ready_to_Parse to TRUE
+ * ENDIF
+ * ENDIF
+ * IF Ready_to_Parse
+ * Parse PVAL
+ * Stuff into WALK
+ * Reset PV_indx to zero
+ * Reset Ready_to_Parse to FALSE
+ * ENDIF
+ * Increment PC
+ * REPEAT
+ * Return with Normal/Abnormal completion indicator
+ *
+ **************************************************************************** */
+
+static bool get_sequence(u8 **walk)
+{
+ int pv_indx = 0;
+ bool retval = FALSE; /* "Abnormal Completion" indicator */
+ bool ready_to_parse = FALSE;
+ char next_ch;
+ char pval[3];
+
#ifdef DEBUG_SCANNER
+ printf("%s:%d: debug: hex field:", iname, lineno);
+#endif
+ pval[2]=0;
+
+ while ( pc < end )
+ {
+ next_ch = *pc;
+ if ( next_ch == ')' )
+ {
+ retval = TRUE;
+ break;
+ }
+ if ( hex_remark_escape )
+ {
+ if ( next_ch == '\\' )
+ {
+ string_remark("string hex-sequence remark");
+ continue;
+ }
+ }
+ if ( isxdigit(next_ch) )
+ {
+ pval[pv_indx] = next_ch;
+ if ( pv_indx == 0 )
+ {
+ pv_indx++;
+ }else{
+ ready_to_parse = TRUE;
+ }
+ }else{
+ if ( next_ch == '\n' ) lineno++ ;
+ if ( pv_indx != 0 )
+ {
+ pval[1] = 0;
+ ready_to_parse = TRUE;
+ }
+ }
+ if ( ready_to_parse )
+ {
+ u8 val = parse_number(pval, NULL, 16);
+ *((*walk)++)=val;
+#ifdef DEBUG_SCANNER
printf(" %02x",val);
#endif
+ pv_indx = 0;
+ ready_to_parse = FALSE;
}
+ pc++;
+ }
#ifdef DEBUG_SCANNER
printf("\n");
#endif
-
- return walk;
+ return ( retval );
}
-static unsigned long get_string(void)
+/* **************************************************************************
+ *
+ * Return the length of the string.
+ * Pack the string, without the terminating '"' (Quote), into statbuf
+ * Protect against PC pointer-over-run past END.
+ * Enable Quote-Backslash as a String-Remark Escape.
+ * Allowability of Quote-Backslash as a String-Remark is under control
+ * of a command-line switch (string_remark_escape ).
+ * Allowability of C-style escape characters is under control
+ * of a command-line switch ( c_style_string_escape ).
+ *
+ * Truncate string to size of Forth Packed-String (i.e., uses leading
+ * count-byte, so limited to 255, number that one byte can express)
+ * unless the string is being gathered for a Message or is being
+ * consumed for purposes of ignoring it, in either of which case
+ * that limit need not be enforced. Parameter "pack_str" controls
+ * this: TRUE if limit needs to be enforced.
+ *
+ * Issue WARNING if string length gets truncated.
+ * Issue WARNING if string crosses line.
+ * The issuance of the Multi-line WARNING is under control of a
+ * one-shot directive similar to OVERLOAD , called MULTI-LINE
+ *
+ * Still to be decided:
+ * Do we want to bring the allowability of strings crossing
+ * lines under control of a command-line switch?
+ *
+ ************************************************************************** */
+
+static signed long get_string( bool pack_str)
{
u8 *walk;
unsigned long len;
- bool run=1;
- u8 c, val;
+ char c;
+ bool run = TRUE;
+ unsigned long start_lineno = lineno; /* For warning message */
+ /*
+ * Bump past the single whitespace character that delimits
+ * the command -- e.g., ." or " or suchlike -- that
+ * starts the string. Allow new-line to be a command-
+ * -delimiting whitespace character. Regard any sub-
+ * sequent whitespace characters as part of the string
+ */
+ if (*pc++=='\n') lineno++;
+
+ got_until_eof = TRUE ;
+
walk=statbuf;
while (run) {
- switch ((c=*pc)) {
- case '\\':
- switch ((c=*(++pc))) {
- case 'n':
- /* newline */
- *(walk++)='\n';
+ switch ((c=*pc))
+ {
+ /* Standard use of '"' (Quote) for special-char escape */
+ case '\"':
+ /* Skip the '"' (Quote) */
+ pc++;
+ /* End of the buffer also ends the string cleanly */
+ if ( pc >= end )
+ {
+ run = FALSE;
+ got_until_eof = FALSE ;
break;
- case 't':
- /* tab */
- *(walk++)='\t';
+ }
+ /* Pick up the next char after the '"' (Quote) */
+ c=*pc;
+ switch (c)
+ {
+ case '(':
+ pc++; /* skip the '(' */
+ run = get_sequence(&walk);
break;
- default:
- val=parse_number(pc, &pc, base);
-#ifdef DEBUG_SCANNER
- if (verbose)
- printf( "%s:%d: debug: escape code "
- "0x%x\n",iname, lineno, val);
-#endif
- *(walk++)=val;
- }
- break;
- case '\"':
- pc++; /* skip the " */
- /* printf("switching: %c\n",*pc); */
- switch(*pc) {
- case '(':
- walk=get_sequence(walk);
- break;
- case '"':
- *(walk++)='"';
- pc++;
- break;
case 'n':
- *(walk++)='\n';
- pc++;
+ add_byte_to_string( '\n', &walk);
break;
case 'r':
- *(walk++)='\r';
- pc++;
+ add_byte_to_string( '\r', &walk);
break;
case 't':
- *(walk++)='\t';
- pc++;
+ add_byte_to_string( '\t', &walk);
break;
case 'f':
- *(walk++)='\f';
- pc++;
+ add_byte_to_string( '\f', &walk);
break;
case 'l':
- *(walk++)='\n';
- pc++;
+ add_byte_to_string( '\n', &walk);
break;
case 'b':
- *(walk++)=0x08;
- pc++;
+ add_byte_to_string( 0x08, &walk);
break;
case '!':
- *(walk++)=0x07;
- pc++;
+ add_byte_to_string( 0x07, &walk);
break;
case '^':
- pc++;
- c=toupper(*(pc++));
- *(walk++)=c-'A';
+ pc++; /* Skip the up-arrow (Caret) */
+ add_byte_to_string( *pc & 0x1f , &walk);
break;
- case '\n':
- lineno++;
+ /* We're done after any of the whitespace
+ * characters follows a quote.
+ */
case ' ':
case '\t':
- run=0;
+ /* Advance past the terminating whitespace
+ * character, except newline.
+ * Let get_word() handle that.
+ */
+ pc++;
+ case '\n':
+ run=FALSE;
+ got_until_eof = FALSE ;
break;
default:
- *(walk++)=*(pc++);
+ /* Control allowability of Quote-Backslash
+ * as a String-Remark by means of a
+ * command-line switch.
+ */
+ if ( string_remark_escape )
+ {
+ if ( c == '\\' )
+ {
+ string_remark("string-escape remark");
+ /* The first non-blank in the new line
+ * has not been processed yet.
+ * Back up to allow it to be.
+ */
+ pc--;
break;
}
+ }
+ add_byte_to_string( c, &walk);
+ }
break;
+ case '\n':
+ /* Allow strings to cross lines. Include the
+ * newline in the string. Account for it.
+ */
+ lineno++;
default:
- *(walk++)=c;
+ /* Control allowability of C-style escape-character
+ * syntax by means of a command-line switch.
+ */
+ if ( c_style_string_escape )
+ {
+ if ( c == '\\' )
+ {
+ pc++;
+ c_string_escape(&walk );
+ break;
+ }
+ }
+ add_byte_to_string( c, &walk);
}
- if (*pc++=='\n') lineno++;
+ /* Advance past the char processed, unless we're done. */
+ if ( run ) pc++;
+ /* Done if we hit end of file before string was concluded */
+ if ( pc >= end )
+ {
+ run = FALSE;
+ if ( got_until_eof )
+ {
+ warn_unterm( WARNING, "string", start_lineno);
+ /* Prevent multiple messages for one error */
+ got_until_eof = FALSE;
+ }
+ }
}
- *(walk++)=0;
-
- if (pc>=end)
- return 0;
-
- len=(unsigned long)walk-(unsigned long)statbuf;
- if (len>1023) {
- printf("%s:%d: error: buffer overflow\n", iname, lineno);
- ERROR;
+ warn_if_multiline( "string", start_lineno);
+
+ len = walk - statbuf;
+ if (len >= GET_BUF_MAX )
+ {
+ tokenization_error ( TKERROR,
+ "get_string buffer overflow. Max is %d\n.", GET_BUF_MAX-1 );
+ len = GET_BUF_MAX-1;
}
#ifdef DEBUG_SCANNER
if (verbose)
printf("%s:%d: debug: scanned string: '%s'\n",
iname, lineno, statbuf);
#endif
+ if ( pack_str && (len > STRING_LEN_MAX) )
+ {
+ tokenization_error ( WARNING,
+ "String length being truncated to %d.\n", STRING_LEN_MAX );
+ len = STRING_LEN_MAX;
+ }
+ statbuf[len] = 0;
- return len>255?255:len;
+ return len ;
}
-static int get_number(long *result)
+
+/* **************************************************************************
+ *
+ * Function name: handle_user_message
+ * Synopsis: Collect a user-generated tokenization-time message;
+ * either print it or discard it. Shared code
+ * for user_message() and skip_user_message()
+ *
+ * Inputs:
+ * Parameters:
+ * delim End-of-string delimiter character.
+ * If it's a double-quote ("), we will use
+ * the get-string() routine, with all
+ * its options, to collect the message.
+ * Otherwise, we'll capture plain text from
+ * the input stream.
+ * print_it TRUE if we should print the message
+ * Local Static Variables:
+ * got_until_eof TRUE if reached end of buffer before delim.
+ * Global Variables:
+ * lineno Save, then restore.
+ *
+ * Outputs:
+ * Returned Value: NONE
+ * Global Variables:
+ * statbuf The string will be collected in here
+ *
+ * Printout (if print_it is TRUE):
+ * The string, with new-line tacked on, will be printed from
+ * the tokenization_error() routine as a MESSAGE.
+ * The line-number will be shown as of the origin of the message
+ *
+ * Error Detection:
+ * Error-reports will be printed regardless of print_it param.
+ * If delimiter was not found, show "Unterminated" warning message.
+ * If delimiter was " (double-quote), the get_string() routine
+ * already checked for a multi-line construct; if delimiter is
+ * a new-line, then a multi-line construct is impossible.
+ * otherwise, we will do the multi-line check here.
+ *
+ **************************************************************************** */
+
+static void handle_user_message( char delim, bool print_it )
{
- u8 lbase, *until;
- long val;
+ signed long wlen;
+ unsigned int start_lineno = lineno;
+ unsigned int multiline_start = lineno; /* For warning message */
+ bool check_multiline = FALSE;
+ const char *ug_msg = "user-generated message";
- lbase=intok?0x10:base;
- val=parse_number(statbuf,&until, lbase);
+ if ( delim == '"' )
+ {
+ wlen = get_string( FALSE);
+ }else{
+ /*
+ * When the message-delimiter is a new-line, and the
+ * command-delimiter was a new-line, it means the
+ * string length is zero; we won't bump the PC.
+ * Otherwise, we will honor the convention we extend
+ * to .( whereby, if the command is delimited
+ * by a new-line, we allow the string to begin
+ * on the next line.
+ */
+ if ( delim == '\n' )
+ {
+ if ( *pc != '\n') pc++;
+ }else{
+ if (*pc++=='\n') lineno++;
+ multiline_start = lineno;
+ check_multiline = TRUE;
+ }
+ wlen = get_until( delim );
+ }
+
+ if ( print_it )
+ {
+ unsigned int tmp_lineno = lineno;
+ lineno = start_lineno;
+ /* Don't add a new-line to body of the message.
+ * Routine already takes care of that.
+ * Besides, buffer might be full...
+ */
+ tokenization_error( MESSAGE, statbuf);
+ lineno = tmp_lineno;
+ }
+
+ if ( got_until_eof ) /* Crude but effective retrofit... */
+ {
+ warn_unterm(WARNING, (char *)ug_msg, start_lineno);
+ }else{
+ if ( check_multiline )
+ {
+ warn_if_multiline( (char *)ug_msg, multiline_start);
+ }
+ }
+}
+
+/* **************************************************************************
+ *
+ * Function name: user_message
+ * Synopsis: Collect a user-generated message and
+ * print it at tokenization-time.
+ *
+ * Tokenizer directive (either mode):
+ * Synonyms String Delimiter
+ * [MESSAGE] #MESSAGE [#MESSAGE] end-of-line
+ * #MESSAGE" "
+ * "Tokenizer-Escape" mode directive String Delimiter
+ * .( )
+ * ." "
+ *
+ * Inputs:
+ * Parameter is the "parameter field" of the TIC entry, which
+ * was initialized to the end-of-string delimiter character.
+ *
+ * Outputs:
+ * Returned Value: NONE
+ * Printout: User-message, parsed from input.
+ *
+ * Extraneous Remarks:
+ * We would have preferred to simply use the "character value"
+ * aspect of the union, but we found portability issues
+ * between big- and little- -endian processors, so we still
+ * have to recast its type here.
+ *
+ **************************************************************************** */
+
+void user_message( tic_param_t pfield )
+{
+ char delim = (char)pfield.deflt_elem ;
+ handle_user_message( delim, TRUE);
+}
+
+/* **************************************************************************
+ *
+ * Function name: skip_user_message
+ * Synopsis: Collect a user-generated message and discard it.
+ * Used when ignoring a Conditional section.
+ *
+ * Tokenizer directive (either mode):
+ * Synonyms String Delimiter
+ * [MESSAGE] #MESSAGE [#MESSAGE] end-of-line
+ * #MESSAGE" "
+ * "Tokenizer-Escape" mode directive String Delimiter
+ * .( )
+ * ." "
+ *
+ * Inputs:
+ * Parameters:
+ * pfield "Parameter field" of the TIC entry, which
+ * was initialized to the delimiter.
+ *
+ * Outputs:
+ * Returned Value: NONE
+ * Printout: NONE
+ *
+ **************************************************************************** */
+
+void skip_user_message( tic_param_t pfield )
+{
+ char delim = (char)pfield.deflt_elem ;
+ handle_user_message( delim, FALSE);
+}
+
+
+
+/* **************************************************************************
+ *
+ * Function name: get_number
+ * Synopsis: If the word retrieved from the input stream is a
+ * valid number (under the current base) convert it.
+ * Return an indication if it was not.
+ *
+ * Inputs:
+ * Parameters:
+ * *result Pointer to place to return the number
+ * Global Variables:
+ * statbuf The word just read that is to be converted.
+ * base The current numeric-interpretation base.
+ *
+ * Outputs:
+ * Returned Value: TRUE = Input was a valid number
+ * Supplied Pointers:
+ * *result The converted number, if valid
+ * otherwise undefined
+ *
+ * Revision History:
+ * Updated Mon, 28 Mar 2005 by David L. Paktor
+ * Always use the current base.
+ * Reversed sense of return-flag.
+ *
+ **************************************************************************** */
+
+bool get_number( long *result)
+{
+ u8 *until;
+ long val;
+ bool retval = FALSE ;
+
+ val = parse_number(statbuf, &until, base);
#ifdef DEBUG_SCANNER
- printf("%s:%d: debug: parsing number: base 0x%x, val 0x%lx, "
- "processed %ld of %ld bytes\n", iname, lineno,
- lbase, val,(size_t)(until-statbuf), strlen((char *)statbuf));
+ printf("%s:%d: debug: parsing number: base 0x%x, val 0x%lx, "
+ "processed %ld of %ld bytes\n", iname, lineno,
+ base, val,(size_t)(until-statbuf), strlen((char *)statbuf));
#endif
- if (until==(statbuf+strlen((char *)statbuf))) {
- *result=val;
- return 0;
- }
-
- return -1;
+ /* If number-parsing ended before the end of the input word,
+ * then the input word was not a valid number.
+ */
+ if (until==(statbuf+strlen((char *)statbuf)))
+ {
+ *result=val;
+ retval = TRUE;
+ }
+
+ return ( retval );
}
+/* **************************************************************************
+ *
+ * Function name: deliver_number
+ * Synopsis: Deliver the supplied number according to the
+ * state of the tokenizer:
+ * In normal tokenization mode, emit it as an
+ * FCode literal.
+ * In "Tokenizer-Escape" mode, push it onto
+ * the Data Stack.
+ *
+ * Inputs:
+ * Parameters:
+ * numval The number, verified to be valid.
+ * Global Variables:
+ * in_tokz_esc TRUE if tokenizer is in "Tokenizer Escape" mode.
+ *
+ * Outputs:
+ * Returned Value: NONE
+ * Items Pushed onto Data-Stack:
+ * Top: The number, if in_tokz_esc was TRUE
+ * FCode Output buffer:
+ * If in_tokz_esc was FALSE, a b(lit) token will be written,
+ * followed by the number.
+ *
+ **************************************************************************** */
+
+static void deliver_number( long numval)
+{
+ if ( in_tokz_esc )
+ {
+ dpush( numval );
+ } else {
+ emit_literal(numval);
+ }
+}
+/* **************************************************************************
+ *
+ * Function name: handle_number
+ * Synopsis: Convert the word just retrieved from the input stream
+ * to a number.
+ * Indicate whether the string was a valid number and
+ * deliver it, as appropriate.
+ *
+ * Inputs:
+ * Parameters: NONE
+ * Global Variables:
+ * statbuf The word that was just read, and to be converted.
+ *
+ * Outputs:
+ * Returned Value: TRUE = Input string was a valid number
+ * If input string was a valid number, the converted number will
+ * be delivered, as appropriate, by deliver_number().
+ *
+ **************************************************************************** */
+
+static bool handle_number( void )
+{
+ bool retval ;
+ long numval;
+
+ retval = get_number( &numval );
+ if ( retval )
+ {
+ deliver_number( numval );
+ }
+
+ return ( retval );
+}
+
+/* **************************************************************************
+ *
+ * Function name: ascii_right_number
+ * Synopsis: Convert a character sequence to a number, justified
+ * toward the right (i.e., the low-order bytes) and
+ * deliver it, as appropriate.
+ *
+ * Inputs:
+ * Parameters:
+ * in_str The input string
+ *
+ * Outputs:
+ * Returned Value: NONE
+ * The converted number will be delivered by deliver_number().
+ *
+ * Process Explanation:
+ * The last four characters in the sequence will become the number.
+ * If there are fewer than four, they will fill the low-order part
+ * of the number.
+ * Example: PCIR is converted to h# 50434952
+ * CPU is converted to h# 00435055
+ * and
+ * LotsOfStuff is equivalent to a# tuff
+ * and is converted to h# 74756666
+ *
+ **************************************************************************** */
+
+static void ascii_right_number( char *in_str)
+{
+ u8 nxt_ch;
+ char *str_ptr = in_str;
+ long numval = 0;
+
+ for ( nxt_ch = (u8)*str_ptr ;
+ ( nxt_ch = (u8)*str_ptr ) != 0 ;
+ str_ptr++ )
+ {
+ numval = ( numval << 8 ) + nxt_ch ;
+ }
+ deliver_number( numval );
+}
+
+
+/* **************************************************************************
+ *
+ * Function name: ascii_left_number
+ * Synopsis: Similar to ascii_right_number() except justified
+ * toward the left (i.e., the high-order bytes).
+ *
+ *
+ * Inputs:
+ * Parameters:
+ * in_str The input string
+ *
+ * Outputs:
+ * Returned Value: NONE
+ * The converted number will be delivered by deliver_number().
+ *
+ * Process Explanation:
+ * If there are fewer than four characters in the sequence, they
+ * will fill the high-order part of the number.
+ * CPU is converted to h# 43505500
+ * In all other respects, similar to ascii_right_number()
+ *
+ **************************************************************************** */
+
+static void ascii_left_number( char *in_str)
+{
+ u8 nxt_ch;
+ char *str_ptr = in_str;
+ long numval = 0;
+ int shift_amt = 24;
+ bool shift_over = FALSE ;
+
+ for ( nxt_ch = (u8)*str_ptr ;
+ ( nxt_ch = (u8)*str_ptr ) != 0 ;
+ str_ptr++ )
+ {
+ if ( shift_over ) numval <<= 8;
+ if ( shift_amt == 0 ) shift_over = TRUE ;
+ numval += ( nxt_ch << shift_amt );
+ if ( shift_amt > 0 ) shift_amt -= 8;
+ }
+ deliver_number( numval );
+
+}
+
+/* **************************************************************************
+ *
+ * Function name: init_scanner
+ * Synopsis: Allocate memory the Scanner will need.
+ * Only need to call once per program run.
+ *
+ **************************************************************************** */
+
void init_scanner(void)
{
- statbuf=malloc(1024);
- if (!statbuf) {
- printf ("no memory.\n");
- exit(-1);
- }
+ statbuf=safe_malloc(GET_BUF_MAX, "initting scanner");
}
+/* **************************************************************************
+ *
+ * Function name: exit_scanner
+ * Synopsis: Free up memory the Scanner used
+ *
+ **************************************************************************** */
+
void exit_scanner(void)
{
free(statbuf);
}
-#define FLAG_EXTERNAL 0x01
-#define FLAG_HEADERS 0x02
-char *name, *alias;
-int flags=0;
+/* **************************************************************************
+ *
+ * Function name: set_hdr_flag
+ * Synopsis: Set the state of the "headered-ness" flag to the
+ * value given, unless over-ridden by one or both
+ * of the "always-..." Command-Line Flags
+ *
+ * Inputs:
+ * Parameters:
+ * new_flag New setting
+ * Global Variables:
+ * always_headers Override HEADERLESS and make HEADERS
+ * always_external Override HEADERLESS and HEADERS;
+ * make EXTERNAL
+ *
+ * Outputs:
+ * Returned Value: None
+ * Local Static Variables:
+ * hdr_flag Adjusted to new setting
+ *
+ * Process Explanation:
+ * If always_headers is TRUE, and new_flag is not FLAG_EXTERNAL
+ * then set to FLAG_HEADERS
+ * If always_external is TRUE, set to FLAG_EXTERNAL, regardless.
+ * (Note: always_external over-rides always_headers).
+ * Otherwise, set to new_flag
+ *
+ **************************************************************************** */
-static int create_word(void)
+static void set_hdr_flag( headeredness new_flag)
{
- unsigned long wlen;
+ headeredness new_state = new_flag;
+ switch ( new_flag)
+ {
+ case FLAG_HEADERLESS:
+ {
+ if ( always_headers )
+ { new_state = FLAG_HEADERS;
+ }
+ /* No break. Intentional... */
+ }
+ case FLAG_HEADERS:
+ {
+ if ( always_external )
+ { new_state = FLAG_EXTERNAL;
+ }
+ /* No break. Intentional... */
+ }
+ case FLAG_EXTERNAL:
+ break; /* Satisfy compiler's error-checking... */
+ /* No default needed here... */
+ }
- if (incolon) {
- printf("%s:%d: error: creating words not allowed "
- "in colon definition.\n", iname, lineno);
- ERROR;
+ hdr_flag = new_state;
+
+}
+
+
+/* **************************************************************************
+ *
+ * Function name: init_scan_state
+ * Synopsis: Initialize various state variables for each time
+ * a new tokenization scan is started.
+ *
+ * Inputs:
+ * Parameters: NONE
+ *
+ * Outputs:
+ * Returned Value: NONE
+ * Global Variables: Initialized to:
+ * base 0x0a (I.e., base = "decimal")
+ * nextfcode By reset_fcode_ranges()
+ * pci_is_last_image TRUE
+ * incolon FALSE
+ * Local Static Variables:
+ * hdr_flag FLAG_HEADERLESS (unless over-ridden)
+ * is_instance FALSE
+ * last_colon_filename NULL
+ * instance_filename NULL
+ * dev_change_instance_warning TRUE
+ * instance_definer_gap FALSE
+ * need_to_pop_source FALSE
+ * first_fc_starter TRUE
+ * ret_stk_depth 0
+ * Memory Freed
+ * Copies of input-file name in last_colon_filename and
+ * instance_filename , if allocated.
+ *
+ **************************************************************************** */
+
+void init_scan_state( void)
+{
+ base = 0x0a;
+ pci_is_last_image = TRUE;
+ incolon = FALSE;
+ is_instance = FALSE;
+ set_hdr_flag( FLAG_HEADERLESS);
+ reset_fcode_ranges();
+ first_fc_starter = TRUE;
+ if ( last_colon_filename != NULL ) free( last_colon_filename);
+ if ( instance_filename != NULL ) free( instance_filename);
+ last_colon_filename = NULL;
+ instance_filename = NULL;
+ dev_change_instance_warning = TRUE;
+ instance_definer_gap = FALSE;
+ need_to_pop_source = FALSE;
+ ret_stk_depth = 0;
+}
+
+
+/* **************************************************************************
+ *
+ * Function name: collect_input_filename
+ * Synopsis: Save a copy of the current input file name in the
+ * given variable, for error-reporting purposes
+ *
+ * Inputs:
+ * Parameters:
+ * saved_nam Pointer to pointer for copy of name
+ * Global Variables:
+ * iname Current input file name
+ * Local Static Variables:
+ *
+ * Outputs:
+ * Returned Value: NONE
+ * Supplied Pointers:
+ * *saved_nam Copy of name
+ * Memory Allocated
+ * For copy of input file name
+ * When Freed?
+ * Subsequent call to this routine with same pointer
+ * (Last copy made will be freed if starting a new tokenization,
+ * otherwise, will persist until end of program.)
+ * Memory Freed
+ * Previous copy in same pointer.
+ *
+ * Process Explanation:
+ * If there is a previous copy, and it still matches the current
+ * input-file name, we don't need to free or re-allocate.
+ *
+ **************************************************************************** */
+
+static void collect_input_filename( char **saved_nam)
+{
+ bool update_lcfn = TRUE; /* Need to re-allocate? */
+ if ( *saved_nam != NULL )
+ {
+ if ( strcmp( *saved_nam, iname) == 0 )
+ {
+ /* Last collected filename unchanged from iname */
+ update_lcfn = FALSE;
+ }else{
+ free( *saved_nam);
}
-
- if(nextfcode > 0xfff) {
- printf("%s:%d: error: maximum number of fcode words "
- "reached.\n", iname, lineno);
- ERROR;
+ }
+ if ( update_lcfn )
+ {
+ *saved_nam = strdup(iname);
+ }
+}
+
+/* **************************************************************************
+ *
+ * Function name: test_in_colon
+ * Synopsis: Error-check whether a word is being used in the
+ * correct state, relative to being inside a colon
+ * definition; issue a message if it's not.
+ *
+ * Inputs:
+ * Parameters:
+ * wname The name of the word in question
+ * sb_in_colon TRUE if the name should be used inside
+ * a colon-definition only; FALSE if
+ * it may only be used outside of a
+ * colon-definition.
+ * severity Type of error/warning message to call.
+ * usually either WARNING or TKERROR
+ * use_instead Word the error-message should suggest be
+ * used "instead". This may be a NULL,
+ * in which case the "suggestion" part
+ * of the message will simply be omitted.
+ * Global Variables:
+ * incolon State of the tokenization; TRUE if inside
+ * a colon definition
+ *
+ * Outputs:
+ * Returned Value: TRUE if no error.
+ * Printout: Error messages as indicated.
+ *
+ * Error Detection:
+ * If the state, relative to being inside a colon-definition,
+ * is not what the parameter says it should be, issue a
+ * message of the indicated severity, and return FALSE.
+ *
+ **************************************************************************** */
+
+static bool test_in_colon ( char *wname,
+ bool sb_in_colon, /* "Should Be IN colon" */
+ int severity,
+ char *use_instead)
+{
+ bool is_wrong;
+ bool retval = TRUE ;
+
+ is_wrong = BOOLVAL(( sb_in_colon != FALSE ) != ( incolon != FALSE )) ;
+ if ( is_wrong )
+ {
+ char *ui_pt1 = "";
+ char *ui_pt2 = "";
+ char *ui_pt3 = "";
+ retval = FALSE;
+ if ( use_instead != NULL )
+ {
+ ui_pt1 = " Use ";
+ ui_pt2 = use_instead;
+ ui_pt3 = " instead.";
}
+ tokenization_error ( severity, "The word %s should not be used "
+ "%sside of a colon definition.%s%s%s\n", strupr(wname),
+ sb_in_colon ? "out" : "in", ui_pt1, ui_pt2, ui_pt3 );
+ }
+ return ( retval );
+}
+
+/* **************************************************************************
+ *
+ * Function name: must_be_deep_in_do
+ * Synopsis: Check that the statement in question is called
+ * from inside the given depth of structures
+ * of the DO ... LOOP -type (i.e., any combination
+ * of DO or ?DO and LOOP or +LOOP ).
+ * Show an error if it is not.
+ *
+ **************************************************************************** */
+
+static void must_be_deep_in_do( int how_deep )
+{
+ int functional_depth = do_loop_depth;
+ if ( incolon )
+ {
+ functional_depth -= last_colon_do_depth;
+ }
+ if ( functional_depth < how_deep )
+ {
+ char deep_do[64] = "";
+ int indx;
+ bool prefix = FALSE;
+
+ for ( indx = 0; indx < how_deep ; indx ++ )
+ {
+ strcat( deep_do, "DO ... ");
+ }
+ for ( indx = 0; indx < how_deep ; indx ++ )
+ {
+ if ( prefix )
+ {
+ strcat( deep_do, " ... ");
+ }
+ strcat( deep_do, "LOOP");
+ prefix = TRUE;
+ }
+
+ tokenization_error( TKERROR,
+ "%s outside of %s structure", strupr(statbuf), deep_do);
+ in_last_colon();
+ }
+
+}
+
+/* **************************************************************************
+ *
+ * Function name: bump_ret_stk_depth
+ * Synopsis: Increment or decrement the Return-Stack-Usage-Depth
+ * counter.
+ *
+ * Inputs:
+ * Parameters:
+ * bump Amount by which to increment;
+ * negative number to decrement.
+ * Local Static Variables:
+ * ret_stk_depth The Return-Stack-Usage-Depth counter
+ *
+ * Outputs:
+ * Returned Value: NONE
+ * Local Static Variables:
+ * ret_stk_depth Incremented or decremented
+ *
+ * Process Explanation:
+ * This simple-seeming function is actually a place-holder
+ * for future expansion. Proper error-detection of
+ * Return-Stack usage is considerably more complex than
+ * what we are implementing here, and is deferred for a
+ * later revision.
+ *
+ * Still to be done:
+ * Full detection of whether the Return-Stack has been cleared
+ * when required, including analysis of Return-Stack usage
+ * within Flow-Control constructs, and before Loop elements...
+ *
+ * Extraneous Remarks:
+ * Some FORTHs use a Loop-Control stack separate from the Return-
+ * -Stack, but others use the Return-Stack to keep LOOP-control
+ * elements. An FCode program must be portable between different
+ * environments, and so must adhere to the restrictions listed
+ * in the ANSI Spec:
+ *
+ * 3.2.3.3 Return stack
+ * . . . . . .
+ * A program may use the return stack for temporary storage during the
+ * execution of a definition subject to the following restrictions:
+ * A program shall not access values on the return stack (using R@,
+ * R>, 2R@ or 2R>) that it did not place there using >R or 2>R;
+ * A program shall not access from within a do-loop values placed
+ * on the return stack before the loop was entered;
+ * All values placed on the return stack within a do-loop shall
+ * be removed before I, J, LOOP, +LOOP, UNLOOP, or LEAVE is
+ * executed;
+ * All values placed on the return stack within a definition
+ * shall be removed before the definition is terminated
+ * or before EXIT is executed.
+ *
+ **************************************************************************** */
+
+static void bump_ret_stk_depth( int bump)
+{
+ ret_stk_depth += bump;
+}
+
+
+/* **************************************************************************
+ *
+ * Function name: ret_stk_balance_rpt
+ * Synopsis: Display a Message if usage of the Return-Stack
+ * appears to be out of balance.
+ *
+ * Inputs:
+ * Parameters:
+ * before_what Phrase to use in Message;
+ * if NULL, use statbuf...
+ * clear_it TRUE if this call should also clear the
+ * Return-Stack-Usage-Depth counter
+ * Global Variables:
+ * statbuf Word currently being processed
+ * Local Static Variables:
+ * ret_stk_depth The Return-Stack-Usage-Depth counter
+ *
+ * Outputs:
+ * Returned Value: NONE
+ * Local Static Variables:
+ * ret_stk_depth May be cleared
+ *
+ * Error Detection:
+ * Based simply on whether the Return-Stack-Usage-Depth counter
+ * is zero. This is a weak and uncertain implementation;
+ * therefore, the Message will be a WARNING phrased with
+ * some equivocation.
+ *
+ * Process Explanation:
+ * Proper detection of Return-Stack usage errors is considerably
+ * more complex, and is deferred for a future revision.
+ *
+ * Still to be done:
+ * Correct analysis of Return-Stack usage around Flow-Control
+ * constructs. Consider, for instance, the following:
+ *
+ * blablabla >R yadayada IF R> gubble ELSE flubble R> THEN
+ *
+ * It is, in fact, correct, but the present scheme would
+ * tag it as a possible error. Conversely, something like:
+ *
+ * blablabla >R yadayada IF R> gubble THEN
+ *
+ * would not get tagged, even though it is actually an error.
+ *
+ * The current simple scheme also does not cover Return-Stack
+ * usage within Do-Loops or before Loop elements like I and
+ * J or UNLOOP or LEAVE. Implementing something like that
+ * would probably need to be integrated in with Flow-Control
+ * constructs, and will be noted in flowcontrol.c
+ *
+ **************************************************************************** */
+
+static void ret_stk_balance_rpt( char *before_what, bool clear_it)
+{
+ if ( ret_stk_depth != 0 )
+ {
+ char *what_flow = ret_stk_depth < 0 ? "deficit" : "excess" ;
+ char *what_phr = before_what != NULL ? before_what : strupr(statbuf);
+
+ tokenization_error( WARNING,
+ "Possible Return-Stack %s before %s", what_flow, what_phr);
+ in_last_colon();
+
+ if ( clear_it )
+ {
+ ret_stk_depth = 0;
+ }
+ }
+}
+
+
+/* **************************************************************************
+ *
+ * Function name: ret_stk_access_rpt
+ * Synopsis: Display a Message if an attempt to access a value
+ * on the Return-Stack appears to occur before
+ * one was placed there.
+ *
+ * Inputs:
+ * Parameters: NONE
+ * Global Variables:
+ * statbuf Word currently being processed
+ * Local Static Variables:
+ * ret_stk_depth The Return-Stack-Usage-Depth counter
+ *
+ * Outputs:
+ * Returned Value: NONE
+ *
+ * Error Detection:
+ * Equivocal WARNING, based simply on whether the Return-Stack-
+ * -Usage-Depth counter not positive.
+ *
+ * Process Explanation:
+ * Proper detection is deferred...
+ *
+ * Still to be done:
+ * Correct analysis of Return-Stack usage...
+ *
+ **************************************************************************** */
+
+static void ret_stk_access_rpt( void)
+{
+ if ( ret_stk_depth <= 0 )
+ {
+ tokenization_error( WARNING,
+ "Possible Return-Stack access attempt by %s "
+ "without value having been placed there",
+ strupr(statbuf) );
+ in_last_colon();
+ }
+}
+
+
+
+/* **************************************************************************
+ *
+ * Function name: encode_file
+ * Synopsis: Input a (presumably binary) file and encode it
+ * as a series of strings which will be accumulated
+ * and encoded in a manner appropriate for a property.
+ *
+ * Associated Tokenizer directive: encode-file
+ *
+ * Error Detection:
+ * Handled by support routines.
+ *
+ **************************************************************************** */
+
+static void encode_file( const char *filename )
+{
+ FILE *f;
+ size_t s;
+ int num_encoded=0;
- wlen=get_word();
- name=strdup((char *)statbuf);
+ tokenization_error( INFO, "ENCODing File %s\n", filename );
+ f = open_expanded_file( filename, "rb", "encoding");
+ if( f != NULL )
+ {
+ while( (s=fread(statbuf, 1, STRING_LEN_MAX, f)) )
+ {
+ emit_token("b(\")");
+ emit_string(statbuf, s);
+ emit_token("encode-bytes");
+ if( num_encoded )
+ emit_token("encode+");
+ num_encoded += s;
+ }
+ fclose( f );
+ tokenization_error ( INFO, "ENCODed %d bytes.\n", num_encoded);
+ }
+}
+
+/* **************************************************************************
+ *
+ * Function name: check_name_length
+ * Synopsis: If the length of a user-defined name exceeds the
+ * ANSI-specified maximum of 31 characters, issue
+ * a message. This is a hard-coded limit.
+ * Although our Tokenizer can handle longer names,
+ * they will cause big problems when encountered
+ * by an FCode interpreter.
+ * If the name is going to be included in the binary
+ * output, the message severity must be an ERROR.
+ * Otherwise, if the name is HEADERLESS, the severity
+ * can be reduced to a Warning; if the name is only
+ * defined in "Tokenizer Escape" mode the message
+ * severity can be further reduced to an Advisory.
+ *
+ * Inputs:
+ * Parameters:
+ * wlen Length of the newly-created word
+ * Global Variables:
+ * in_tokz_esc TRUE if in "Tokenizer Escape" mode.
+ * Local Static Variables:
+ * hdr_flag State of headered-ness for name-creation
+ *
+ * Outputs:
+ * Returned Value: NONE
+ * Global Variables:
+ * Printout: ERROR message if applicable.
+ *
+ * Error Detection:
+ * The whole point of this routine.
+ *
+ * Revision History:
+ * Updated Wed, 20 Jul 2005 by David L. Paktor
+ * Escalated from merely an informative warning to a TKERROR
+ * Updated Fri, 21 Oct 2005 by David L. Paktor
+ * Adjust severity if name doesn't go into the FCode anyway...
+ *
+ **************************************************************************** */
+
+void check_name_length( signed long wlen )
+{
+ if ( wlen > 31 )
+ {
+ int severity = TKERROR;
+ if ( in_tokz_esc )
+ { severity = INFO;
+ }else{
+ if (hdr_flag == FLAG_HEADERLESS)
+ { severity = WARNING;
+ }
+ }
+ tokenization_error( severity,
+ "ANSI Forth does not permit definition of names "
+ "longer than 31 characters.\n" );
+ }
+
+}
+
+
+/* **************************************************************************
+ *
+ * Function name: definer_name
+ * Synopsis: Given a defining-word internal token, return
+ * a printable string for the definer, for use
+ * in an error-message.
+ *
+ * Inputs:
+ * Parameters:
+ * definer Internal token for the defining-word
+ * reslt_ptr Pointer to string-pointer that takes
+ * the result, if successful
+ *
+ * Outputs:
+ * Returned Value: TRUE if definer was recognized
+ * Supplied Pointers:
+ * *reslt_ptr If successful, points to printable string;
+ * otherwise, left unchanged.
+ *
+ *
+ **************************************************************************** */
+
+static bool definer_name(fwtoken definer, char **reslt_ptr)
+{
+ bool retval = TRUE;
+ switch (definer)
+ {
+ case VARIABLE:
+ *reslt_ptr = "VARIABLE";
+ break;
+ case DEFER:
+ *reslt_ptr = "DEFER";
+ break;
+ case VALUE:
+ *reslt_ptr = "VALUE";
+ break;
+ case BUFFER:
+ *reslt_ptr = "BUFFER";
+ break;
+ case CONST:
+ *reslt_ptr = "CONSTANT";
+ break;
+ case COLON:
+ *reslt_ptr = "COLON";
+ break;
+ case CREATE:
+ *reslt_ptr = "CREATE";
+ break;
+ case FIELD:
+ *reslt_ptr = "FIELD";
+ break;
+ case MACRO_DEF:
+ *reslt_ptr = "MACRO";
+ break;
+ case ALIAS:
+ *reslt_ptr = "ALIAS";
+ break;
+ case LOCAL_VAL:
+ *reslt_ptr = "Local Value name";
+ break;
+ default:
+ retval = FALSE;
+ }
+
+ return ( retval);
+}
+
+
+/* **************************************************************************
+ *
+ * Function name: as_a_what
+ * Synopsis: Add the phrase "as a[n] <DEF'N_TYPE>" for the given
+ * definition-type to the given string buffer.
+ *
+ * Inputs:
+ * Parameters:
+ * definer Internal token for the defining-word
+ * as_what The string buffer to which to add.
+ *
+ * Outputs:
+ * Returned Value: TRUE if an assigned name was found
+ * for the given definer and text
+ * was added to the buffer.
+ * Supplied Pointers:
+ * *as_what Text is added to this buffer.
+ *
+ * Process Explanation:
+ * The calling routine is responsible to make sure the size of
+ * the buffer is adequate. Allow 25 for this routine.
+ * The added text will not have spaces before or after; if any
+ * are needed, they, too, are the responsibility of the
+ * calling routine. The return value gives a helpful clue.
+ *
+ **************************************************************************** */
+
+bool as_a_what( fwtoken definer, char *as_what)
+{
+ char *defn_type_name;
+ bool retval = definer_name(definer, &defn_type_name);
+ if ( retval )
+ {
+ strcat( as_what, "as a");
+ /* Handle article preceding definer name
+ * that starts with a vowel.
+ */
+ /* HACK: Only one definer name -- ALIAS --
+ * begins with a vowel. Take advantage
+ * of that...
+ * Otherwise, we'd need to do something involving
+ * strchr( "AEIOU", defn_type_name[0] )
+ */
+ if ( definer == ALIAS ) strcat( as_what, "n" );
+
+ strcat( as_what, " ");
+ strcat( as_what, defn_type_name);
+ }
+ return( retval);
+}
+
+
+/* **************************************************************************
+ *
+ * Function name: lookup_word
+ * Synopsis: Find the TIC-entry for the given word in the Current
+ * mode -- relative to "Tokenizer-Escape" -- and
+ * Scope into which definitions are being entered.
+ * Optionally, prepare text for various Message types.
+ *
+ * Inputs:
+ * Parameters:
+ * stat_name Word to look up
+ * where_pt1 Pointer to result-display string, part 1
+ * NULL if not preparing text
+ * where_pt2 Pointer to result-display string, part 2
+ * NULL if not preparing text
+ * Global Variables:
+ * in_tokz_esc TRUE if in "Tokenizer Escape" mode.
+ * scope_is_global TRUE if "global" scope is in effect
+ * current_device_node Current dev-node data-struct
+ * ibm_locals TRUE if IBM-style Locals are enabled
+ *
+ * Outputs:
+ * Returned Value: Pointer to TIC-entry; NULL if not found
+ * Supplied Pointers:
+ * *where_pt1 Result display string, part 1 of 2
+ * *where_pt2 Result display string, part 2 of 2
+ *
+ * Process Explanation:
+ * We will set the two-part result-display string in this routine
+ * because only here do we know in which vocabulary the word
+ * was found.
+ * Pre-load the two parts of the result-display string.
+ * If we are in "Tokenizer Escape" mode, look up the word: first,
+ * in the "Tokenizer Escape" Vocabulary, or, if not found,
+ * among the "Shared" words.
+ * Otherwise, we're in Normal" mode. Look it up: first, among the
+ * Locals, if IBM-style Locals are enabled (it can possibly be
+ * one if "Tokenizer Escape" mode was entered during a colon-
+ * -definition); then, if it was not found and if "Device"
+ * scope is in effect, look in the current device-node; then,
+ * if not found, in the "core" vocabulary.
+ * Load the second part of the result-display string with the
+ * appropriate phrase for whereever it was found.
+ * Then adjust the first part of the result-display string with
+ * the definer, if known.
+ *
+ * The two strings will be formatted to be printed adjacently,
+ * without any additional spaces in the printf() format.
+ * The first part of the result-display string will not start with
+ * a space, but will have an intermediate space if necessary.
+ * The second part of the result-display string will not start
+ * with a space, and will contain the terminating new-line
+ * if appropriate. It might or might not have been built
+ * with a call to in_what_node().
+ *
+ * If the calling routine displays the result-display strings,
+ * it should follow-up with a call to show_node_start()
+ * This will be harmless if in_what_node() was not used
+ * in the construction of the result-display string.
+ * If the calling routine is NOT going to display the result strings,
+ * it should pass NULLs for the string-pointer pointers.
+ *
+ * The second part of the string consists of pre-coded phrases;
+ * therefore, we can directly assign the pointer.
+ * The first part of the string, however, has developed into
+ * something constructed "on the fly". Earlier, it, too,
+ * had been a directly-assignable pointer; all the callers
+ * to this routine expect that. Rather than change all the
+ * callers, we will assign a local buffer for it.
+ *
+ * Extraneous Remarks:
+ * We had to add the rule allowing where_pt1 or where_pt2 to be
+ * NULL after we introduced the in_what_node() function.
+ * We had cases where residue from a lookup for processing
+ * showed up later in an unrelated Message. The NULL rule
+ * should prevent that.
+ *
+ **************************************************************************** */
+
+static char lookup_where_pt1_buf[32];
+
+tic_hdr_t *lookup_word( char *stat_name, char **where_pt1, char **where_pt2 )
+{
+ tic_hdr_t *found = NULL;
+ bool trail_space = TRUE;
+ bool doing_lookup = BOOLVAL( ( where_pt1 != NULL )
+ && ( where_pt2 != NULL ) );
+ char *temp_where_pt2 = "in the core vocabulary.\n";
+
+ lookup_where_pt1_buf[0] = 0; /* Init'lz part-1 buffer */
+
+ /* "Core vocab" refers both to shared fwords and built-in tokens. */
+
+ /* Distinguish between "Normal" and "Tokenizer Escape" mode */
+ if ( in_tokz_esc )
+ { /* "Tokenizer Escape" mode. */
+ found = lookup_tokz_esc( stat_name);
+ if ( found != NULL )
+ {
+ temp_where_pt2 = in_tkz_esc_mode;
+ }else{
+ /* "Core vocabulary". */
+ found = lookup_shared_word( stat_name);
+ }
+ }else{
+ /* "Normal" tokenization mode */
+ if ( ibm_locals )
+ {
+ found = lookup_local( stat_name);
+ if ( doing_lookup && ( found != NULL ) )
+ {
+ trail_space = FALSE;
+ temp_where_pt2 = ".\n";
+ }
+ }
+
+ if ( found == NULL )
+ {
+ found = lookup_in_dev_node( stat_name);
+ if ( found != NULL )
+ {
+ if ( doing_lookup )
+ {
+ temp_where_pt2 = in_what_node( current_device_node);
+ }
+ }else{
+ /* "Core vocabulary". */
+ found = lookup_core_word( stat_name);
+ }
+ }
+ }
+
+ if ( ( doing_lookup ) && ( found != NULL ) )
+ {
+ if ( as_a_what( found->fword_defr, lookup_where_pt1_buf) )
+ {
+ if ( trail_space )
+ {
+ strcat(lookup_where_pt1_buf, " ");
+ }
+ }
+ *where_pt1 = lookup_where_pt1_buf;
+ *where_pt2 = temp_where_pt2;
+ }
+ return( found);
+}
+
+/* **************************************************************************
+ *
+ * Function name: word_exists
+ * Synopsis: Check whether a given word is already defined in the
+ * Current mode -- relative to "Tokenizer-Escape" --
+ * and Scope into which definitions are being entered.
+ * Used for error-reporting.
+ *
+ * Inputs:
+ * Parameters:
+ * stat_name Word to look up
+ * where_pt1 Pointer to string, part 1 of 2,
+ * to display in result
+ * where_pt2 Pointer to string, part 2 of 2,
+ * to display in result
+ *
+ * Outputs:
+ * Returned Value: TRUE if the name exists.
+ * Supplied Pointers:
+ * *where_pt1 Result display string, part 1 of 2
+ * *where_pt2 Result display string, part 2 of 2
+ *
+ * Process Explanation:
+ * If the calling routine displays the result-display strings,
+ * it should follow-up with a call to show_node_start()
+ *
+ * Extraneous Remarks:
+ * This used to be a much heftier routine; now it's just
+ * a wrapper around lookup_word() .
+ *
+ **************************************************************************** */
+
+bool word_exists( char *stat_name, char **where_pt1, char **where_pt2 )
+{
+ bool retval = FALSE;
+ tic_hdr_t *found = lookup_word( stat_name, where_pt1, where_pt2 );
+
+ if ( found != NULL )
+ {
+ retval = TRUE;
+ }
+
+ return( retval);
+}
+
+/* **************************************************************************
+ *
+ * Function name: warn_if_duplicate
+ * Synopsis: Check whether a given word is already defined in
+ * the current mode and issue a warning if it is.
+ *
+ * Inputs:
+ * Parameters:
+ * stat_name Word to check
+ * Global Variables:
+ * verbose_dup_warning Whether to run the check at all.
+ * Local Static Variables:
+ * do_not_overload FALSE if OVERLOAD is in effect.
+ *
+ * Outputs:
+ * Returned Value: NONE
+ * Local Static Variables:
+ * do_not_overload Restored to TRUE
+ * Printout:
+ * Warning message if a duplicate.
+ *
+ * Error Detection:
+ * None. This is merely an informative warning.
+ *
+ * Process Explanation:
+ * "Current mode" -- meaning, whether the tokenizer is operating
+ * in "Tokenizer Escape" mode or in normal tokenization mode --
+ * will be recognized by the word_exists() function.
+ *
+ * Extraneous Remarks:
+ * The OVERLOAD directive is our best shot at creating a more
+ * fine-grained way to temporarily bypass this test when
+ * deliberately overloading a name. It would be nice to have
+ * a mechanism, comparable to the classic
+ * WARNING @ WARNING OFF ..... WARNING !
+ * that could be applied to a range of definitions, but:
+ * (1) That would require more of a true FORTH infrastructure;
+ * hence, more effort than I am willing to invest, at
+ * this juncture, for such a small return,
+ * and
+ * (2) Most intentional-overloading ranges only cover a
+ * single definition anyway.
+ *
+ **************************************************************************** */
+
+void warn_if_duplicate( char *stat_name)
+{
+ if ( verbose_dup_warning && do_not_overload )
+ {
+ char *where_pt1;
+ char *where_pt2;
+ if ( word_exists( stat_name, &where_pt1, &where_pt2) )
+ {
+ tokenization_error( WARNING,
+ "Duplicate definition: %s already exists %s%s",
+ stat_name, where_pt1, where_pt2 );
+ show_node_start();
+ }
+ }
+ do_not_overload = TRUE;
+}
+
+
+/* **************************************************************************
+ *
+ * Function name: glob_not_allowed
+ * Synopsis: Print a Message that "XXX is not allowed."
+ * because Global Scope is in effect.
+ * Used from several places...
+ *
+ * Inputs:
+ * Parameters:
+ * severity Severity of the Message
+ * not_ignoring FALSE = "Ignoring", for the part of the
+ * message about "How It's being Handled"
+ * Global Variables:
+ * statbuf Disallowed word currently being processed
+ *
+ * Outputs:
+ * Returned Value: NONE
+ * Printout: Message of given severity.
+ *
+ **************************************************************************** */
+
+static void glob_not_allowed( int severity, bool not_ignoring)
+{
+ tokenization_error( severity, "Global Scope is in effect; "
+ "%s not allowed. %s.\n",
+ strupr(statbuf),
+ not_ignoring ?
+ "Attempting to compensate.." :
+ "Ignoring" );
+}
+
+
+/* **************************************************************************
+ *
+ * Function name: not_in_dict
+ * Synopsis: Print the message "XXX is not in dictionary."
+ * Used from several places...
+ *
+ * Inputs:
+ * Parameters:
+ * stat_name Word that could not be processed
+ *
+ * Outputs:
+ * Returned Value: NONE
+ * Printout: Error message.
+ *
+ **************************************************************************** */
+
+static void not_in_dict( char *stat_name)
+{
+ tokenization_error ( TKERROR,
+ "Word %s is not in dictionary.\n", stat_name);
+}
+
+/* **************************************************************************
+ *
+ * Function name: tokenized_word_error
+ * Synopsis: Report an error when a word could not be processed
+ * by the tokenizer. Messages will vary...
+ *
+ * Inputs:
+ * Parameters:
+ * stat_name Word that could not be processed
+ * Global Variables:
+ * in_tokz_esc TRUE if tokenizer is in "Tokenizer Escape" mode.
+ *
+ * Outputs:
+ * Returned Value: NONE
+ * Printout: Error message. Possible Advisory about
+ *
+ * Error Detection:
+ * Error was detected by the calling routine...
+ *
+ * Process Explanation:
+ * If the tokenizer is in "Tokenizer Escape" mode, the word might
+ * be one that can be used in normal tokenization mode;
+ * Conversely, if the tokenizer is in normal-tokenization mode,
+ * the word might be one that can be used in the "Escape" mode.
+ * Or, the word is completely unknown.
+ * Recognizing the current mode is handled by word_exists()
+ * However, we need to test for the *converse* of the current mode,
+ * so before we call word_exists() we are going to save and
+ * invert the setting of in_tokz_esc (and afterwards, of
+ * course, restore it...)
+ *
+ **************************************************************************** */
+
+static void tokenized_word_error( char *stat_name)
+{
+ char *where_pt1;
+ char *where_pt2;
+ bool found_somewhere;
+
+ bool sav_in_tokz_esc = in_tokz_esc;
+ in_tokz_esc = INVERSE(sav_in_tokz_esc);
+
+ found_somewhere = word_exists( stat_name, &where_pt1, &where_pt2);
+ if ( found_somewhere )
+ {
+ tokenization_error ( TKERROR, "The word %s is %s recognized "
+ "in tokenizer-escape mode.\n",
+ stat_name, sav_in_tokz_esc ? "not" : "only" );
+ } else {
+ not_in_dict( stat_name);
+ }
+
+ if ( INVERSE(exists_in_ancestor( stat_name)) )
+ {
+ if ( found_somewhere && sav_in_tokz_esc )
+ {
+ tokenization_error(INFO,
+ "%s is defined %s%s", stat_name, where_pt1, where_pt2 );
+ show_node_start();
+ }
+ }
+
+ in_tokz_esc = sav_in_tokz_esc;
+}
+
+
+/* **************************************************************************
+ *
+ * Function name: unresolved_instance
+ * Synopsis: Print the "unresolved instance" message
+ *
+ * Inputs:
+ * Parameters:
+ * severity Severity of the Message
+ * Local Static Variables:
+ * instance_filename File where "instance" invoked
+ * instance_lineno Line number where "instance" invoked
+ *
+ * Outputs:
+ * Returned Value: NONE
+ * Printout: Message.
+ *
+ * Error Detection:
+ * Error was detected by the calling routine...
+ *
+ **************************************************************************** */
+
+static void unresolved_instance( int severity)
+{
+ tokenization_error( severity, "Unresolved \"INSTANCE\"" );
+ just_where_started( instance_filename, instance_lineno );
+}
+
+
+/* **************************************************************************
+ *
+ * Function name: modified_by_instance
+ * Synopsis: Print the "[not] modified by instance" message
+ *
+ * Inputs:
+ * Parameters:
+ * definer Internal token for the defining-word
+ * was_modded FALSE if "not modified..."
+ * Local Static Variables:
+ * instance_filename File where "instance" invoked
+ * instance_lineno Line number where "instance" invoked
+ *
+ * Outputs:
+ * Returned Value: NONE
+ * Printout: WARNING message.
+ *
+ * Error Detection:
+ * Error was detected by the calling routine...
+ *
+ **************************************************************************** */
+
+static void modified_by_instance( fwtoken definer, bool was_modded)
+{
+ char *was_not = was_modded ? "was" : "not" ;
+ char *defn_type_name;
+
+ /* No need to check the return value */
+ definer_name(definer, &defn_type_name);
+
+ tokenization_error ( WARNING,
+ "%s definition %s modified by \"INSTANCE\"",
+ defn_type_name, was_not );
+ just_where_started( instance_filename, instance_lineno );
+ }
+
+/* **************************************************************************
+ *
+ * Function name: validate_instance
+ * Synopsis: If "instance" is in effect, check whether it is
+ * appropriate to the defining-word being called.
+ *
+ * Inputs:
+ * Parameters:
+ * definer Internal token for the defining-word
+ * Local Static Variables:
+ * is_instance TRUE if "instance" is in effect.
+ * instance_definer_gap TRUE if invalid definer(s) invoked
+ * since "instance" went into effect.
+ *
+ * Outputs:
+ * Returned Value: NONE
+ * Local Static Variables:
+ * is_instance Reset to FALSE if definer was valid.
+ * instance_definer_gap TRUE if definer was not valid;
+ * FALSE if definer was valid.
+ *
+ * Error Detection:
+ * If "instance" is in effect, the only defining-words that are
+ * valid are: value variable defer or buffer: Attempts
+ * to use any other defining-word will be reported with a
+ * WARNING, but "instance" will remain in effect.
+ * If an invalid defining-word was invoked since "instance" went
+ * into effect, then, when it is finally applied to a valid
+ * definer, issue a WARNING.
+ *
+ * Process Explanation:
+ * Implicit in the Standard is the notion that, once INSTANCE has
+ * been executed, it remains in effect until a valid defining-
+ * word is encountered. We will do the same.
+ *
+ **************************************************************************** */
+
+static void validate_instance(fwtoken definer)
+{
+ if ( is_instance )
+ {
+ bool is_error = TRUE ;
+
+ switch ( definer)
+ {
+ case VALUE:
+ case VARIABLE:
+ case DEFER:
+ case BUFFER:
+ is_error = FALSE;
+ /* No default needed, likewise, no breaks; */
+ /* but some compilers get upset without 'em... */
+ default:
+ break;
+ }
+
+ if( is_error )
+ {
+ modified_by_instance(definer, FALSE );
+ instance_definer_gap = TRUE;
+ }else{
+ if ( instance_definer_gap )
+ {
+ modified_by_instance(definer, TRUE );
+ }
+ is_instance = FALSE;
+ instance_definer_gap = FALSE;
+ }
+ }
+}
+
+
+/* **************************************************************************
+ *
+ * Function name: trace_creation
+ * Synopsis: If the word being created is on the Trace List,
+ * display the appropriate message
+ *
+ * Inputs:
+ * Parameters:
+ * definer Internal token for the defining-word
+ * nu_name The word being created
+ * Global Variables:
+ * verbose No point in doing all this if we're
+ * not showing the message anyway...
+ * in_tokz_esc TRUE if we are in Tokenizer-Escape mode
+ * scope_is_global TRUE if "global" scope is in effect
+ * current_device_node Current dev-node data-struct
+ *
+ * Outputs:
+ * Returned Value: NONE
+ * Printout:
+ * Advisory Message, if the word is on the Trace List.
+ *
+ * Process Explanation:
+ * The order of scope-checking is important:
+ * A Local has no scope beyond the definition in which it occurs.
+ * Tokenizer-Escape mode supercedes "Normal" mode, and renders
+ * moot the differences between Global and Device scope.
+ * Global scope is mutually exclusive with Device scope.
+ * Device scope needs to identify where the Current device-node
+ * began.
+ *
+ **************************************************************************** */
+
+void trace_creation( fwtoken definer, char *nu_name)
+{
+ if ( verbose )
+ {
+ if ( is_on_trace_list( nu_name) )
+ {
+ char as_what[96] = "";
+ bool show_last_colon = BOOLVAL( definer == LOCAL_VAL);
+
+ as_a_what( definer, as_what); /* No need to check return value. */
+
+ /* Scope-checking starts here, unless show_last_colon is TRUE.
+ * Come out of this with as_what[] filled up and
+ * terminated with a new-line, if appropriate,
+ */
+ while ( ! show_last_colon )
+ {
+ strcat( as_what, " ");
+
+ if ( in_tokz_esc )
+ {
+ strcat( as_what, in_tkz_esc_mode);
+ break;
+ }
+
+ if ( scope_is_global )
+ {
+ strcat( as_what, "with Global scope.\n");
+ }else{
+ /* In Device scope. Show the Current node. */
+ strcat( as_what, in_what_node( current_device_node));
+ }
+ break;
+
+ } /* Destination of BREAKs ... */
+
+ tokenization_error(INFO, "Creating %s %s", nu_name, as_what);
+
+ if ( show_last_colon )
+ {
+ in_last_colon();
+ }else{
+ show_node_start();
+ }
+
+ }
+ }
+}
+
+/* **************************************************************************
+ *
+ * Function name: create_word
+ * Synopsis:
+ *
+ * Inputs:
+ * Parameters:
+ * definer Internal token for the defining-word
+ * Global Variables:
+ * control_stack_depth Number of "Control Stack" entries in effect
+ * nextfcode FCode-number to be assigned to the new name
+ * statbuf Symbol last read from the input stream
+ * pc Input-source Scanning pointer
+ * hdr_flag State of headered-ness for name-creation
+ * force_tokens_case If TRUE, force token-names' case in FCode
+ * force_lower_case_tokens
+ * If force_tokens_case is TRUE, this
+ * determines which case to force
+ * iname Input-source file name; for error-reporting
+ * lineno Input-source Line number; also for err-rep't
+ *
+ * Outputs:
+ * Returned Value: TRUE if successful
+ * Global Variables:
+ * nextfcode Incremented (by bump_fcode() )
+ * statbuf Advanced to next symbol; must be re-read
+ * pc Advanced, then restored to previous value
+ * Memory Allocated
+ * Copy of the name being defined, by support routine.
+ * Copy of input-source file name, for error-reporting
+ * When Freed?
+ * Copy of name being defined is freed when Current Device Vocab
+ * is "finished", or at end of tokenization.
+ * Copy of input-source file name is freed at end of this routine.
+ *
+ * Error Detection:
+ * ERROR if already inside a colon-definition. Discontinue
+ * processing and return FALSE.
+ * ERROR if inside a control-structure. Continue processing,
+ * though, to catch other errors, and even return TRUE;
+ * except: leave the new token undefined.
+ * Warning on duplicate name (subject to command-line control)
+ * Message if name is excessively long; Warning if headerless.
+ * FATAL if the value of nextfcode is larger than the legal
+ * maximum for an FCode, (0x0fff).
+ *
+ * Revision History:
+ * Updated Thu, 24 Mar 2005 by David L. Paktor
+ * Optional warning when name about to be created is a
+ * duplicate of an existing name.
+ * Updated Wed, 30 Mar 2005 by David L. Paktor
+ * Warning when name length exceeds ANSI-specified max (31 chars).
+ * Updated Tue, 05 Apr 2005 by David L. Paktor
+ * Add "definer" parameter and call to add_definer() . Part
+ * of the mechanism to forbid attempts to use the TO
+ * directive to change values of CONSTANTs in particular
+ * and of inappropriate targets in general.
+ * Updated Fri, 06 May 2005 by David L. Paktor
+ * Error-detection of DO ... LOOP and BEGIN ... imbalance
+ * Error-detection of nextfcode exceeding legal maximum (0x0fff).
+ * Updated Wed, 20 Jul 2005 by David L. Paktor
+ * Put Duplicate-Name-Test under command-line control...
+ * Updated Wed, 24 Aug 2005 by David L. Paktor
+ * Error-detection via clear_control_structs() routine.
+ * Updated Tue, 10 Jan 2006 by David L. Paktor
+ * Convert to tic_hdr_t type vocabulary.
+ * Updated Thu, 20 Apr 2006 by David L. Paktor
+ * Allow creation of new definition within body of a flow-control
+ * structure. (Remove error-detection via clear_control_structs)
+ * Updated Tue, 13 Jun 2006 by David L. Paktor
+ * Move detection of out-of-bounds nextfcode to assigning_fcode()
+ * routine, which also detects Overlapping Ranges error.
+ * Updated Thu, 27 Jun 2006 by David L. Paktor
+ * Report Error for attempt to create def'n inside control structure.
+ *
+ * Extraneous Remarks:
+ * We must not set incolon to TRUE (if we are creating a colon
+ * definition) until *AFTER* this routine has been called, due
+ * to the initial error-checking. If we need to detect whether
+ * we are creating a colon definition, we can do so by testing
+ * whether the parameter, DEFINER, equals COLON .
+ *
+ **************************************************************************** */
+
+static bool create_word(fwtoken definer)
+{
+ signed long wlen;
+ bool retval = FALSE;
+ char *defn_type_name;
+
+ /* If already inside a colon, ERROR and discontinueprocessing */
+ /* If an alias to a definer is used, show the name of the alias */
+ if ( test_in_colon(statbuf, FALSE, TKERROR, NULL) )
+ {
+ char defn_type_buffr[32] = "";
+ unsigned int old_lineno = lineno; /* For error message */
+ bool define_token = TRUE;
+
+ { /* Set up definition-type text for error-message */
+
+ /* No need to check the return value */
+ definer_name(definer, &defn_type_name);
+
+ strcat( defn_type_buffr, defn_type_name);
+ strcat( defn_type_buffr, " definition");
+ }
+ /* If in a control-structure, ERROR but continue processing */
+ if ( control_stack_depth != 0 )
+ {
+ announce_control_structs( TKERROR, defn_type_buffr, 0);
+ /* Leave the new token undefined. */
+ define_token = FALSE;
+ }
+
+ /* Get the name of the new token */
+ wlen = get_word();
+
#ifdef DEBUG_SCANNER
printf("%s:%d: debug: defined new word %s, fcode no 0x%x\n",
iname, lineno, name, nextfcode);
#endif
- add_token(nextfcode, name);
- if (flags) {
- if (flags&FLAG_EXTERNAL)
- emit_token("external-token");
- else
- emit_token("named-token");
- emit_string((u8 *)name, wlen);
- } else
- emit_token("new-token");
+ if ( wlen <= 0 )
+ {
+ warn_unterm( TKERROR, defn_type_buffr, old_lineno);
+ }else{
+ bool emit_token_name = TRUE;
+
+ /* Handle Tracing of new definitions */
+ trace_creation( definer, statbuf);
+
+ /* Other Error or Warnings as applicable */
+ validate_instance( definer);
+ warn_if_duplicate( statbuf);
+ check_name_length( wlen);
+
+ /* Bump FCode; error-check as applicable */
+ assigning_fcode();
+
+ /* Define the new token, unless disallowed */
+ add_to_current( statbuf, nextfcode, definer, define_token);
+
+ /* Emit appropriate FCodes: Type of def'n, */
+ switch ( hdr_flag )
+ {
+ case FLAG_HEADERS:
+ emit_token("named-token");
+ break;
+
+ case FLAG_EXTERNAL:
+ emit_token("external-token");
+ break;
+
+ default: /* FLAG_HEADERLESS */
+ emit_token("new-token");
+ emit_token_name = FALSE;
+ }
+
+ /* Emit name of token, if applicable */
+ if ( emit_token_name )
+ {
+ if ( force_tokens_case )
+ {
+ if ( force_lower_case_tokens )
+ {
+ strlwr( statbuf);
+ }else{
+ strupr( statbuf);
+ }
+ }
+ emit_string((u8 *)statbuf, wlen);
+ }
+
+ /* Emit the new token's FCode */
+ emit_fcode(nextfcode);
+
+ /* Prepare FCode Assignment Counter for next definition */
+ bump_fcode();
+
+ /* Declare victory */
+ retval = TRUE;
+ }
+ }
+ return( retval);
+}
+
+
+/* **************************************************************************
+ *
+ * Function name: cannot_apply
+ * Synopsis: Print error message of the form:
+ * "Cannot apply <func> to <targ>, which is a <def'n>"
+ *
+ * Inputs:
+ * Parameters:
+ * func_nam The name of the function
+ * targ_nam The name of the target
+ * defr The numeric-code of the definer-type
+ *
+ * Outputs:
+ * Returned Value: NONE
+ * Printout:
+ * The error message is the entire printout of this routine
+ *
+ * Error Detection:
+ * Error was detected by calling routine
+ *
+ * Process Explanation:
+ * The calling routine already looked up the definer for its
+ * own purposes, so we don't need to do that again here.
+ *
+ * Still to be done:
+ * If the definer-name is not found, we might still look up
+ * the target name in the various vocabularies and use
+ * a phrase for those. E.g., if it is a valid token,
+ * we could say it's defined as a "primitive". (I'm
+ * not sure what we'd say about an FWord...)
+ *
+ **************************************************************************** */
+
+static void cannot_apply( char *func_nam, char *targ_nam, fwtoken defr)
+{
+ char *defr_name = "" ;
+ const char *defr_phrase = ", which is defined as a " ;
+
+ if ( ! definer_name(defr, &defr_name) )
+ {
+ defr_phrase = "";
+ }
+
+ tokenization_error ( TKERROR ,
+ "Cannot apply %s to %s %s%s.\n",
+ func_nam, targ_nam, defr_phrase, defr_name );
+
+}
+
+
+/* **************************************************************************
+ *
+ * Function name: lookup_with_definer
+ * Synopsis: Return pointer to data-structure of named word,
+ * if it's valid in Current context, and supply its
+ * definer. If it's not valid in Current context,
+ * see if it might be a Local, and supply that definer.
+ *
+ * Inputs:
+ * Parameters:
+ * stat_name Name to look up
+ * *definr Pointer to place to put the definer.
+ *
+ * Outputs:
+ * Returned Value: Pointer to data-structure, or
+ * NULL if not in Current context.
+ * Supplied Pointers:
+ * *definr Definer; possibly LOCAL_VAL
+ *
+ * Process Explanation:
+ * If the name is not found in the Current context, and does not
+ * exist as a Local, *definr will remain unchanged.
+ *
+ * Extraneous Remarks:
+ * This is an odd duck^H^H^H^H^H^H^H^H^H^H^H^H a highly-specialized
+ * routine created to meet some corner-case needs engendered by
+ * the conversion to tic_hdr_t vocabularies all around, combined
+ * with an obsessive urge to preserve a high level of detail in
+ * our error-messages.
+ *
+ **************************************************************************** */
+
+static tic_hdr_t *lookup_with_definer( char *stat_name, fwtoken *definr )
+{
+ tic_hdr_t *retval = lookup_current( stat_name);
+ if ( retval != NULL )
+ {
+ *definr = retval->fword_defr;
+ }else{
+ if ( exists_as_local( stat_name) ) *definr = LOCAL_VAL;
+ }
+ return ( retval );
+}
+
+/* **************************************************************************
+ *
+ * Function name: validate_to_target
+ * Synopsis: Print a message if the intended target
+ * of the TO directive is not valid
+ *
+ * Inputs:
+ * Parameters: NONE
+ * Global Variables:
+ * statbuf Next symbol to be read from the input stream
+ * pc Input-source Scanning pointer
+ *
+ * Outputs:
+ * Returned Value: TRUE = Allow b(to) token to be output.
+ * Global Variables:
+ * statbuf Advanced to next symbol; must be re-read
+ * pc Advanced, then restored to previous value
+ *
+ * Error Detection:
+ * If next symbol is not a valid target of TO , issue ERROR
+ * message. Restored pc will cause the next symbol to
+ * be processed by ordinary means.
+ * Allow b(to) token to be output in selected cases. Even if
+ * user has set the "Ignore Errors" flag, certain targets are
+ * still too risky to be allowed to follow a b(to) token;
+ * if "Ignore Errors" is not set, output won't get created
+ * anyway.
+ * Issue ERROR in the extremely unlikely case that "to" is the
+ * last word in the Source.
+ *
+ * Process Explanation:
+ * Valid targets for a TO directive are words defined by:
+ * DEFER, VALUE and arguably VARIABLE. We will also allow
+ * CONSTANT, but will still issue an Error message.
+ * After the check, restore pc ; this was only a look-ahead.
+ * Also restore lineno and abs_token_no
+ *
+ * Extraneous Remarks:
+ * Main part of the mechanism to detect attempts to use the TO
+ * directive to change the values of CONSTANTs in particular
+ * and of inappropriate targets in general.
+ *
+ **************************************************************************** */
+
+static bool validate_to_target( void )
+{
+ signed long wlen;
+ tic_hdr_t *test_entry;
+ u8 *saved_pc = pc;
+ char *cmd_cpy = strupr( strdup( statbuf)); /* For error message */
+ unsigned int saved_lineno = lineno;
+ unsigned int saved_abs_token_no = abs_token_no;
+ fwtoken defr = UNSPECIFIED ;
+ bool targ_err = TRUE ;
+ bool retval = FALSE ;
+
+ wlen = get_word();
+ if ( wlen <= 0 )
+ {
+ warn_unterm( TKERROR, cmd_cpy, saved_lineno);
+ }else{
+
+ test_entry = lookup_with_definer( statbuf, &defr);
+ if ( test_entry != NULL )
+ {
+ switch (defr)
+ {
+ case VARIABLE:
+ tokenization_error( WARNING,
+ "Applying %s to a VARIABLE (%s) is "
+ "not recommended; use ! instead.\n",
+ cmd_cpy, statbuf);
+ case DEFER:
+ case VALUE:
+ targ_err = FALSE ;
+ case CONST:
+ retval = TRUE ;
+ /* No default needed, likewise, no breaks; */
+ /* but some compilers get upset without 'em... */
+ default:
+ break;
+ }
+ }
+
+ if ( targ_err )
+ {
+ cannot_apply(cmd_cpy, strupr(statbuf), defr );
+ }
+
+ pc = saved_pc;
+ lineno = saved_lineno;
+ abs_token_no = saved_abs_token_no;
+ }
+ free( cmd_cpy);
+ return( retval);
+}
+
+
+/* **************************************************************************
+ *
+ * Function name: you_are_here
+ * Synopsis: Display a generic Advisory of the Source command
+ * or directive encountered and being processed
+ *
+ * Inputs:
+ * Parameters: NONE
+ * Global Variables:
+ * statbuf The command being processed
+ *
+ * Outputs:
+ * Returned Value: NONE
+ * Printout:
+ * Advisory message
+ *
+ **************************************************************************** */
+
+static void you_are_here( void)
+{
+ tokenization_error( INFO,
+ "%s encountered; processing...\n",
+ strupr(statbuf) );
+}
+
+
+/* **************************************************************************
+ *
+ * Function name: fcode_starter
+ * Synopsis: Respond to one of the "FCode Starter" words
+ *
+ * Inputs:
+ * Parameters:
+ * token_name The FCode-token for this "Starter" word
+ * spread The separation between tokens.
+ * is_offs16 Whether we are using a 16-bit number
+ * for branch- (and suchlike) -offsets,
+ * or the older-style 8-bit offset numbers.
+ * Global Variables:
+ * iname Input-File name, used to set ifile_name
+ * field of current_device_node
+ * lineno Current Input line number, used to set
+ * line_no field of current_device_node
+ * Local Static Variables:
+ * fcode_started If this is TRUE, we have an Error.
+ * first_fc_starter Control calling reset_fcode_ranges() ;
+ * only on the first fcode_starter of
+ * a tokenization.
+ *
+ * Outputs:
+ * Returned Value: NONE
+ * Global Variables:
+ * offs16 Global "16-bit-offsets" flag
+ * current_device_node The ifile_name and line_no fields will be
+ * loaded with the current input file name
+ * and line number. This node will be the
+ * top-level device-node.
+ * FCode Ranges will be reset the first time per tokenization
+ * that this routine is entered.
+ * A new FCode Range will be started every time after that.
+ * Local Static Variables:
+ * fcode_started Set to TRUE. We invoke the starter only
+ * once per image-block.
+ * first_fc_starter Reset to FALSE if not already
+ * Memory Allocated
+ * Duplicate of Input-File name
+ * When Freed?
+ * In fcode_ender()
+ *
+ * Error Detection:
+ * Spread of other than 1 -- Warning message.
+ * "FCode Starter" previously encountered -- Warning and ignore.
+ *
+ * Question under consideration:
+ * Do we want directives -- such as definitions of constants --
+ * supplied before the "FCode Starter", to be considered as
+ * taking place in "Tokenizer Escape" mode? That would mean
+ * the "Starter" functions must be recognized in "Tokenizer
+ * Escape" mode. Many ramifications to be thought through...
+ * I think I'm coming down strongly on the side of "No". The user
+ * who wants to do that can very well invoke "Tokenizer Escape"
+ * mode explicitly.
+ *
+ **************************************************************************** */
+
+static void fcode_starter( const char *token_name, int spread, bool is_offs16)
+{
+ you_are_here();
+ if ( spread != 1 )
+ {
+ tokenization_error( WARNING, "spread of %d not supported.\n", spread);
+ }
+ if ( fcode_started )
+ {
+ tokenization_error( WARNING,
+ "Only one \"FCode Starter\" permitted per tokenization. "
+ "Ignoring...\n");
+ } else {
+
+ emit_fcodehdr(token_name);
+ offs16 = is_offs16;
+ fcode_started = TRUE;
+
+ current_device_node->ifile_name = strdup(iname);
+ current_device_node->line_no = lineno;
+
+ if ( first_fc_starter )
+ {
+ reset_fcode_ranges();
+ first_fc_starter = FALSE;
+ }else{
+ set_next_fcode( nextfcode);
+ }
+ }
+}
+
+/* **************************************************************************
+ *
+ * Function name: fcode_end_err_check
+ * Synopsis: Do error-checking at end of tokenization,
+ * whether due to FCODE-END or end-of-file,
+ * and reset the indicators we check.
+ *
+ * Inputs:
+ * Parameters: NONE
+ * Global Variables:
+ * Data-Stack depth Is anything left on the stack?
+ *
+ * Outputs:
+ * Returned Value: NONE
+ * Global Variables:
+ * Data-Stack Reset to empty
+ *
+ * Error Detection:
+ * Unresolved control structures detected by clear_control_structs()
+ * If anything is left on the stack, it indicates some incomplete
+ * condition; we will treat it as a Warning.
+ *
+ **************************************************************************** */
+
+static void fcode_end_err_check( void)
+{
+ bool stack_imbal = BOOLVAL( stackdepth() != 0 );
+
+ if ( stack_imbal )
+ {
+ tokenization_error( WARNING,
+ "Stack imbalance before end of tokenization.\n");
+ }
+ clear_stack();
+ clear_control_structs("End of tokenization");
+}
+
+/* **************************************************************************
+ *
+ * Function name: fcode_ender
+ * Synopsis: Respond to one of the "FCode Ender" words:
+ * The FCode-token for "End0" or "End1"
+ * has already been written to the
+ * FCode Output buffer.
+ * Finish the FCode header: fill in its
+ * checksum and length.
+ * Reset the token names defined in "normal" mode
+ * (Does not reset the FCode-token number)
+ *
+ * Associated FORTH words: END0, END1
+ * Associated Tokenizer directive: FCODE-END
+ *
+ * Inputs:
+ * Parameters: NONE
+ * Global Variables:
+ * incolon If TRUE, a colon def'n has not been completed
+ * last_colon_filename For error message.
+ * last_colon_lineno For error message.
+ * scope_is_global For error detection
+ * is_instance For error detection
+ *
+ * Outputs:
+ * Returned Value: NONE
+ * Global Variables:
+ * haveend Set to TRUE
+ * fcode_started Reset to FALSE. Be ready to start anew.
+ * FCode-defined tokens, aliases and macros -- i.e., those
+ * *NOT* defined in tokenizer-escape mode -- are reset.
+ * (Also, command-line-defined symbols are preserved).
+ * Vocabularies will be reset
+ * Device-node data structures will be deleted
+ * Top-level device-node ifile_name and line_no fields
+ * will be reset.
+ * Memory Freed
+ * Duplicate of Input-File name, in top-level device-node.
+ * Printout:
+ * Advisory message giving current value of nextfcode
+ * (the "FCode-token Assignment Counter")
+ *
+ * Error Detection:
+ * ERROR if a Colon definition has not been completed.
+ * ERROR if "instance" is still in effect
+ * WARNING if Global-Scope has not been terminated; compensate.
+ *
+ * Extraneous Remarks:
+ * In order to accommodate odd cases, such as multiple FCode blocks
+ * within a single PCI header, this routine does not automatically
+ * reset nextfcode to h# 0800
+ *
+ **************************************************************************** */
+
+void fcode_ender(void)
+{
+ if ( incolon )
+ {
+ char *tmp_iname = iname;
+ iname = last_colon_filename;
+ unterm_is_colon = TRUE;
+ warn_unterm( TKERROR, "Colon Definition", last_colon_lineno);
+ iname = tmp_iname;
+ }
+
+ haveend = TRUE;
+
+ if ( is_instance )
+ {
+ unresolved_instance( TKERROR);
+ }
+
+ if ( scope_is_global )
+ {
+ tokenization_error( WARNING ,
+ "No DEVICE-DEFINITIONS directive encountered before end. "
+ "Compensating...\n");
+ resume_device_scope();
+ }
+ fcode_end_err_check();
+ reset_normal_vocabs();
+ finish_fcodehdr();
+ fcode_started = FALSE;
+
+ if ( current_device_node->ifile_name != default_top_dev_ifile_name )
+ {
+ free( current_device_node->ifile_name );
+ current_device_node->ifile_name = default_top_dev_ifile_name;
+ current_device_node->line_no = 0;
+ }
+}
+
+/* **************************************************************************
+ *
+ * Function name: get_token
+ * Synopsis: Read the next word in the input stream and retrieve
+ * its FCode-token number. If it's not a symbol to
+ * which a single token is assigned (e.g., if it's
+ * a macro), report an error.
+ *
+ * Associated FORTH words: ['] '
+ * Associated Tokenizer directive: F[']
+ *
+ * Inputs:
+ * Parameters:
+ * *tok_entry Place to put the pointer to token entry
+ * Global Variables:
+ * statbuf The command being processed
+ * pc Input stream character pointer
+ *
+ * Outputs:
+ * Returned Value: TRUE if successful (i.e., no error)
+ * Supplied Pointers:
+ * *tok_entry The token entry, if no error
+ * Global Variables:
+ * statbuf The next word in the input stream
+ * pc Restored to previous value if error
+ *
+ * Error Detection:
+ * The next word in the input stream is expected to be on the
+ * same line as the directive. The get_word_in_line()
+ * routine will check for that.
+ * If the next word in the input stream is not a symbol
+ * for which a single-token FCode number is assigned,
+ * report an ERROR and restore PC to its previous value.
+ *
+ **************************************************************************** */
+
+static bool get_token(tic_hdr_t **tok_entry)
+{
+ bool retval = FALSE;
+ u8 *save_pc;
+
+ /* Copy of command being processed, for error message */
+ char cmnd_cpy[FUNC_CPY_BUF_SIZE+1];
+ strncpy( cmnd_cpy, statbuf, FUNC_CPY_BUF_SIZE);
+ cmnd_cpy[FUNC_CPY_BUF_SIZE] = 0; /* Guarantee null terminator. */
+
+ save_pc = pc;
+
+ if ( get_word_in_line( statbuf) )
+ {
+ fwtoken defr = UNSPECIFIED;
+
+ /* We need to scan the newest definitions first; they
+ * might supercede standard ones. We need, though,
+ * to bypass built-in FWords that need to trigger
+ * some tokenizer internals before emitting their
+ * synonymous FCode Tokens, (e.g., version1 , end0 ,
+ * and start{0-4}); if we find one of those, we will
+ * need to search again, specifically within the list
+ * of FCode Tokens.
+ */
+ *tok_entry = lookup_with_definer( statbuf, &defr);
+ if ( *tok_entry != NULL )
+ {
+ /* Built-in FWords can be uniquely identified by their
+ * definer, BI_FWRD_DEFN . The definer for "shared"
+ * FWords is COMMON_FWORD but there are none of
+ * those that might be synonymous with legitimate
+ * FCode Tokens, nor are any likely ever to be...
+ */
+ if ( defr == BI_FWRD_DEFN )
+ {
+ *tok_entry = lookup_token( statbuf);
+ retval = BOOLVAL( *tok_entry != NULL );
+ }else{
+ retval = entry_is_token( *tok_entry);
+ }
+ }
+
+ if ( INVERSE( retval) )
+ {
+ cannot_apply( cmnd_cpy, strupr(statbuf), defr );
+ pc = save_pc;
+ }
+ }
+
+ return ( retval );
+}
+
+
+static void base_change ( int new_base )
+{
+ if ( incolon && ( INVERSE( in_tokz_esc) ) )
+ {
+ emit_literal(new_base );
+ emit_token("base");
+ emit_token("!");
+ } else {
+ base = new_base;
+ }
+}
+
+static void base_val (int new_base)
+{
+ u8 *old_pc;
+
+ char base_cmnd[FUNC_CPY_BUF_SIZE+1];
+ strncpy( base_cmnd, statbuf, FUNC_CPY_BUF_SIZE);
+ base_cmnd[FUNC_CPY_BUF_SIZE] = 0; /* Guarantee NULL terminator */
+
+ old_pc=pc;
+ if ( get_word_in_line( statbuf) )
+ {
+ u8 basecpy=base;
+
+ base = new_base;
+ if ( ! handle_number() )
+ {
+ /* We did get a word on the line, but it's not a valid number */
+ tokenization_error( WARNING ,
+ "Applying %s to non-numeric value. Ignoring.\n",
+ strupr(base_cmnd) );
+ pc = old_pc;
+ }
+ base=basecpy;
+ }
+}
+
+
+/* **************************************************************************
+ *
+ * Function name: eval_string
+ * Synopsis: Prepare to tokenize a string, artificially generated
+ * by this program or created as a user-defined
+ * Macro. When done, resume at existing source.
+ * Keep the file-name and line-number unchanged.
+ *
+ * Inputs:
+ * Parameters:
+ * inp_bufr String (or buffer) to evaluate
+ *
+ * Outputs:
+ * Returned Value: NONE
+ * Global Variables, changed by call to init_inbuf():
+ * start Points to given string
+ * pc ditto
+ * end Points to end of given string
+ *
+ * Revision History:
+ * Updated Thu, 23 Feb 2006 by David L. Paktor
+ * This routine no longer calls its own instance of tokenize()
+ * It has become the gateway to the mechanism that makes a
+ * smooth transition between the body of the Macro, User-
+ * defined Symbol or internally-generated string and the
+ * resumption of processing the source file.
+ * A similar (but more complicated) transition when processing
+ * an FLOADed file will be handled elsewhere.
+ * Updated Fri, 24 Feb 2006 by David L. Paktor
+ * In order to support Macro-recursion protection, this routine
+ * is no longer the gateway for Macros; they will have to
+ * call push_source() directly.
+ *
+ **************************************************************************** */
+
+void eval_string( char *inp_bufr)
+{
+ push_source( NULL, NULL, FALSE);
+ init_inbuf( inp_bufr, strlen(inp_bufr));
+}
+
+
+/* **************************************************************************
+ *
+ * Function name: finish_or_new_device
+ * Synopsis: Handle the shared logic for the NEW-DEVICE and
+ * FINISH-DEVICE commands.
+ *
+ * Inputs:
+ * Parameters:
+ * finishing_device TRUE for FINISH-DEVICE,
+ * FALSE for NEW-DEVICE
+ * Global Variables:
+ * incolon TRUE if inside a colon definition
+ * noerrors TRUE if ignoring errors
+ * scope_is_global TRUE if "global scope" in effect
+ * Local Static Variables:
+ * is_instance TRUE if "instance" is in effect
+ * dev_change_instance_warning TRUE if warning hasn't been issued
+ *
+ * Outputs:
+ * Returned Value: NONE
+ * Local Static Variables:
+ * dev_change_instance_warning FALSE if warning is issued
+ * instance_definer_gap TRUE if "instance" is in effect
+ *
+ * Error Detection:
+ * NEW-DEVICE and FINISH-DEVICE should not be used outside of
+ * a colon-definition if global-scope is in effect. Error
+ * message; no further action unless we are ignoring errors.
+ * Issue a WARNING if INSTANCE wasn't resolved before the current
+ * device-node is changed. Try not to be too repetitive...
+ *
+ * Process Explanation:
+ * The words NEW-DEVICE and FINISH-DEVICE may be incorporated into
+ * a colon-definition, whether the word is defined in global-
+ * or device- -scope. Such an incorporation does not effect
+ * a change in the device-node vocabulary; simply emit the token.
+ * If we are in interpretation mode, though, we need to check for
+ * errors before changing the device-node vocabulary:
+ * If global-scope is in effect, we need to check whether we are
+ * ignoring errors; if so, we will compensate by switching to
+ * device-scope.
+ * If "instance" is in effect, it's "dangling". It will remain
+ * in effect through a device-node change, but this is very
+ * bad style and deserves a WARNING, but only one for each
+ * occurrence. It would be unaesthetic, to say the least,
+ * to have multiple messages for the same dangling "instance"
+ * in a "finish-device new-device" sequence.
+ * We must be careful about the order we do things, because of
+ * the messages printed as a side-effect of the node change...
+ *
+ * Extraneous Remarks:
+ * I will violate strict structure here.
+ *
+ **************************************************************************** */
+
+static void finish_or_new_device( bool finishing_device )
+{
+ if ( INVERSE( incolon ) )
+ {
+ if ( INVERSE( is_instance) )
+ {
+ /* Arm warning for next time: */
+ dev_change_instance_warning = TRUE;
+ }else{
+ /* Dangling "instance" */
+ instance_definer_gap = TRUE;
+ /* Warn only once. */
+ if ( dev_change_instance_warning )
+ {
+ unresolved_instance( WARNING);
+ dev_change_instance_warning = FALSE;
+ }
+ }
+
+ /* Note: "Instance" cannot be in effect during "global" scope */
+ if ( scope_is_global )
+ {
+ glob_not_allowed( TKERROR, noerrors );
+ if ( noerrors )
+ {
+ resume_device_scope();
+ }else{
+ return;
+ }
+ }
+
+ if ( finishing_device )
+ {
+ finish_device_vocab();
+ }else{
+ new_device_vocab();
+ }
+ }
+ emit_token( finishing_device ? "finish-device" : "new-device" );
+ }
- emit_fcode(nextfcode);
- nextfcode++;
+
+/* **************************************************************************
+ *
+ * Function name: abort_quote
+ * Synopsis: Optionally implement the ABORT" function as
+ * though it were a macro. Control whether to allow
+ * it, and which style to support, via switches set
+ * on the command-line at run-time.
+ *
+ * Inputs:
+ * Parameters:
+ * tok Numeric-code associated with the
+ * FORTH word that was just read.
+ * Global Variables:
+ * enable_abort_quote Whether to allow ABORT"
+ * sun_style_abort_quote SUN-style versus Apple-style
+ * abort_quote_throw Whether to use -2 THROW vs ABORT
+ *
+ * Outputs:
+ * Returned Value: TRUE if it was handled
+ * Global Variables:
+ * report_multiline Reset to FALSE.
+ * Printout:
+ * ADVISORY: ABORT" in fcode is not defined by IEEE 1275-1994
+ *
+ * Error Detection:
+ * Performed by other routines. If user selected not to
+ * allow ABORT" , it will simply be treated as an
+ * unknown word.
+ * The string following it, however, will still be consumed.
+ *
+ * Process Explanation:
+ * If the supplied tok was not ABORTTXT , then return FALSE.
+ * If the enable_abort_quote flag is FALSE, consume the
+ * string following the Abort" token, but be careful to
+ * leave the Abort" token in statbuf, as it will be used
+ * for the error message.
+ * Otherwise, create and prepare for processing the appropriate Macro:
+ * For Apple Style, we push the specified string onto the stack
+ * and do -2 THROW (and hope the stack unwinds correctly).
+ * For Sun Style, we test the condition on top of the stack,
+ * and if it's true, print the specified string before we
+ * do the -2 THROW.
+ * We perform the underlying operations directly: placing an "IF"
+ * (if Sun Style), then placing the string. This bypasses
+ * any issues of double-parsing, as well as of doubly checking
+ * for a multi-line string.
+ * Finally, we perform the operational equivalents of the remainder
+ * of the command sequence.
+ *
+ * Extraneous Remarks:
+ * I would have preferred not to have to directly perform the under-
+ * lying operations, and instead simply prepare the entire command
+ * sequence in a buffer, but I needed to handle the case where
+ * quote-escaped quotes are included in the string: If the string
+ * were simply to be reproduced into the buffer, the quote-escaped
+ * quotes would appear as plain quote-marks and terminate the
+ * string parsing prematurely, leaving the rest of the string
+ * to be treated as code instead of text...
+ * Also, the introduction of the variability of whether to do the
+ * -2 THROW or to compile-in the token for ABORT makes the
+ * buffer-interpretation scheme somewhat too messy for my tastes.
+ *
+ **************************************************************************** */
+
+static bool abort_quote( fwtoken tok)
+{
+ bool retval = FALSE;
+ if ( tok == ABORTTXT )
+ {
+ if ( ! enable_abort_quote )
+ {
+ /* ABORT" is not enabled; we'd better consume the string */
+ char *save_statbuf;
+ signed long wlen;
+ save_statbuf = strdup( (char *)statbuf);
+ wlen = get_string( FALSE);
+ strcpy( statbuf, save_statbuf);
+ free( save_statbuf);
+ }else{
+ /* ABORT" is not to be used in FCODE drivers
+ * but Apple drivers do use it. Therefore we
+ * allow it. We push the specified string to
+ * the stack, do -2 THROW and hope that THROW
+ * will correctly unwind the stack.
+ * Presumably, Apple Source supplies its own
+ * IF ... THEN
+ */
+ char *abort_string;
+ signed long wlen;
- return 0;
+ retval = TRUE;
+ tokenization_error (INFO, "ABORT\" in fcode not "
+ "defined by IEEE 1275-1994\n");
+ test_in_colon("ABORT\"", TRUE, TKERROR, NULL);
+ wlen=get_string( TRUE);
+
+ if ( sun_style_abort_quote ) emit_if();
+
+ emit_token("b(\")");
+ emit_string(statbuf, wlen);
+
+ if ( sun_style_abort_quote ) emit_token("type");
+
+ if ( abort_quote_throw )
+ {
+ emit_literal( -2);
+ emit_token("throw");
+ }else{
+ emit_token("abort");
+ }
+
+ if ( sun_style_abort_quote ) emit_then();
+ /* Sun Style */
+ abort_string = " type -2 THROW THEN:" ;
}
+ }
+ return( retval );
+}
-static void encode_file( const char *filename )
+
+/* **************************************************************************
+ *
+ * Function name: create_alias
+ * Synopsis: Create an alias, as specified by the user
+ *
+ * Associated FORTH word: ALIAS
+ *
+ * Inputs:
+ * Parameters: NONE
+ * Global Variables:
+ * incolon Colon-def'n-in-progress indicator
+ * in_tokz_esc "Tokenizer Escape" mode indicator
+ * Input Stream
+ * Two words will be read.
+ *
+ * Outputs:
+ * Returned Value: TRUE if succeeded.
+ * Global Variables:
+ * statbuf New name will be copied back into here.
+ * Memory Allocated
+ * The two words will be copied into freshly-allocated memory
+ * that will be passed to the create_..._alias() routine.
+ * When Freed?
+ * When Current Device Vocabulary is "finished", or at end
+ * of tokenization, or upon termination of program.
+ * If not able to create alias, the copies will be freed here.
+ *
+ * Error Detection:
+ * If the ALIAS command was given during colon-definition, that
+ * can be handled by this tokenizer, but it is not supported
+ * by IEEE 1275-1994. Issue a WARNING.
+ * If the new name is a copy of an existing word-name, issue a warning.
+ * If the word to which an alias is to be created does not exist
+ * in the appropriate mode -- relative to "Tokenizer-Escape" --
+ * that is an ERROR.
+ * If "instance" is in effect, the ALIAS command is an ERROR.
+ *
+ * Process Explanation:
+ * Get two words -- the new name and the "old" word -- from the
+ * same line of input as the ALIAS command.
+ * Copy the new name back into statbuf for use in trace_creation.
+ * Determine whether or not we are in "Tokenizer-Escape" mode.
+ * Subsequent searches will take place in that same mode.
+ * If the "new" name already exists, issue a warning.
+ * In each vocabulary applicable to the current mode -- i.e.,
+ * "Tokenizer-Escape" or "Normal" -- (except: cannot
+ * make aliases to "Locals"):
+ * Try using the create_..._alias() routine.
+ * If it succeeds, we are done.
+ * IMPORTANT: The order in which we try the vocabularies MUST
+ * match the order in which tokenize_one_word() searches them.
+ * If all the attempts failed, the "old" word does not exist;
+ * declare an ERROR and free up the memory that was allocated.
+ *
+ * Extraneous Remarks:
+ * With the separation of the tokenizer[ state, this
+ * function has become too complicated to keep as a
+ * simple CASE in the big SWITCH statement anymore...
+ *
+ * I had earlier thought that it was sufficient to create a
+ * macro linking the "new" name to the "old" word. There
+ * were too many cases, though, where that didn't work.
+ * This is cleaner.
+ *
+ * I will not be adhering to the strict rules of structure in
+ * this routine, as it would get me nested too deeply...
+ *
+ * Revision History:
+ * Updated Tue, 10 Jan 2006 by David L. Paktor
+ * Convert to tic_hdr_t type vocabularies.
+ *
+ **************************************************************************** */
+
+static bool create_alias( void )
{
- FILE *f;
- size_t s;
- int i=0;
+ char *new_alias ;
+
+ validate_instance(ALIAS);
+ if ( incolon )
+ {
+ tokenization_error ( WARNING,
+ "ALIAS during colon-definition "
+ "is not supported by IEEE 1275-1994\n");
+}
+ if ( get_word_in_line( "ALIAS") )
+ {
+
+ new_alias = strdup((char *)statbuf);
+
+ if (get_word_in_line( "ALIAS") )
+{
+ char *old_name = strdup((char *)statbuf) ;
+
+ /* Copy the "new" alias name back into statbuf.
+ * This is a HACK ^H^H^H^H awkward way to retrofit
+ * support for the trace_creation() function.
+ */
+ strcpy( statbuf, new_alias);
+
+ /* We don't call trace_creation() here because we don't
+ * know if the creation succeeded. However, we want
+ * to issue a "Duplicate" warning based on the attempt,
+ * even if it doesn't succeed.
+ * We would prefer to have the "Trace" message precede the
+ * "Duplicate" warning, but we don't think it's worth
+ * the effort. When it becomes worthwhile, the way to
+ * do it would be to factor out the block that handles
+ * normal-tokenization versus "Tokenizer-Escape" mode;
+ * condition the "Trace" message on its success-return,
+ * show the "Duplicate" warning in any case, then show
+ * the error-message and do the cleanup conditioned on
+ * a failure-return.
+ * That will also obviate the need for a return value from
+ * this routine and for the copy-back into statbuf.
+ */
+ warn_if_duplicate(new_alias);
+
+ /*
+ * Here is where we begin trying the create_..._alias()
+ * routines for the vocabularies.
+ */
+
+ /*
+ * Distinguish between "Normal" tokenization mode
+ * and "Tokenizer Escape" mode
+ */
+ if ( in_tokz_esc )
+ {
+ if ( create_tokz_esc_alias( new_alias, old_name) )
+ return(TRUE);
- if( !(f=fopen(filename,"rb")) ) {
- printf("%s:%d: opening '%s':\n", iname, lineno, filename );
- ERROR;
- return;
+ /*
+ * Handle the classes of operatives that are common between
+ * "Tokenizer Escape" mode and "Normal" tokenization mode.
+ * Those classes include selected non-fcode forth constructs
+ * and Conditional-Compilation Operators.
+ */
+ {
+ tic_hdr_t *found = lookup_shared_word( old_name);
+ if ( found != NULL )
+ {
+ if ( create_core_alias( new_alias, old_name) )
+ return(TRUE);
+ }
}
- while( (s=fread(statbuf, 1, 255, f)) ) {
- emit_token("b(\")");
- emit_string(statbuf, s);
- emit_token("encode-bytes");
- if( i++ )
- emit_token("encode+");
+ }else{
+ /* "Normal" tokenization mode */
+
+ /* Can create aliases for "Locals", why not? */
+ if ( create_local_alias( new_alias, old_name) )
+ return(TRUE);
+
+ /*
+ * All other classes of operatives -- non-fcode forth
+ * constructs, Standard and user-defined fcode
+ * tokens, Macros, and Conditional-Compilation
+ * Operators, -- are included in the "currently
+ * active" vocabulary.
+ */
+
+ if ( create_current_alias( new_alias, old_name) )
+ return(TRUE);
+
+ } /* End of separate handling for normal-tokenization mode
+ * versus "Tokenizer-Escape" mode
+ */
+
+ /* It's not a word, a macro or any of that other stuff. */
+ tokenized_word_error(old_name);
+ free(old_name);
}
- fclose( f );
+ free (new_alias);
+ }
+ return(FALSE);
}
+
+/* **************************************************************************
+ *
+ * Function name: string_err_check
+ * Synopsis: Error-check after processing or Ignoring
+ * simple strings
+ *
+ * Inputs:
+ * Parameters:
+ * is_paren TRUE if string is Dot-Paren .(
+ * FALSE if Ess-Quote ( s" )
+ * sav_lineno Saved Line Number, for Unterminated Error
+ * strt_lineno Start Line Number, for Multiline Warning
+ * Global Variables:
+ * noerrors TRUE if ignoring errors
+ * Local Static Variables:
+ * got_until_eof TRUE if reached end of buffer before delim.
+ *
+ * Outputs:
+ * Returned Value: TRUE if did not reach end of buffer, or,
+ * if ignoring errors, TRUE anyway.
+ *
+ * Error Detection:
+ * Multi-line warning, "Unterminated" Error messages, as apppropriate
+ *
+ **************************************************************************** */
-static void handle_internal(u16 tok)
+static bool string_err_check( bool is_paren,
+ unsigned int sav_lineno,
+ unsigned int strt_lineno )
{
- unsigned long wlen;
- long offs1,offs2;
- u16 itok;
+ bool retval = noerrors ;
+ char *item_typ = is_paren ?
+ "Dot-Paren" : "Ess-Quote" ;
+ if ( got_until_eof ) /* Crude retrofit... */
+ {
+ warn_unterm( TKERROR, item_typ, sav_lineno );
+ }else{
+ retval = TRUE;
+ warn_if_multiline( item_typ, strt_lineno );
+ }
+ return( retval);
+}
+
+
+/* **************************************************************************
+ *
+ * Function name: handle_internal
+ * Synopsis: Perform the functions associated with FORTH words
+ * that do not map directly to a single token. This
+ * is the functions that will go into the FUNCT field
+ * of entries in the "FWords" and "Shared Words" lists.
+ *
+ * Inputs:
+ * Parameters:
+ * pfield Param-field of the tic_hdr_t -type entry
+ * associated with the FORTH-Word (FWord)
+ * just read that is being "handled".
+ * Global Variables:
+ * statbuf The word that was just read.
+ *
+ * Outputs:
+ * Returned Value: NONE
+ * Global Variables:
+ * statbuf More words may be read.
+ *
+ * Error Detection:
+ * Too numerous to list here...
+ *
+ * Process Explanation:
+ * Recast the type of the param-field of a tic_hdr_t -type
+ * entry and rename it "tok".
+ * The "tok" will be used as the control-expression for a
+ * SWITCH statement with a large number of CASE labels.
+ * Both "FWords" and "shared_words" list entries will
+ * be processed by this routine.
+ *
+ * Revision History:
+ * Updated Wed, 20 Jul 2005 by David L. Paktor
+ * Put handling of ABORT" under control of a run-time
+ * command-line switch.
+ * Put decision to support IBM-style Locals under control
+ * of a run-time command-line switch.
+ * Updated Tue, 17 Jan 2006 by David L. Paktor
+ * Convert to handler for tic_hdr_t type vocab entries.
+ *
+ * Extraneous Remarks:
+ * We would prefer to keep this function private, so we will
+ * declare its prototype here and in the one other file
+ * where we need it, namely, dictionary.c, rather than
+ * exporting it widely in a .h file.
+ *
+ **************************************************************************** */
+
+void handle_internal( tic_param_t pfield);
+void handle_internal( tic_param_t pfield)
+{
+ fwtoken tok = pfield.fw_token;
+
+ signed long wlen;
+ unsigned int sav_lineno = lineno; /* For error message */
+
+ bool handy_toggle = TRUE ; /* Various uses... */
#ifdef DEBUG_SCANNER
printf("%s:%d: debug: tokenizing control word '%s'\n",
@@ -443,727 +4450,1087 @@
#endif
switch (tok) {
case BEGIN:
- emit_token("b(<mark)");
- dpush((unsigned long)opc);
+ emit_begin();
break;
case BUFFER:
- create_word();
+ if ( create_word(tok) )
+ {
emit_token("b(buffer:)");
+ }
break;
case CONST:
- create_word();
+ if ( create_word(tok) )
+ {
emit_token("b(constant)");
+ }
break;
case COLON:
- create_word();
+ {
+ /* Collect error- -detection or -reporting items,
+ * but don't commit until we're sure the
+ * creation was a success.
+ */
+ u16 maybe_last_colon_fcode = nextfcode ;
+ unsigned int maybe_last_colon_lineno = lineno;
+ unsigned int maybe_last_colon_abs_token_no = abs_token_no;
+ unsigned int maybe_last_colon_do_depth = do_loop_depth;
+ /* last_colon_defname
+ * has to wait until after call to create_word()
+ */
+
+ if ( create_word(tok) )
+ {
+ last_colon_fcode = maybe_last_colon_fcode;
+ last_colon_lineno = maybe_last_colon_lineno;
+ last_colon_abs_token_no = maybe_last_colon_abs_token_no;
+ last_colon_do_depth = maybe_last_colon_do_depth;
+ collect_input_filename( &last_colon_filename);
+ /* Now we can get last_colon_defname */
+ if ( last_colon_defname != NULL )
+ {
+ free( last_colon_defname);
+ }
+ last_colon_defname = strdup(statbuf);
+
emit_token("b(:)");
incolon=TRUE;
+ hide_last_colon();
+ lastcolon = opc;
+ }
+ }
break;
case SEMICOLON:
+ if ( test_in_colon("SEMICOLON", TRUE, TKERROR, NULL) )
+ {
+ ret_stk_balance_rpt( "termination,", TRUE);
+ /* Clear Control Structures just back to where
+ * the current Colon-definition began.
+ */
+ clear_control_structs_to_limit(
+ "End of colon-definition", last_colon_abs_token_no);
+
+ if ( ibm_locals )
+ {
+ finish_locals();
+ forget_locals();
+ }
+
emit_token("b(;)");
incolon=FALSE;
+ reveal_last_colon();
+ }
break;
case CREATE:
- create_word();
+ if ( create_word(tok) )
+ {
emit_token("b(create)");
+ }
break;
case DEFER:
- create_word();
+ if ( create_word(tok) )
+ {
emit_token("b(defer)");
+ }
break;
+ case ALLOW_MULTI_LINE:
+ report_multiline = FALSE;
+ break;
+
+ case OVERLOAD:
+ if ( test_in_colon(statbuf, FALSE, WARNING, NULL) )
+ {
+ do_not_overload = FALSE;
+ }
+ break;
+
+ case DEFINED:
+ if (get_word_in_line( statbuf) )
+ {
+ eval_user_symbol(statbuf);
+ }
+ break;
+
+ case CL_FLAG:
+ if (get_word_in_line( statbuf) )
+ {
+ set_cl_flag( statbuf, TRUE);
+ }
+ break;
+
+ case SHOW_CL_FLAGS:
+ show_all_cl_flag_settings( TRUE);
+ break;
+
case FIELD:
- create_word();
+ if ( create_word(tok) )
+ {
emit_token("b(field)");
+ }
break;
case VALUE:
- create_word();
+ if ( create_word(tok) )
+ {
emit_token("b(value)");
+ }
break;
case VARIABLE:
- create_word();
+ if ( create_word(tok) )
+ {
emit_token("b(variable)");
+ }
break;
- case EXTERNAL:
- flags=FLAG_EXTERNAL;
- break;
-
- case TOKENIZE:
- emit_token("b(')");
- break;
-
case AGAIN:
- emit_token("bbranch");
- offs1=dpop()-(unsigned long)opc;
- emit_offset(offs1);
+ emit_again();
break;
case ALIAS:
- wlen=get_word();
- name=strdup((char *)statbuf);
- wlen=get_word();
- alias=strdup((char *)statbuf);
- if(lookup_macro(name))
- printf("%s:%d: warning: duplicate alias\n",
- iname, lineno);
- add_macro(name,alias);
+ if ( create_alias() )
+ {
+ trace_creation( ALIAS, statbuf);
+ }
break;
case CONTROL:
- wlen=get_word();
- emit_token("b(lit)");
- emit_num32(statbuf[0]&0x1f);
+ if ( get_word_in_line( statbuf) )
+ {
+ emit_literal(statbuf[0]&0x1f);
+ }
break;
case DO:
emit_token("b(do)");
- dpush((unsigned long)opc);
- emit_offset(0);
- dpush((unsigned long)opc);
+ mark_do();
break;
case CDO:
emit_token("b(?do)");
- dpush((unsigned long)opc);
- emit_offset(0);
- dpush((unsigned long)opc);
+ mark_do();
break;
case ELSE:
- offs2=dpop();
- emit_token("bbranch");
- dpush((unsigned long)opc);
- emit_offset(0);
- emit_token("b(>resolve)");
- offs1=(unsigned long)opc;
- opc=(u8 *)offs2;
- offs2=offs1-(unsigned long)opc;
- emit_offset(offs2);
- opc=(u8 *)offs1;
+ emit_else();
break;
case CASE:
- emit_token("b(case)");
- dpush(0);
+ emit_case();
break;
case ENDCASE:
- /* first emit endcase, then calculate offsets. */
- emit_token("b(endcase)");
-
- offs1=(unsigned long)opc;
-
- offs2=dpop();
- while (offs2) {
- u16 tmp;
-
- opc=(u8 *)(ostart+offs2);
+ emit_endcase();
+ break;
- /* we're using an fcode offset to temporarily
- * store our linked list. At this point we take
- * the signed fcode offset as unsigned as we know
- * that the offset will always be >0. This code
- * is still broken for any case statement that
- * occurs after the fcode bytecode grows larger
- * than 64kB
- */
- tmp=receive_offset();
+ case NEW_DEVICE:
+ handy_toggle = FALSE;
+ case FINISH_DEVICE:
+ finish_or_new_device( handy_toggle );
+ break;
- offs2=(unsigned long)offs1-(unsigned long)opc;
-
-#if defined(DEBUG_SCANNER)
- printf ("%s:%d: debug: endcase offset 0x%lx\n",
- iname,lineno, (unsigned long)offs2);
-#endif
- emit_offset(offs2);
- offs2=tmp;
+ case FLITERAL:
+ {
+ u32 val;
+ val = dpop();
+ emit_literal(val);
}
- opc=(u8 *)offs1;
break;
case OF:
- emit_token("b(of)");
- dpush((unsigned long)(opc-ostart));
- emit_offset(0);
+ emit_of();
break;
case ENDOF:
- offs1=dpop();
- emit_token("b(endof)");
+ emit_endof();
+ break;
- offs2=dpop();
- dpush((unsigned long)(opc-ostart));
- emit_offset(offs2);
-
- offs2=(unsigned long)(opc-ostart);
- opc=(u8 *)(ostart+offs1);
- offs1=offs2-offs1;
- emit_offset(offs1);
-
- opc=(u8 *)(ostart+offs2);
+ case EXTERNAL:
+ set_hdr_flag( FLAG_EXTERNAL );
break;
case HEADERLESS:
- flags=0;
+ set_hdr_flag( FLAG_HEADERLESS );
break;
case HEADERS:
- flags=FLAG_HEADERS;
+ set_hdr_flag( FLAG_HEADERS );
break;
case DECIMAL:
/* in a definition this is expanded as macro "10 base !" */
- if (incolon) {
- emit_token("b(lit)");
- emit_num32(0x0a);
- emit_token("base");
- emit_token("!");
- } else
- base=10;
+ base_change ( 0x0a );
break;
case HEX:
- if (incolon) {
- emit_token("b(lit)");
- emit_num32(0x10);
- emit_token("base");
- emit_token("!");
- } else
- base=16;
+ base_change ( 0x10 );
break;
case OCTAL:
- if (incolon) {
- emit_token("b(lit)");
- emit_num32(0x08);
- emit_token("base");
- emit_token("!");
- } else
- base=8;
+ base_change ( 0x08 );
break;
case OFFSET16:
if (!offs16)
- printf("%s:%d: switching to "
- "16bit offsets.\n", iname, lineno);
+ {
+ tokenization_error(INFO, "Switching to 16-bit offsets.\n");
+ }else{
+ tokenization_error(WARNING,
+ "Call of OFFSET16 is redundant.\n");
+ }
emit_token("offset16");
offs16=TRUE;
break;
case IF:
- emit_token("b?branch");
- dpush((unsigned long)opc);
- emit_offset(0);
+ emit_if();
break;
- case CLEAVE:
+/* **************************************************************************
+ *
+ * Still to be done:
+ * Correct analysis of Return-Stack usage within Do-Loops
+ * or before Loop Elements like I and J or UNLOOP or LEAVE.
+ *
+ **************************************************************************** */
+ case UNLOOP:
+ emit_token("unloop");
+ must_be_deep_in_do(1);
+ break;
+
case LEAVE:
emit_token("b(leave)");
+ must_be_deep_in_do(1);
break;
+
+ case LOOP_I:
+ emit_token("i");
+ must_be_deep_in_do(1);
+ break;
+
+ case LOOP_J:
+ emit_token("j");
+ must_be_deep_in_do(2);
+ break;
case LOOP:
emit_token("b(loop)");
- offs1=dpop();
- offs2=offs1-(unsigned long)opc;
- emit_offset(offs2);
- offs1=(unsigned long)opc;
- opc=(u8 *)dpop();
- offs2=offs1-(unsigned long)opc;
- emit_offset(offs2);
- opc=(u8 *)offs1;
+ resolve_loop();
break;
- case CLOOP:
+ case PLUS_LOOP:
emit_token("b(+loop)");
- offs1=dpop();
- offs2=offs1-(unsigned long)opc;
- emit_offset(offs2);
- offs1=(unsigned long)opc;
- opc=(u8 *)dpop();
- offs2=offs1-(unsigned long)opc;
- emit_offset(offs2);
- opc=(u8 *)offs1;
+ resolve_loop();
break;
- case GETTOKEN:
- emit_token("b(')");
- wlen=get_word();
- itok=lookup_token((char *)statbuf);
- if (itok==0xffff) {
- printf("%s:%d: error: no such word '%s' in [']\n",
- iname, lineno, statbuf);
- ERROR;
+
+ case INSTANCE:
+ {
+ bool set_instance_state = FALSE;
+ bool emit_instance = TRUE;
+ /* We will treat "instance" in a colon-definition as
+ * an error, but allow it to be emitted if we're
+ * ignoring errors; if we're not ignoring errors,
+ * there's no output anyway...
+ */
+ if ( test_in_colon(statbuf, FALSE, TKERROR, NULL) )
+ { /* We are in interpretation (not colon) state. */
+ /* "Instance" not allowed during "global" scope */
+ if ( scope_is_global )
+ {
+ glob_not_allowed( WARNING, FALSE );
+ emit_instance = FALSE;
+ }else{
+ set_instance_state = TRUE;
+ }
+ }
+ if ( emit_instance )
+ {
+ if ( set_instance_state )
+ {
+ /* "Instance" isn't cumulative.... */
+ if ( is_instance )
+ {
+ unresolved_instance( WARNING);
+ }
+ collect_input_filename( &instance_filename);
+ instance_lineno = lineno;
+ is_instance = TRUE;
+ dev_change_instance_warning = TRUE;
+ }
+ emit_token("instance");
+ }
}
- /* FIXME check size, u16 or token */
- emit_fcode(itok);
break;
- case ASCII:
- wlen=get_word();
- emit_token("b(lit)");
- emit_num32(statbuf[0]);
+ case GLOB_SCOPE:
+ if ( test_in_colon(statbuf, FALSE, TKERROR, NULL) )
+ {
+ if ( INVERSE( is_instance) )
+ {
+ enter_global_scope();
+ }else{
+ tokenization_error( TKERROR,
+ "Global Scope not allowed. "
+ "\"Instance\" is in effect; issued" );
+ just_where_started( instance_filename,
+ instance_lineno );
+ }
+ }
break;
- case CHAR:
- if (incolon)
- printf("%s:%d: warning: CHAR cannot be used inside "
- "of a colon definition.\n", iname, lineno);
- wlen=get_word();
- emit_token("b(lit)");
- emit_num32(statbuf[0]);
+ case DEV_SCOPE:
+ if ( test_in_colon(statbuf, FALSE, TKERROR, NULL) )
+ {
+ resume_device_scope();
+ }
break;
+ case TICK: /* ' */
+ test_in_colon(statbuf, FALSE, WARNING, "[']");
+ case BRACK_TICK: /* ['] */
+ {
+ tic_hdr_t *token_entry;
+ if ( get_token( &token_entry) )
+ {
+ emit_token("b(')");
+ /* Emit the token; warning or whatever comes gratis */
+ token_entry->funct( token_entry->pfield);
+ }
+ }
+ break;
+
+ case F_BRACK_TICK: /* F['] <name>
+ * emits the token-number for <name>
+ * Mainly useful to compute the argument
+ * to get-token or set-token
+ */
+ {
+ tic_hdr_t *token_entry;
+ if ( get_token( &token_entry) )
+ {
+ /* "Obsolete" warning doesn't come gratis here... */
+ token_entry_warning( token_entry);
+ /* In Tokenizer-Escape mode, push the token */
+ if ( in_tokz_esc )
+ {
+ dpush( token_entry->pfield.deflt_elem);
+ }else{
+ emit_literal( token_entry->pfield.deflt_elem);
+ }
+ }
+ }
+ break;
+
+ case CHAR:
+ handy_toggle = FALSE;
case CCHAR:
- wlen=get_word();
- emit_token("b(lit)");
- emit_num32(statbuf[0]);
+ test_in_colon(statbuf, handy_toggle, WARNING,
+ handy_toggle ? "CHAR" : "[CHAR]" );
+ case ASCII:
+ if ( get_word_in_line( statbuf) )
+ {
+ emit_literal(statbuf[0]);
+ }
break;
case UNTIL:
- emit_token("b?branch");
- emit_offset(dpop()-(unsigned long)opc);
+ emit_until();
break;
case WHILE:
- emit_token("b?branch");
- dpush((unsigned long)opc);
- emit_offset(0);
+ emit_while();
break;
case REPEAT:
- emit_token("bbranch");
- offs2=dpop();
- offs1=dpop();
- offs1-=(unsigned long)opc;
- emit_offset(offs1);
-
- emit_token("b(>resolve)");
- offs1=(unsigned long)opc;
- opc=(u8 *)offs2;
- emit_offset(offs1-offs2);
- opc=(u8 *)offs1;
+ emit_repeat();
break;
case THEN:
- emit_token("b(>resolve)");
- offs1=(unsigned long)opc;
- opc=(u8 *)dpop();
- offs2=offs1-(unsigned long)opc;
- emit_offset(offs2);
- opc=(u8 *)offs1;
+ emit_then();
break;
+ case IS:
+ tokenization_error ( INFO,
+ "Substituting TO for deprecated IS\n");
case TO:
+ if ( validate_to_target() )
+ {
emit_token("b(to)");
+ }
break;
case FLOAD:
+ if ( get_word_in_line( statbuf) )
{
- u8 *oldstart, *oldpc, *oldend;
- char *oldiname;
- int oldlineno;
-
- wlen=get_word();
+ bool stream_ok ;
- oldstart=start; oldpc=pc; oldend=end;
- oldiname=iname; oldlineno=lineno;
+ push_source( close_stream, NULL, TRUE) ;
- init_stream((char *)statbuf);
- tokenize();
- close_stream();
+ tokenization_error( INFO, "FLOADing %s\n", statbuf );
- iname=oldiname; lineno=oldlineno;
- end=oldend; pc=oldpc; start=oldstart;
+ stream_ok = init_stream( statbuf );
+ if ( INVERSE( stream_ok) )
+ {
+ drop_source();
+ }
}
break;
- case STRING:
- if (*pc++=='\n') lineno++;
- wlen=get_string();
+ case STRING: /* Double-Quote ( " ) string */
+ handy_toggle = FALSE;
+ case PSTRING: /* Dot-Quote ( ." ) string */
+ wlen=get_string( TRUE);
emit_token("b(\")");
- emit_string(statbuf,wlen-1);
+ emit_string(statbuf, wlen);
+ if ( handy_toggle )
+ {
+ emit_token("type");
+ }
break;
- case PSTRING:
+ case SSTRING: /* Ess-Quote ( s" ) string */
+ handy_toggle = FALSE;
+ case PBSTRING: /* Dot-Paren .( string */
if (*pc++=='\n') lineno++;
- wlen=get_string();
+ {
+ unsigned int strt_lineno = lineno;
+ wlen = get_until( handy_toggle ? ')' : '"' );
+ if ( string_err_check( handy_toggle,
+ sav_lineno, strt_lineno) )
+ {
emit_token("b(\")");
- emit_string(statbuf,wlen-1);
+ emit_string(statbuf, wlen);
+ if ( handy_toggle )
+ {
emit_token("type");
+ }
+ }
+ }
break;
- case PBSTRING:
- if (*pc++=='\n') lineno++;
- get_until(')');
+ case FUNC_NAME:
+ if ( test_in_colon( statbuf, TRUE, TKERROR, NULL) )
+ {
+ if ( in_tokz_esc )
+ {
+ tokenization_error( P_MESSAGE, "Currently" );
+ in_last_colon();
+ }else{
emit_token("b(\")");
- emit_string(statbuf,strlen((char *)statbuf)-1);
- emit_token("type");
+ emit_string( last_colon_defname,
+ strlen( last_colon_defname) );
+ /* if ( hdr_flag == FLAG_HEADERLESS ) { WARNING } */
+ }
+ }
break;
- case SSTRING:
- if (*pc++=='\n') lineno++;
- get_until('"');
+ case IFILE_NAME:
emit_token("b(\")");
- emit_string(statbuf,strlen((char *)statbuf)-1);
- pc++; /* skip " */
+ emit_string( iname, strlen( iname) );
break;
+ case ILINE_NUM:
+ emit_literal( lineno);
+ break;
+
case HEXVAL:
- {
- u8 basecpy=base;
- long val;
-
- base=0x10;
- wlen=get_word();
- if (!get_number(&val)) {
- emit_token("b(lit)");
- emit_num32(val);
- } else {
- printf("%s:%d: warning: illegal value in h#"
- " ignored\n", iname, lineno);
- }
- base=basecpy;
- }
+ base_val (0x10);
break;
case DECVAL:
- {
- u8 basecpy=base;
- long val;
-
- base=0x0a;
- wlen=get_word();
- if (!get_number(&val)) {
- emit_token("b(lit)");
- emit_num32(val);
- } else {
- printf("%s:%d: warning: illegal value in d#"
- " ignored\n", iname, lineno);
- }
-
- base=basecpy;
- }
+ base_val (0x0a);
break;
case OCTVAL:
+ base_val (8);
+ break;
+
+ case ASC_LEFT_NUM:
+ handy_toggle = FALSE;
+ case ASC_NUM:
+ if (get_word_in_line( statbuf) )
{
- u8 basecpy=base;
- long val;
-
- base=0x08;
- wlen=get_word();
- if (!get_number(&val)) {
- emit_token("b(lit)");
- emit_num32(val);
+ if ( handy_toggle )
+ {
+ ascii_right_number( statbuf);
} else {
- printf("%s:%d: warning: illegal value in o#"
- " ignored\n", iname, lineno);
+ ascii_left_number( statbuf);
}
-
- base=basecpy;
}
break;
- case BEGINTOK:
- intok=TRUE;
+
+ case CONDL_ENDER: /* Conditional directives out of context */
+ case CONDL_ELSE:
+ tokenization_error ( TKERROR,
+ "No conditional preceding %s directive\n",
+ strupr(statbuf) );
break;
- case EMITBYTE:
- if (intok)
- emit_byte(dpop());
- else
- printf ("%s:%d: warning: emit-byte outside tokenizer"
- " scope\n", iname, lineno);
+ case PUSH_FCODE:
+ tokenization_error( INFO,
+ "FCode-token Assignment Counter of 0x%x "
+ "has been saved on stack.\n", nextfcode );
+ dpush( (long)nextfcode );
break;
- case NEXTFCODE:
- if (intok)
- nextfcode=dpop();
- else
- printf("%s:%d: warning: next-fcode outside tokenizer"
- " scope\n", iname, lineno);
+ case POP_FCODE:
+ pop_next_fcode();
break;
+
+ case RESET_FCODE:
+ tokenization_error( INFO,
+ "Encountered %s. Resetting FCode-token "
+ "Assignment Counter. ", strupr(statbuf) );
+ list_fcode_ranges( FALSE);
+ reset_fcode_ranges();
+ break;
- case ENDTOK:
- intok=FALSE;
+ case EXIT:
+ if ( test_in_colon( statbuf, TRUE, TKERROR, NULL)
+ || noerrors )
+ {
+ ret_stk_balance_rpt( NULL, FALSE);
+ if ( ibm_locals )
+ {
+ finish_locals ();
+ }
+ emit_token("exit");
+ }
break;
+
+ case ESCAPETOK:
+ enter_tokz_esc();
+ break;
case VERSION1:
case FCODE_V1:
- printf("%s:%d: using version1 header\n", iname, lineno);
- emit_token("version1");
- fcode_hdr=opc;
- emit_fcodehdr();
- offs16=FALSE;
+ tokenization_error( INFO, "Using version1 header "
+ "(8-bit offsets).\n");
+ fcode_starter( "version1", 1, FALSE) ;
break;
case START1:
case FCODE_V2:
case FCODE_V3: /* Full IEEE 1275 */
- emit_token("start1");
- fcode_hdr=opc;
- emit_fcodehdr();
- offs16=TRUE;
+ fcode_starter( "start1", 1, TRUE);
break;
case START0:
- printf ("%s:%d: warning: spread of 0 not supported.",
- iname, lineno);
- emit_token("start0");
- fcode_hdr=opc;
- emit_fcodehdr();
- offs16=TRUE;
+ fcode_starter( "start0", 0, TRUE);
break;
case START2:
- printf ("%s:%d: warning: spread of 2 not supported.",
- iname, lineno);
- emit_token("start2");
- fcode_hdr=opc;
- emit_fcodehdr();
- offs16=TRUE;
+ fcode_starter( "start2", 2, TRUE);
break;
case START4:
- printf ("%s:%d: warning: spread of 4 not supported.",
- iname, lineno);
- emit_token("start4");
- fcode_hdr=opc;
- emit_fcodehdr();
- offs16=TRUE;
+ fcode_starter( "start4", 4, TRUE);
break;
+ case END1:
+ tokenization_error( WARNING,
+ "Appearance of END1 in FCode source code "
+ "is not intended by IEEE 1275-1994\n");
+ handy_toggle = FALSE;
case END0:
case FCODE_END:
- haveend=TRUE;
- emit_token("end0");
+ if ( handy_toggle )
+ {
+ you_are_here();
+ }
+ emit_token( handy_toggle ? "end0" : "end1" );
+ fcode_ender();
+ FFLUSH_STDOUT
break;
- case END1:
- haveend=TRUE;
- emit_token("end1");
+ case RECURSE:
+ if ( test_in_colon(statbuf, TRUE, TKERROR, NULL ) )
+ {
+ emit_fcode(last_colon_fcode);
+ }
break;
+
case RECURSIVE:
+ if ( test_in_colon(statbuf, TRUE, TKERROR, NULL ) )
+ {
+ reveal_last_colon();
+ }
break;
+ case RET_STK_FETCH:
+ ret_stk_access_rpt();
+ emit_token( "r@");
+ break;
+
+ case RET_STK_FROM:
+ ret_stk_access_rpt();
+ bump_ret_stk_depth( -1);
+ emit_token( "r>");
+ break;
+
+ case RET_STK_TO:
+ bump_ret_stk_depth( 1);
+ emit_token( ">r");
+ break;
+
case PCIHDR:
- {
- u32 classid=dpop();
- u16 did=dpop();
- u16 vid=dpop();
-
- pci_hdr=opc;
- emit_pcihdr(vid, did, classid);
-
- printf("%s:%d: PCI header vendor id=0x%04x, "
- "device id=0x%04x, class=%06x\n",
- iname, lineno, vid, did, classid);
- }
+ emit_pcihdr();
break;
case PCIEND:
- if (!pci_hdr) {
- printf("%s:%d: error: pci-header-end/pci-end "
- "without pci-header\n", iname, lineno);
- ERROR;
- }
finish_pcihdr();
+ reset_fcode_ranges();
+ FFLUSH_STDOUT
break;
case PCIREV:
- pci_revision=dpop();
- printf("%s:%d: PCI header revision=0x%04x\n",
- iname, lineno, pci_revision);
+ pci_image_rev = dpop();
+ tokenization_error( INFO,
+ "PCI header revision=0x%04x%s\n", pci_image_rev,
+ big_end_pci_image_rev ?
+ ". Will be saved in Big-Endian format."
+ : "" );
break;
case NOTLAST:
- pci_is_last_image=FALSE;
- printf("%s:%d: PCI header not last image!\n",
- iname, lineno);
+ handy_toggle = FALSE;
+ case ISLAST:
+ dpush(handy_toggle);
+ case SETLAST:
+ {
+ u32 val = dpop();
+ bool new_pili = BOOLVAL( (val != 0) );
+ if ( pci_is_last_image != new_pili )
+ {
+ tokenization_error( INFO,
+ new_pili ?
+ "Last image for PCI header.\n" :
+ "PCI header not last image.\n" );
+ pci_is_last_image = new_pili;
+ }
+ }
break;
- case ABORTTXT:
- /* ABORT" is not to be used in FCODE drivers
- * but Apple drivers do use it. Therefore we
- * allow it. We push the specified string to
- * the stack, do -2 THROW and hope that THROW
- * will correctly unwind the stack.
- */
-
- printf("%s:%d: warning: ABORT\" in fcode not defined by "
- "IEEE 1275-1994.\n", iname, lineno);
- if (*pc++=='\n') lineno++;
- wlen=get_string();
-
-#ifdef BREAK_COMPLIANCE
- /* IF */
- emit_token("b?branch");
-
- dpush((unsigned long)opc);
- emit_offset(0);
-#endif
- emit_token("b(\")");
- emit_string(statbuf,wlen-1);
-#ifdef BREAK_COMPLIANCE
- emit_token("type");
-#endif
- emit_token("-2");
- emit_token("throw");
-#ifdef BREAK_COMPLIANCE
- /* THEN */
- emit_token("b(>resolve)");
- offs1=(unsigned long)opc;
- opc=(u8 *)dpop();
- offs2=offs1-(unsigned long)opc;
- emit_offset(offs2);
- opc=(u8 *)offs1;
-#endif
+ case SAVEIMG:
+ if (get_word_in_line( statbuf) )
+ {
+ free(oname);
+ oname = strdup( statbuf );
+ tokenization_error( INFO,
+ "Output is redirected to file: %s\n", oname);
+ }
break;
- case FCODE_DATE:
+ case RESETSYMBS:
+ tokenization_error( INFO,
+ "Resetting symbols defined in %s mode.\n",
+ in_tokz_esc ? "tokenizer-escape" : "\"normal\"");
+ if ( in_tokz_esc )
{
- time_t tt;
- char fcode_date[11];
-
- tt=time(NULL);
- strftime(fcode_date, 11, "%m/%d.%Y",
- localtime(&tt));
- emit_token("b(\")");
- emit_string((u8 *)fcode_date,10);
+ reset_tokz_esc();
+ }else{
+ reset_normal_vocabs();
}
break;
+ case FCODE_DATE:
+ handy_toggle = FALSE;
case FCODE_TIME:
{
time_t tt;
- char fcode_time[9];
+ char temp_buffr[32];
tt=time(NULL);
- strftime(fcode_time, 9, "%H:%M:%S",
- localtime(&tt));
+ if ( handy_toggle )
+ {
+ strftime(temp_buffr, 32, "%T %Z", localtime(&tt));
+ }else{
+ strftime(temp_buffr, 32, "%m/%d/%Y", localtime(&tt));
+ }
+ if ( in_tokz_esc )
+ {
+ tokenization_error( MESSAGE, temp_buffr);
+ }else{
emit_token("b(\")");
- emit_string((u8 *)fcode_time,8);
+ emit_string((u8 *)temp_buffr, strlen(temp_buffr) );
+ }
}
break;
case ENCODEFILE:
- wlen=get_word();
+ if (get_word_in_line( statbuf) )
+ {
encode_file( (char*)statbuf );
+ }
break;
default:
- printf("%s:%d: error: Unimplemented control word '%s'\n",
- iname, lineno, statbuf);
- ERROR;
+ /* IBM-style Locals, under control of a switch */
+ if ( ibm_locals )
+ {
+ bool found_it = TRUE;
+ switch (tok) {
+ case CURLY_BRACE:
+ declare_locals( FALSE);
+ break;
+ case DASH_ARROW:
+ assign_local();
+ break;
+ default:
+ found_it = FALSE;
}
+ if ( found_it ) break;
}
-void tokenize(void)
+ /* Down here, we have our last chance to recognize a token.
+ * If abort_quote is disallowed, we will still consume
+ * the string. In case the string spans more than one
+ * line, we want to make sure the line number displayed
+ * in the error-message is the one on which the disallowed
+ * abort_quote token appeared, not the one where the
+ * string ended; therefore, we might need to be able to
+ * "fake-out" the line number...
+ */
{
- unsigned long wlen;
- u16 tok;
- u8 *mac;
- long val;
+ bool fake_out_lineno = FALSE;
+ unsigned int save_lineno = lineno;
+ unsigned int true_lineno;
+ if ( abort_quote( tok) )
+ { break;
+ }else{
+ if ( tok == ABORTTXT ) fake_out_lineno = TRUE;
+ }
+ true_lineno = lineno;
+
+ if ( fake_out_lineno ) lineno = save_lineno;
+ tokenization_error ( TKERROR,
+ "Unimplemented control word '%s'\n", strupr(statbuf) );
+ if ( fake_out_lineno ) lineno = true_lineno;
+ }
+ }
+}
- while ((wlen=get_word())!=0) {
+/* **************************************************************************
+ *
+ * Function name: skip_string
+ * Synopsis: When Ignoring, skip various kinds of strings. Maps
+ * to string-handlers in handle_internal()...
+ *
+ * Associated FORTH words: Double-Quote ( " ) string
+ * Dot-Quote ( ." ) string
+ * Ess-Quote ( s" ) string
+ * Dot-Paren .( string
+ * ABORT" (even if not enabled)
+ * { (Local-Values declaration) and -> (Local-Values assignment)
+ * are also handled if ibm_locals is enabled.
+ *
+ * Inputs:
+ * Parameters:
+ * pfield Param-field of the entry associated with
+ * the FWord that is being Ignored.
+ * Global Variables:
+ * statbuf The word that was just read.
+ * pc Input-stream pointer
+ * lineno Line-number, used for errors and warnings
+ * ibm_locals TRUE if IBM-style Locals are enabled
+ *
+ * Outputs:
+ * Returned Value: NONE
+ *
+ * Error Detection:
+ * Multi-line warnings, "Unterminated" Errors
+ * handled by called routines
+ *
+ * Extraneous Remarks:
+ * We would prefer to keep this function private, too, so we
+ * will declare its prototype here and in the one other
+ * file where we need it, namely, dictionary.c, rather
+ * than exporting it widely in a .h file.
+ *
+ **************************************************************************** */
- /* Filter comments */
- switch (statbuf[0]) {
- case '\\':
- pc-=wlen;
- get_until('\n');
- continue;
+void skip_string( tic_param_t pfield);
+void skip_string( tic_param_t pfield)
+{
+ fwtoken tok = pfield.fw_token;
+ unsigned int sav_lineno = lineno;
+ bool handy_toggle = TRUE ; /* Various uses... */
- case '(':
- /* only a ws encapsulated '(' is a stack comment */
- if (statbuf[1])
+ switch (tok) {
+ case STRING: /* Double-Quote ( " ) string */
+ case PSTRING: /* Dot-Quote ( ." ) string */
+ case ABORTTXT: /* ABORT", even if not enabled */
+ get_string( FALSE); /* Don't truncate; ignoring anyway */
+ /* Will handle multi-line warnings, etc. */
break;
- pc-=wlen;
- get_until(')');
+ case SSTRING: /* Ess-Quote ( s" ) string */
+ handy_toggle = FALSE;
+ case PBSTRING: /* Dot-Paren .( string */
if (*pc++=='\n') lineno++;
+ {
+ unsigned int strt_lineno = lineno;
+ get_until( handy_toggle ? ')' : '"' );
+ string_err_check( handy_toggle, sav_lineno, strt_lineno );
+ }
+ break;
+
+ default:
+ /* IBM-style Locals, under control of a switch */
+ if ( ibm_locals )
+ {
+ bool found_it = TRUE;
+ switch (tok) {
+ case CURLY_BRACE:
+ declare_locals( TRUE);
+ break;
+ case DASH_ARROW:
+ get_word();
+ break;
+ default:
+ found_it = FALSE;
+ }
+ if ( found_it ) break;
+ }
+
+ tokenization_error ( FATAL, "Program Error. "
+ "Unimplemented skip-string word '%s'\n", strupr(statbuf) );
+ }
+}
+
+/* **************************************************************************
+ *
+ * Function name: process_remark
+ * Synopsis: The active function for remarks (backslash-space)
+ * and comments (enclosed within parens)
+ *
+ * Associated FORTH word(s): \ (
+ *
+ * Inputs:
+ * Parameters:
+ * TIC entry "parameter field", init'd to delimiter character.
+ *
+ * Outputs:
+ * Returned Value: NONE
+ *
+ * Error Detection:
+ * Warning if end-of-file encountered before delimiter.
+ * Warning if multi-line parentheses-delimited comment.
+ *
+ * Process Explanation:
+ * Skip until the delimiter.
+ * If end-of-file was encountered, issue Warning.
+ * Otherwise, and if delimiter was not new-line,
+ * check for multi-line with Warning.
+ *
+ **************************************************************************** */
+
+void process_remark( tic_param_t pfield )
+{
+ char until_char = (char)pfield.deflt_elem ;
+ unsigned int start_lineno = lineno;
+
#ifdef DEBUG_SCANNER
+
+ get_until(until_char);
printf ("%s:%d: debug: stack diagram: %s)\n",
iname, lineno, statbuf);
-#endif
- continue;
- }
+#else
- /* Check whether a macro with given name exists */
+ if ( skip_until( until_char) )
+ {
+ if ( until_char == '\n' )
+ {
+ /* Don't need any saved line number here ... */
+ tokenization_error ( WARNING,
+ "Unterminated remark.\n");
+ }else{
+ warn_unterm( WARNING, "comment", start_lineno);
+ }
+ }else{
+ if ( until_char != '\n' )
+ {
+ pc++;
+ warn_if_multiline( "comment", start_lineno);
+ }
+ }
+#endif /* DEBUG_SCANNER */
+}
- mac=(u8 *)lookup_macro((char *)statbuf);
- if(mac) {
- u8 *oldstart, *oldpc, *oldend;
-#ifdef DEBUG_SCANNER
- printf("%s:%d: debug: macro %s folds out to sequence"
- " '%s'\n", iname, lineno, statbuf, mac);
-#endif
- oldstart=start; oldpc=pc; oldend=end;
- start=pc=end=mac;
- end+=strlen((char *)mac);
- tokenize();
+/* **************************************************************************
+ *
+ * Function name: filter_comments
+ * Synopsis: Process remarks and comments in special conditions
+ *
+ * Inputs:
+ * Parameters:
+ * inword Current word just parsed
+ *
+ * Outputs:
+ * Returned Value: TRUE if Current word is a Comment-starter.
+ * Comment will be processed
+ *
+ * Process Explanation:
+ * We want to be able to recognize any alias the user may have
+ * defined to a comment-delimiter, in whatever applicable
+ * vocabulary it might be.
+ * The active-function of any such alias will, of necessity, be
+ * the process_remark() routine, defined just above.
+ * We will search for the TIC-entry of the given word; if we don't
+ * find it, it's not a comment-delimiter. If we do find it,
+ * and it is one, we invoke its active-function and return TRUE.
+ * We also want to permit the "allow-multiline-comments" directive
+ * to be processed in the context that calls this routine, so
+ * we will check for that condition, too.
+ *
+ **************************************************************************** */
- end=oldend; pc=oldpc; start=oldstart;
+bool filter_comments( u8 *inword)
+{
+ bool retval = FALSE;
+ tic_hdr_t *found = lookup_word( inword, NULL, NULL );
- continue;
+ if ( found != NULL )
+ {
+ if ( found->funct == process_remark )
+ {
+ found->funct( found->pfield);
+ retval = TRUE;
+ }else{
+ /* Permit the "allow-multiline-comments" directive */
+ if ( found->funct == handle_internal )
+ {
+ if ( found->pfield.fw_token == ALLOW_MULTI_LINE )
+ {
+ /* Make sure any intended side-effects occur... */
+ found->funct( found->pfield);
+ retval = TRUE;
}
+ }
+ }
+ }
+ return ( retval );
+ }
- /* Check whether it's a non-fcode forth construct */
- tok=lookup_fword((char *)statbuf);
- if (tok!=0xffff) {
-#ifdef DEBUG_SCANNER
- printf("%s:%d: debug: matched internal opcode 0x%04x\n",
- iname, lineno, tok);
-#endif
- handle_internal(tok);
-#ifdef DEBUG_SCANNER
- if (verbose)
- printf("%s:%d: debug: '%s' done.\n",
- iname,lineno,statbuf);
-#endif
- continue;
- }
+/* **************************************************************************
+ *
+ * Function name: tokenize_one_word
+ * Synopsis: Tokenize the currently-obtained word
+ * along with whatever it consumes.
+ *
+ * Inputs:
+ * Parameters:
+ * wlen Length of symbol just retrieved from the input stream
+ * This is not really used here any more; it's
+ * left over from an earlier implementation.
+ * Global Variables:
+ * statbuf The symbol (word) just retrieved from input stream.
+ * in_tokz_esc TRUE if "Tokenizer-Escape" mode is in effect; a
+ * different set of vocabularies from "Normal"
+ * mode will be checked (along with those that
+ * are common to both modes).
+ * ibm_locals Controls whether to check for IBM-style Locals;
+ * set by means of a command-line switch.
+ *
+ * Outputs:
+ * Returned Value: NONE
+ * Global Variables:
+ * statbuf May be incremented
+ * in_tokz_esc May be set if the word just retrieved is
+ * the tokenizer[ directive.
+ * tic_found
+ *
+ * Error Detection:
+ * If the word could neither be identified nor processed as a number,
+ * that is an ERROR; pass it to tokenized_word_error for a
+ * message.
+ *
+ * Process Explanation:
+ * Look for the word in each of the various lists and vocabularies
+ * in which it might be found, as appropriate to the current
+ * state of activity.
+ * If found, process it accordingly.
+ * If not found, try to process it as a number.
+ * If cannot process it as a number, declare an error.
+ *
+ * Revision History:
+ * Updated Tue, 10 Jan 2006 by David L. Paktor
+ * Convert to tic_hdr_t type vocabularies.
+ * Updated Mon, 03 Apr 2006 by David L. Paktor
+ * Replaced bulky "Normal"-vs-"Escape" block with a call
+ * to lookup_word . Attend to a small but important
+ * side-effect of the "handle_<vocab>" routines that
+ * feeds directly into the protection against self-
+ * -recursion in a user-defined Macro: Set the global
+ * variable tic_found to the entry, just before we
+ * execute it, and we're good to go...
+ *
+ * Extraneous Remarks:
+ * We trade off the strict rules of structure for simplicity
+ * of coding.
+ *
+ **************************************************************************** */
- /* Check whether it's one of the defined fcode words */
+void tokenize_one_word( signed long wlen )
+{
- tok=lookup_token((char *)statbuf);
- if (tok!=0xffff) {
-#ifdef DEBUG_SCANNER
- printf("%s:%d: debug: matched fcode no 0x%04x\n",
- iname, lineno, tok);
-#endif
- emit_fcode(tok);
- continue;
- }
+ /* The shared lookup routine now handles everything. */
+ tic_hdr_t *found = lookup_word( statbuf, NULL, NULL );
- /* It's not a word or macro - is it a number? */
+ if ( found != NULL )
+ {
+ tic_found = found;
+ found->funct( found->pfield);
+ return ;
+ }
- if (!get_number(&val)) {
- if (intok)
- dpush(val);
- else {
- emit_fcode(lookup_token("b(lit)"));
- emit_num32(val);
+ /* It's not a word in any of our current contexts.
+ * Is it a number?
+ */
+ if ( handle_number() )
+ {
+ return ;
}
- continue;
+
+ /* Could not identify - give a shout. */
+ tokenized_word_error( statbuf );
}
- /* could not identify - bail out. */
+/* **************************************************************************
+ *
+ * Function name: tokenize
+ * Synopsis: Tokenize the current input stream.
+ * May be called recursively for macros and such.
+ *
+ * Revision History:
+ * Updated Thu, 24 Mar 2005 by David L. Paktor
+ * Factor-out comment-filtration; apply to gather_locals
+ * Factor-out tokenizing a single word (for conditionals)
+ * Separate actions of "Tokenizer-Escape" mode.
+ *
+ **************************************************************************** */
+
+void tokenize(void)
+{
+ signed long wlen = 0;
- printf("%s:%d: error: word '%s' is not in dictionary.\n",
- iname, lineno, statbuf);
- ERROR;
+ while ( wlen >= 0 )
+ {
+ wlen = get_word();
+ if ( wlen > 0 )
+ {
+ tokenize_one_word( wlen );
}
+ }
}
Added: fcode-utils/toke/scanner.h
===================================================================
--- fcode-utils/toke/scanner.h (rev 0)
+++ fcode-utils/toke/scanner.h 2006-08-18 12:47:12 UTC (rev 76)
@@ -0,0 +1,123 @@
+#ifndef _TOKE_SCANNER_H
+#define _TOKE_SCANNER_H
+
+/*
+ * OpenBIOS - free your system!
+ * ( FCode tokenizer )
+ *
+ * This program is part of a free implementation of the IEEE 1275-1994
+ * Standard for Boot (Initialization Configuration) Firmware.
+ *
+ * Copyright (C) 2001-2005 Stefan Reinauer, <stepan(a)openbios.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA, 02110-1301 USA
+ *
+ */
+
+/* **************************************************************************
+ *
+ * External/Prototype definitions for Scanning functions in Tokenizer
+ *
+ * (C) Copyright 2005 IBM Corporation. All Rights Reserved.
+ * Module Author: David L. Paktor dlpaktor(a)us.ibm.com
+ *
+ **************************************************************************** */
+
+
+#include "types.h"
+#include "ticvocab.h"
+
+/* ************************************************************************** *
+ *
+ * Global Variables Exported
+ *
+ **************************************************************************** */
+
+extern u8 *statbuf; /* The word just read from the input stream */
+extern u8 base; /* The numeric-interpretation base */
+
+
+/* pci data */
+extern bool pci_is_last_image;
+extern u16 pci_image_rev; /* Vendor's Image, NOT PCI Data Struct Rev */
+extern u16 pci_vpd;
+
+
+/* Having to do with the state of the tokenization */
+extern bool offs16; /* Using 16-bit branch- (etc) -offsets */
+extern bool in_tokz_esc; /* TRUE if in "Tokenizer Escape" mode */
+extern bool incolon; /* TRUE if inside a colon definition */
+extern bool haveend; /* TRUE if the "end" code was read. */
+extern int do_loop_depth; /* How deep we are inside DO ... LOOP variants */
+
+/* For special-case error detection or reporting */
+extern int lastcolon; /* Loc'n in output stream of latest colon-def'n. */
+ /* Used for error-checking of IBM-style Locals */
+extern char *last_colon_defname; /* Name of last colon-definition */
+extern char *last_colon_filename; /* File where last colon-def'n made */
+extern unsigned int last_colon_lineno; /* Line number of last colon-def'n */
+extern bool report_multiline; /* False to suspend multiline warning */
+extern unsigned int last_colon_abs_token_no;
+
+/* ************************************************************************** *
+ *
+ * Function Prototypes / Functions Exported:
+ *
+ **************************************************************************** */
+
+void init_scanner( void );
+void exit_scanner( void );
+void init_scan_state( void );
+void fcode_ender( void );
+
+bool skip_until( char lim_ch);
+void push_source( void (*res_func)(), _PTR res_parm, bool is_f_chg );
+signed long get_word( void);
+bool get_word_in_line( char *func_nam);
+bool get_rest_of_line( void);
+void warn_unterm( int severity,
+ char *something,
+ unsigned int saved_lineno);
+void warn_if_multiline( char *something, unsigned int start_lineno );
+void user_message( tic_param_t pfield );
+void skip_user_message( tic_param_t pfield );
+bool get_number( long *result);
+void eval_string( char *inp_bufr);
+
+void process_remark( tic_param_t pfield );
+bool filter_comments( u8 *inword);
+bool as_a_what( fwtoken definer, char *as_what);
+tic_hdr_t *lookup_word( char *stat_name, char **where_pt1, char **where_pt2 );
+bool word_exists( char *stat_name, char **where_pt1, char **where_pt2 );
+void warn_if_duplicate ( char *stat_name);
+void trace_creation( fwtoken definer, char *nu_name);
+void tokenize_one_word( signed long wlen );
+void check_name_length( signed long wlen );
+
+void tokenize( void );
+
+/* **************************************************************************
+ *
+ * Macro Name: FUNC_CPY_BUF_SIZE
+ * Size of a temporary buffer to retain a copy of
+ * a function name taken from statbuf, when statbuf
+ * will be used to return a value, but the function
+ * name might still be needed for an error message.
+ *
+ **************************************************************************** */
+
+#define FUNC_CPY_BUF_SIZE 40
+
+
+#endif /* _TOKE_SCANNER_H */
Modified: fcode-utils/toke/stack.c
===================================================================
--- fcode-utils/toke/stack.c 2006-08-18 09:45:11 UTC (rev 75)
+++ fcode-utils/toke/stack.c 2006-08-18 12:47:12 UTC (rev 76)
@@ -24,93 +24,203 @@
*
*/
+/* **************************************************************************
+ * Modifications made in 2005 by IBM Corporation
+ * (C) Copyright 2005 IBM Corporation. All Rights Reserved.
+ * Modifications Author: David L. Paktor dlpaktor(a)us.ibm.com
+ **************************************************************************** */
+
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
-#include "toke.h"
#include "stack.h"
+#include "scanner.h"
+#include "errhandler.h"
+/* **************************************************************************
+ *
+ * Global Variables Imported
+ * statbuf The word just read from the input stream
+ *
+ **************************************************************************** */
-#define GUARD_STACK
-#define EXIT_STACKERR
-#ifdef GLOBALSTACK
-#define STATIC static
-#else
-#define STATIC
-#endif
-STATIC long *dstack,*startdstack,*enddstack;
-#undef STATIC
+/* **************************************************************************
+ *
+ * Global Variables Exported
+ * dstack Pointer to current item on top of Data Stack
+ *
+ **************************************************************************** */
+long *dstack;
+
+/* **************************************************************************
+ *
+ * Local/Static Pointers ..... to ... -> Points to ...
+ * startdstack Start of data-stack area -> last possible item
+ * enddstack End of data-stack area -> past first item
+ *
+ *************************************************************************** */
+
+static long *startdstack;
+static long *enddstack;
+
+void clear_stack(void)
+{
+ dstack = enddstack;
+}
+
/* internal stack functions */
-int init_stack(void)
+void init_stack(void)
{
- startdstack=enddstack=malloc(MAX_ELEMENTS*sizeof(long));
- enddstack+=MAX_ELEMENTS;
+ startdstack = safe_malloc(MAX_ELEMENTS*sizeof(long), "initting stack");
+ enddstack = startdstack + MAX_ELEMENTS;
dstack=enddstack;
- return 0;
}
-#ifdef GLOBALSTACK
+/* Input Param: stat TRUE = Underflow, FALSE = Overflow */
+static void stackerror(bool stat)
+{
+ /*
+ * Because all of our stack operations are protected and
+ * we have no risk of the dstack pointer going into
+ * invalid territory, this error needs not be FATAL.
+ */
+ tokenization_error ( TKERROR , "stack %sflow at or near %s \n",
+ (stat)?"under":"over" , statbuf );
+}
-#ifdef GUARD_STACK
-static void stackerror(int stat)
+/*
+ * Return TRUE if the stack depth is equal to or greater than
+ * the supplied minimum requirement. If not, print an error.
+ */
+bool min_stack_depth(int mindep)
{
- printf ("FATAL: stack %sflow\n",
- (stat)?"under":"over" );
-#ifdef EXIT_STACKERR
- exit(-1);
-#endif
+ bool retval = TRUE ;
+ long *stack_result;
+
+ stack_result = dstack + mindep;
+ /*
+ * The above appears counter-intuitive. However, C compensates
+ * for the size of the object of a pointer when it handles
+ * address arithmetic. A more explicit expression that would
+ * yield the same result, might look something like this:
+ *
+ * (long *)((int)dstack + (mindep * sizeof(long)))
+ *
+ * I doubt that that form would yield tighter code, or otherwise
+ * represent any material advantage...
+ */
+
+ if ( stack_result > enddstack )
+ {
+ retval = FALSE;
+ stackerror(TRUE);
+ }
+
+ return ( retval );
}
-#endif
+/*
+ * Return TRUE if the stack has room for the supplied # of items
+ */
+static bool room_on_stack_for(int newdep)
+{
+ bool retval = TRUE ;
+ long *stack_result;
+
+ stack_result = dstack - newdep;
+ /* See above note about "counter-intuitive" pointer address arithmetic */
+
+ if ( stack_result < startdstack )
+ {
+ retval = FALSE;
+ stackerror(FALSE);
+ }
+
+ return ( retval );
+}
+
void dpush(long data)
{
#ifdef DEBUG_DSTACK
printf("dpush: sp=%p, data=0x%lx, ", dstack, data);
#endif
- *(--dstack)=data;
-#ifdef GUARD_STACK
- if (dstack<startdstack) stackerror(0);
-#endif
+ if ( room_on_stack_for(1) )
+ {
+ --dstack;
+ *(dstack)=data;
+ }
}
long dpop(void)
{
- long val;
+ long val = 0;
#ifdef DEBUG_DSTACK
printf("dpop: sp=%p, data=0x%lx, ",dstack, *dstack);
#endif
- val=*(dstack++);
-#ifdef GUARD_STACK
- if (dstack>enddstack) stackerror(1);
-#endif
+ if ( min_stack_depth(1) )
+ {
+ val=*(dstack);
+ dstack++;
+ }
return val;
}
long dget(void)
{
- return *(dstack);
+ long val = 0;
+ if ( min_stack_depth(1) )
+ {
+ val = *(dstack);
+ }
+ return val;
}
-#endif
-/* Stack helper functions */
-
-u8 *get_stackstring(void)
+long stackdepth(void)
{
- long size;
- u8 *fstring, *retstring;
+ long depth;
- size=dpop();
- fstring=(u8 *)dpop();
+ depth = enddstack - dstack;
+ /*
+ * Again, C's address arithmetic compensation comes into play.
+ * See the note at min_stack_depth()
+ *
+ * A more explicit equivalent expression might look like this:
+ *
+ * (((long int)enddstack - (long int)dstack) / sizeof(long))
+ *
+ * I doubt any material advantage with that one either...
+ */
- retstring=malloc(size+1);
- strncpy((char *)retstring, (const char *)fstring, size);
- retstring[size]=0;
+ return (depth);
+}
- return retstring;
+void swap(void)
+{
+ long nos_temp; /* Next-On-Stack temp */
+ if ( min_stack_depth(2) )
+ {
+ nos_temp = dstack[1];
+ dstack[1]= dstack[0];
+ dstack[0]= nos_temp;
+ }
}
+void two_swap(void)
+{
+ long two_deep, three_deep;
+ if ( min_stack_depth(4) )
+ {
+ two_deep = dstack[2];
+ three_deep = dstack[3];
+ dstack[2] = dstack[0];
+ dstack[3] = dstack[1];
+ dstack[1] = three_deep;
+ dstack[0] = two_deep;
+ }
+}
+
Modified: fcode-utils/toke/stack.h
===================================================================
--- fcode-utils/toke/stack.h 2006-08-18 09:45:11 UTC (rev 75)
+++ fcode-utils/toke/stack.h 2006-08-18 12:47:12 UTC (rev 76)
@@ -1,3 +1,6 @@
+#ifndef _TOKE_STACK_H
+#define _TOKE_STACK_H
+
/*
* OpenBIOS - free your system!
* ( FCode tokenizer )
@@ -24,23 +27,47 @@
*
*/
-#ifdef ANSI_ONLY
-#define GLOBALSTACK
-#endif
+/* **************************************************************************
+ * Modifications made in 2005 by IBM Corporation
+ * (C) Copyright 2005 IBM Corporation. All Rights Reserved.
+ * Modifications Author: David L. Paktor dlpaktor(a)us.ibm.com
+ **************************************************************************** */
+#include "types.h"
+
+/* ************************************************************************** *
+ *
+ * Macros:
+ * MAX_ELEMENTS Size of stack area, in "elements"
+ *
+ **************************************************************************** */
+
#define MAX_ELEMENTS 1024
-#ifdef GLOBALSTACK
+/* ************************************************************************** *
+ *
+ * Global Variables Exported
+ *
+ **************************************************************************** */
+
+extern long *dstack;
+
+/* ************************************************************************** *
+ *
+ * Function Prototypes / Functions Exported:
+ *
+ **************************************************************************** */
+
void dpush(long data);
long dpop(void);
long dget(void);
-#else
-extern long *dstack,*startdstack;
-static inline void dpush(long data) { *(--dstack)=data; }
-static inline long dpop(void) { return (long)*(dstack++); }
-static inline long dget(void) { return *(dstack); }
-#endif
-int init_stack(void);
-u8 *get_stackstring(void);
+void clear_stack(void);
+void init_stack(void);
+bool min_stack_depth(int mindep); /* TRUE if no error */
+long stackdepth(void);
+void swap(void);
+void two_swap(void);
+
+#endif /* _TOKE_STACK_H */
Modified: fcode-utils/toke/stream.c
===================================================================
--- fcode-utils/toke/stream.c 2006-08-18 09:45:11 UTC (rev 75)
+++ fcode-utils/toke/stream.c 2006-08-18 12:47:12 UTC (rev 76)
@@ -24,6 +24,12 @@
*
*/
+/* **************************************************************************
+ * Modifications made in 2005 by IBM Corporation
+ * (C) Copyright 2005 IBM Corporation. All Rights Reserved.
+ * Modifications Author: David L. Paktor dlpaktor(a)us.ibm.com
+ **************************************************************************** */
+
#include <stdio.h>
#include <stdlib.h>
#ifdef __GLIBC__
@@ -32,134 +38,1577 @@
#include <string.h>
#include <sys/stat.h>
+#include "emit.h"
+#include "stream.h"
+#include "errhandler.h"
#include "toke.h"
-#include "stream.h"
-#define OUTPUT_SIZE 131072
+/* **************************************************************************
+ *
+ * Revision History:
+ * Updated Tue, 31 Jan 2006 by David L. Paktor
+ * Add support for embedded Environment-Variables in path name
+ * Updated Thu, 16 Feb 2006 David L. Paktor
+ * Collect missing (inaccessible) filenames
+ * Updated Thu, 16 Mar 2006 David L. Paktor
+ * Add support for Include-Lists
+ *
+ **************************************************************************** */
-extern bool offs16;
-extern u16 nextfcode;
+/* **************************************************************************
+ *
+ * Global Variables Exported
+ * start Start of input-source buffer
+ * end End of input-source buffer
+ * pc Input-source Scanning pointer
+ * iname Current Input File name
+ * lineno Current Line Number in Input File
+ * ostart Start of Output Buffer
+ * opc FCode Output Buffer Position Counter
+ * oname Output File name
+ *
+ **************************************************************************** */
-u8 *start, *pc, *end;
-char *iname;
+/* Input pointers, Position Counters and Length counters */
+u8 *start = NULL;
+u8 *pc;
+u8 *end;
+char *iname = NULL;
+unsigned int lineno = 0;
+unsigned int abs_token_no = 0; /* Absolute Token Number in all Source Input
+ * Will be used to identify position
+ * where colon-definition begins and
+ * to limit clearing of control-structs.
+ */
+static unsigned int ilen; /* Length of Input Buffer */
+
/* output pointers */
-u8 *ostart, *opc, *oend, *oname;
-static unsigned int ilen;
+u8 *ostart;
+char *oname = NULL;
+unsigned int opc; /* Output Position Counter */
-unsigned int lineno;
+/* We want to limit exposure of this v'ble, so don't put it in .h file */
+unsigned int olen; /* Length of Output Buffer */
+/* We want to limit exposure of this Imported Function, likewise. */
+void init_emit( void);
-int init_stream( const char *name)
+/* **************************************************************************
+ *
+ * Internal Static Variables
+ * load_list_name Name of the Load List File
+ * load_list_file (Pointer to) File-Structure for the Load List File
+ * depncy_list_name Name of the Dependency List File
+ * depncy_file (Pointer to) File-Structure for the Dependency List File
+ * missing_list_name Name of the Missing-Files-List File
+ * missing_list_file (Pointer to) File-Structure for Missing-List File
+ * no_files_missing TRUE if able to load all files
+ *
+ **************************************************************************** */
+
+static char *load_list_name;
+static FILE *load_list_file;
+static char *depncy_list_name;
+static FILE *depncy_file;
+static char *missing_list_name;
+static FILE *missing_list_file;
+static bool no_files_missing = TRUE;
+
+/* **************************************************************************
+ *
+ * Private data-structure for Include-List support
+ *
+ * Components are simply a string-pointer and a link pointer
+ *
+ **************************************************************************** */
+
+typedef struct incl_list
{
- FILE *infile;
- unsigned int i;
+ char *dir_path;
+ struct incl_list *next;
+ } incl_list_t;
+
+/* **************************************************************************
+ *
+ * Internal Static Variables associated with Include-List support
+ * include_list_start Start of the Include-List
+ * include_list_next Next entry in Include-List to add or read
+ * max_dir_path_len Size of longest entry in the Include-List
+ * include_list_full_path Full-Path (i.e., expanded File-name with
+ * Include-List Entry) that was last opened.
+ *
+ **************************************************************************** */
+static incl_list_t *include_list_start = NULL;
+static incl_list_t *include_list_next = NULL;
+static unsigned int max_dir_path_len = 0;
+static char *include_list_full_path = NULL;
+
+
+/* **************************************************************************
+ *
+ * Function name: add_to_include_list
+ * Synopsis: Add an entry to the Include-List
+ *
+ * Inputs:
+ * Parameters:
+ * dir_compt Directory Component to add to Inc-List
+ * Local Static Variables:
+ * include_list_start First entry in the Include-List
+ * include_list_next Next entry in Include-List to add
+ * max_dir_path_len Previous max Dir-Component Length
+ *
+ * Outputs:
+ * Returned Value: NONE
+ * Local Static Variables:
+ * include_list_start Assigned a value, first time through
+ * include_list_next "Next" field updated with new entry,
+ * then pointer updated to new entry.
+ * max_dir_path_len Maximum Length
+ * Memory Allocated
+ * For the list-entry, and for the directory/path name to be added
+ * When Freed?
+ * Remains in effect through the life of the program.
+ *
+ * Process Explanation:
+ * Unlike most of our linked-lists, this one will be linked forward,
+ * i.e., in the order elements are added, and will be searched
+ * in a forward order.
+ * This means extra code to handle the first entry.
+ * Allocate and initialize the New Include-List Entry.
+ * If this is the first entry, point the List-Starter at it.
+ * Otherwise, the Last-Entry-on-the-List pointer is already valid;
+ * point its "next" field at the New Entry.
+ * Point the Last-Entry-on-the-List pointer at the New Entry.
+ *
+ **************************************************************************** */
+
+void add_to_include_list( char *dir_compt)
+{
+ unsigned int new_path_len = strlen( dir_compt);
+ incl_list_t *new_i_l_e = safe_malloc( sizeof( incl_list_t),
+ "adding to include-list" );
+
+ new_i_l_e->dir_path = strdup( dir_compt);
+ new_i_l_e->next = NULL;
+
+ if ( include_list_start == NULL )
+ {
+ include_list_start = new_i_l_e;
+ }else{
+ include_list_next->next = new_i_l_e;
+ }
+
+ include_list_next = new_i_l_e;
+ if ( new_path_len > max_dir_path_len ) max_dir_path_len = new_path_len;
+}
+
+#define DISPLAY_WIDTH 80
+/* **************************************************************************
+ *
+ * Function name: display_include_list
+ * Synopsis: Display the Include-List, once it's completed,
+ * if "verbose" mode is in effect.
+ *
+ * Inputs:
+ * Parameters: NONE
+ * Local Static Variables:
+ * include_list_start First entry in the Include-List
+ * include_list_next Next entry, as we step through.
+ * Macro:
+ * DISPLAY_WIDTH Width limit of the display
+ *
+ * Outputs:
+ * Returned Value: NONE
+ * Local Static Variables:
+ * include_list_next NULL, when reaches end of Incl-List
+ * Printout:
+ * The elements of the Include-List, separated by a space, on
+ * a line up to the DISPLAY_WIDTH, or on a line by itself
+ * if the element is wider.
+ *
+ * Process Explanation:
+ * The calling routine will check for the verbose flag.
+ * Nothing to be done here if Include-List is NULL.
+ * Print a header, then the list.
+ *
+ **************************************************************************** */
+
+void display_include_list( void)
+{
+ if ( include_list_start != NULL )
+ {
+ int curr_wid = DISPLAY_WIDTH; /* Current width; force new line */
+ printf("\nInclude-List:");
+ include_list_next = include_list_start ;
+ while ( include_list_next != NULL )
+ {
+ int this_wid = strlen( include_list_next->dir_path) + 1;
+ char *separator = " ";
+ if ( curr_wid + this_wid > DISPLAY_WIDTH )
+ {
+ separator = "\n\t";
+ curr_wid = 7; /* Allow 1 for the theoretical space */
+ }
+ printf("%s%s", separator, include_list_next->dir_path);
+ curr_wid += this_wid;
+ include_list_next = include_list_next->next ;
+ }
+ printf("\n");
+ }
+}
+
+
+
+/* **************************************************************************
+ *
+ * We cannot accommodate the structures of the different
+ * routines that open files with a single function, so
+ * we will have to divide the action up into pieces:
+ * one routine to initialize the include-list search, a
+ * second to return successive candidates. The calling
+ * routine will do the operation (stat or fopen) until
+ * it succeeds or the list is exhausted. Then it will
+ * call a final routine to clean up and display messages.
+ *
+ * I'm sure I don't need to mention that, when no include-list
+ * is defined, these functions will still support correct
+ * operation...
+ *
+ **************************************************************************** */
+
+/* **************************************************************************
+ *
+ * Function name: init_incl_list_scan
+ * Synopsis: Initialize the search through the Include-List
+ *
+ * Inputs:
+ * Parameters:
+ * base_name Expanded user-supplied file-name
+ * Local Static Variables:
+ * include_list_start First entry in the Include-List
+ * max_dir_path_len Maximum Directory Component Length
+ *
+ * Outputs:
+ * Returned Value: NONE
+ * Local Static Variables:
+ * include_list_next Next entry in Include-List to read
+ * include_list_full_path Full-Path Buffer pointer
+ * Memory Allocated
+ * Full-Path Buffer (If Include-List was defined)
+ * When Freed?
+ * In finish_incl_list_scan()
+ *
+ * Process Explanation:
+ * The base_name passed to the routine is expected to have
+ * any embedded Environment-Variables already expanded.
+ * The Full-Path Buffer is presumed to be unallocated, and
+ * its pointer to be NULL.
+ * The Next-Entry-to-read pointer is also presumed to be NULL.
+ * If an Include-List has been defined, we will allocate memory
+ * for the Full-Path Buffer and point the Next-Entry pointer
+ * at the Start of the List. If not, no need to do anything.
+ *
+ **************************************************************************** */
+
+static void init_incl_list_scan( char *base_name)
+{
+ if ( include_list_start != NULL )
+ {
+ /* Allocate memory for the file-name buffer.
+ * maximum path-element length plus base-name length
+ * plus one for the slash plus one for the ending NULL
+ */
+ unsigned int new_path_len = max_dir_path_len + strlen( base_name) + 2;
+ include_list_full_path = safe_malloc( new_path_len,
+ "scanning include-list" );
+ include_list_next = include_list_start;
+ }
+}
+
+/* **************************************************************************
+ *
+ * Function name: scan_incl_list
+ * Synopsis: Prepare the next candidate in the include-list search
+ * Indicate when the end has been reached.
+ *
+ * Inputs:
+ * Parameters:
+ * base_name Expanded user-supplied file-name
+ * Local Static Variables:
+ * include_list_full_path Full-Path Buffer pointer
+ * include_list_next Next entry in Include-List to read
+ *
+ * Outputs:
+ * Returned Value: TRUE if valid candidate; FALSE when done
+ * Local Static Variables:
+ * include_list_full_path Next Full file-name Path to use
+ * include_list_next Updated to next entry in the List
+ *
+ * Process Explanation:
+ * Include-List Components are presumed not to require any expansion;
+ * the Shell is expected to resolve any Environment-Variables
+ * supplied in command-line arguments before they are passed
+ * to the (this) application-program.
+ * We will, therefore, not attempt to expand any Components of
+ * the Include-List.
+ * If the Full-Path Buffer pointer is NULL, it indicates that no
+ * entries have been made to the Include-List and this is our
+ * first time through this routine in this search; we will
+ * use the base-name as supplied, presumably relative to the
+ * current directory. Point the buffer-pointer at the base-
+ * -name and return "Not Done".
+ * Otherwise, we will look at the Next-Entry pointer:
+ * If it is NULL, we have come to the end of the Include-List;
+ * whether because no Include-List was defined or because
+ * we have reached the end, we will return "Done".
+ * Otherwise, we will load the Full-Path Buffer with the entry
+ * currently indicated by the Next-Entry pointer, advance
+ * it to the next entry in the List and return "Not Done".
+ * We will supply a slash as the directory-element separator in
+ * between the Include-List entry and the base_name
+ *
+ * Extraneous Remarks:
+ * The slash as directory-element separator works in UNIX-related
+ * environments, but is not guaranteed in others. I would
+ * have preferred to specify that Include-List Components are
+ * required to end with the appropriate separator, but that
+ * was neither acceptable nor compatible with existing practice
+ * in other utilities, and the effort to programmatically
+ * determine the separator used by the Host O/S was too much
+ * for such a small return. And besides, we already have so
+ * many other UNIX-centric assumptions hard-coded into the
+ * routines in this file (dollar-sign to signify Environment
+ * Variables, period for file-name-extension separator, etc.)
+ * that it's just too much of an uphill battle anymore...
+ *
+ **************************************************************************** */
+
+static bool scan_incl_list( char *base_name)
+{
+ bool retval = FALSE; /* default to "Done" */
+ if ( include_list_full_path == NULL )
+ {
+ include_list_full_path = base_name;
+ retval = TRUE;
+ }else{
+ if ( include_list_next != NULL )
+ {
+
+ /* Special case: If the next Directory Component is
+ * an empty string, do not prepend a slash; that
+ * would either become a root-based absolute path,
+ * or, if the base-name is itself an absolute path,
+ * it would be a path that begins with two slashes,
+ * and *some* Host Operating Systems ***REALLY***
+ * DO NOT LIKE that!
+ */
+ if ( strlen( include_list_next->dir_path) == 0 )
+ {
+ sprintf( include_list_full_path, "%s", base_name);
+ }else{
+ sprintf( include_list_full_path, "%s/%s",
+ include_list_next->dir_path, base_name);
+ }
+ include_list_next = include_list_next->next;
+ retval = TRUE;
+ }
+ }
+
+ return( retval);
+}
+
+/* **************************************************************************
+ *
+ * Function name: finish_incl_list_scan
+ * Synopsis: Clean up after a search through the Include-List
+ * Display appropriate messages.
+ *
+ * Inputs:
+ * Parameters:
+ * op_succeeded TRUE if intended operation was ok.
+ *
+ * Local Static Variables:
+ * include_list_start Non-NULL if Include-List was defined
+ *
+ * Outputs:
+ * Returned Value: NONE
+ * Local Static Variables:
+ * include_list_full_path Reset to NULL
+ * include_list_next Reset to NULL
+ * Memory Freed
+ * Full-Path Buffer (If Include-List was defined)
+ * Printout:
+ * If file was found in Include-List, Advisory showing where.
+ *
+ **************************************************************************** */
+
+static void finish_incl_list_scan( bool op_succeeded)
+{
+ if ( include_list_start != NULL )
+ {
+ if ( op_succeeded )
+ {
+ tokenization_error( INFO,
+ "File was found in %s\n" ,include_list_full_path );
+ }
+ free( include_list_full_path);
+ }
+ include_list_full_path = NULL;
+ include_list_next = NULL;
+}
+
+/* **************************************************************************
+ *
+ * Function name: open_incl_list_file
+ * Synopsis: Look in the Include-List, if one is defined, for
+ * the file whose name is given and open it.
+ *
+ * Inputs:
+ * Parameters:
+ * base_name Expanded user-supplied file-name
+ * mode Mode-string to use; usually "r" or "rb"
+ * Local Static Variables:
+ * include_list_full_path Full Path to use in fopen atttempt
+ *
+ * Outputs:
+ * Returned Value: File structure pointer; NULL if failed
+ * Local Static Variables:
+ * include_list_full_path Full Path used, if succeeded
+ *
+ * Error Detection:
+ * Calling routine will detect and report Errors.
+ *
+ * Process Explanation:
+ * This routine will initialize and step through Include-List.
+ * Calling routine will be responsible for "finishing" the
+ * Include-List search, as well as any Advisory messages.
+ *
+ **************************************************************************** */
+
+static FILE *open_incl_list_file( char *base_name, char *mode)
+{
+ FILE *retval = NULL;
+
+ init_incl_list_scan( base_name);
+ while ( scan_incl_list( base_name) )
+ {
+ retval = fopen( include_list_full_path, mode);
+ if ( retval != NULL )
+ {
+ break;
+ }
+ }
+
+ return (retval);
+}
+
+/* **************************************************************************
+ *
+ * Function name: stat_incl_list_file
+ * Synopsis: Look in the Include-List, if defined, for given file,
+ * and collect its statistics.
+ *
+ *
+ * Inputs:
+ * Parameters:
+ * base_name Expanded user-supplied file-name
+ * file_info Pointer to STAT structure
+ * Local Static Variables:
+ * include_list_full_path Full Path to use in file-status atttempt
+ *
+ * Outputs:
+ * Returned Value: TRUE if succeeded.
+ * Local Static Variables:
+ * include_list_full_path Full Path used, if succeeded
+ * Supplied Pointers:
+ * *file_info File-statistics structure from STAT call
+ *
+ * Error Detection:
+ * Calling routine will detect and report Errors.
+ *
+ * Process Explanation:
+ * This routine will initialize and step through Include-List.
+ * Calling routine will be responsible for "finishing" the
+ * Include-List search, as well as any Advisory messages.
+ *
+ **************************************************************************** */
+
+static bool stat_incl_list_file( char *base_name, struct stat *file_info)
+{
+ bool retval = FALSE;
+ int stat_reslt = -1; /* Success = 0 */
+
+ init_incl_list_scan( base_name);
+ while ( scan_incl_list( base_name) )
+ {
+ stat_reslt = stat( include_list_full_path, file_info);
+ if ( stat_reslt == 0 )
+ {
+ retval = TRUE;
+ break;
+ }
+ }
+
+ return (retval);
+}
+
+/* **************************************************************************
+ *
+ * Function name: init_inbuf
+ * Synopsis: Set the given buffer as the current input source
+ *
+ * Inputs:
+ * Parameters:
+ * inbuf Pointer to start of new input buffer
+ * buflen Length of new input buffer
+ *
+ * Outputs:
+ * Returned Value: NONE
+ * Global Variables:
+ * start Points to given buffer
+ * end Points to end of new input buffer
+ * pc Re-initialized
+ *
+ **************************************************************************** */
+
+void init_inbuf(char *inbuf, unsigned int buflen)
+{
+ start = inbuf;
+ pc = start;
+ end = pc + buflen;
+}
+
+/* **************************************************************************
+ *
+ * Function name: could_not_open
+ * Synopsis: Report the "Could not open" Message for various Files.
+ *
+ * Inputs:
+ * Parameters:
+ * severity Severity of message, WARNING or ERROR
+ * fle_nam Name of file
+ * for_what Phrase after "... for "
+ *
+ * Outputs:
+ * Returned Value: NONE
+ * Printout:
+ * Message of indicated severity.
+ *
+ * Error Detection:
+ * Error already detected; reported here.
+ *
+ **************************************************************************** */
+
+static void could_not_open(int severity, char *fle_nam, char *for_what)
+{
+ tokenization_error( severity, "Could not open file %s for %s.\n",
+ fle_nam, for_what);
+
+}
+
+/* **************************************************************************
+ *
+ * Function name: file_is_missing
+ * Synopsis: Add the given File to the Missing-Files-List.
+ *
+ * Inputs:
+ * Parameters:
+ * fle_nam Name of file
+ * Local Static Variables:
+ * missing_list_file Missing-Files-List File Structure
+ * May be NULL if none was opened
+ *
+ * Outputs:
+ * Returned Value: NONE
+ * Local Static Variables:
+ * no_files_missing Set FALSE
+ * File Output:
+ * Write File name to Missing-Files-List (if one was opened)
+ *
+ * Error Detection:
+ * Error already detected; reported here.
+ *
+ **************************************************************************** */
+
+static void file_is_missing( char *fle_nam)
+{
+ if ( missing_list_file != NULL )
+ {
+ fprintf( missing_list_file, "%s\n", fle_nam);
+ no_files_missing = FALSE;
+ }
+}
+
+/* **************************************************************************
+ *
+ * Function name: add_to_load_lists
+ * Synopsis: Add the given input file-name to the Load-List File,
+ * and the Full File path to the Dependency-List File.
+ *
+ * Inputs:
+ * Parameters:
+ * in_name Name of given input Source File
+ * Local Static Variables:
+ * load_list_file Load List File Structure pointer
+ * depncy_file Dependency-List File Structure ptr
+ * Either may be NULL if the file was not opened.
+ * include_list_full_path Full Path to where the file was found.
+ *
+ * Outputs:
+ * Returned Value: NONE
+ * File Output:
+ * Write given file-name to Load-List file (if one was opened)
+ * Write File Path to Dependency-List file (if one was opened)
+ *
+ * Process Explanation:
+ * Write into the Load-List file the input Source Filename in the
+ * same form -- i.e., unexpanded -- as was supplied by the User.
+ * Write into the Dependency-List file the full expanded path, as
+ * supplied by the program to the Host Operating System.
+ *
+ **************************************************************************** */
+
+static void add_to_load_lists( const char *in_name)
+{
+ if ( load_list_file != NULL )
+ {
+ fprintf( load_list_file, "%s\n", in_name);
+ }
+ if ( depncy_file != NULL )
+ {
+ fprintf( depncy_file, "%s\n", include_list_full_path);
+ }
+}
+
+
+/* **************************************************************************
+ *
+ * In the functions that support accessing files whose path-names
+ * contain embedded Environment-Variables, the commentaries
+ * will refer to this process, or to inputs that require it,
+ * using variants of the term "expand".
+ *
+ * We will also keep some of the relevant information as Local
+ * Static Variables.
+ *
+ **************************************************************************** */
+
+static char expansion_buffer[ 2*GET_BUF_MAX];
+static bool was_expanded;
+static int expansion_msg_severity = INFO;
+
+/* **************************************************************************
+ *
+ * Function name: expanded_name
+ * Synopsis: Advisory message to display filename expansion.
+ *
+ * Inputs:
+ * Parameters:
+ * Local Static Variables:
+ * was_expanded TRUE if expansion happened
+ * expansion_buffer Buffer with result of expansion
+ * expansion_msg_severity Whether it's an ordinary Advisory
+ * or we force a message.
+ *
+ * Outputs:
+ * Returned Value: NONE
+ *
+ * Printout:
+ * Advisory message showing expansion, if expansion happened
+ * Otherwise, nothing.
+ *
+ **************************************************************************** */
+
+static void expanded_name( void )
+{
+ if ( was_expanded )
+ {
+ tokenization_error( expansion_msg_severity,
+ "File name expanded to: %s\n", expansion_buffer);
+ }
+}
+
+
+/* **************************************************************************
+ *
+ * Function name: expansion_error
+ * Synopsis: Supplemental message to display filename expansion.
+ * Called after an expanded-filename failure was reported.
+ *
+ * Inputs:
+ * Parameters:
+ * Global Variables:
+ * verbose Set by "-v" switch
+ *
+ * Outputs:
+ * Returned Value: NONE
+ * Printout:
+ * Advisory message showing expansion, if applicable
+ * and if wasn't already shown.
+ *
+ * Error Detection:
+ * Called after Error was reported.
+ *
+ * Process Explanation:
+ * Presumptions are that:
+ * An Error message, showing the user-supplied form of the
+ * pathname is also being displayed
+ * An advisory message showing the pathname expansion may
+ * have been displayed during the expansion process,
+ * if verbose was TRUE.
+ * The purpose of this routine is to display the expansion if
+ * it had not already just been displayed, i.e., if verbose
+ * is not set to TRUE: Temporarily force the display of an
+ * Advisory message.
+ *
+ * Extraneous Remarks:
+ * If this routine is called before the Error message is displayed,
+ * the verbose and non-verbose versions of the Log-File will
+ * match up nicely...
+ *
+ **************************************************************************** */
+
+static void expansion_error( void )
+{
+ if ( INVERSE( verbose) )
+ {
+ expansion_msg_severity |= FORCE_MSG;
+ expanded_name();
+ expansion_msg_severity ^= FORCE_MSG;
+ }
+}
+
+
+/* **************************************************************************
+ *
+ * Function name: expand_pathname
+ * Synopsis: Perform the expansion of a path-name that may contain
+ * embedded Environment-Variables
+ *
+ * Inputs:
+ * Parameters:
+ * input_pathname The user-supplied filename
+ * Global/Static MACRO:
+ * GET_BUF_MAX Size of expansion buffer is twice this.
+ *
+ * Outputs:
+ * Returned Value: Pointer to expanded name, or to
+ * input if no expansion needed.
+ * NULL if error.
+ * Local Static Variables:
+ * was_expanded TRUE if expansion needed and succeeded
+ * expansion_buffer Result of expansion
+ * Printout:
+ * Advisory message showing expansion
+ * Presumption is that an Advisory giving the user-supplied
+ * pathname was already printed.
+ *
+ * Error Detection:
+ * Syntax error. System might print something; it might not be
+ * captured, even to a log-file. System failure return might
+ * be the only program-detectable indication. Display ERROR
+ * message and return NULL pointer. Calling routine will
+ * display the user-supplied pathname in its Error message
+ * indicating failure to open the file.
+ *
+ * Process Explanation:
+ * Generally speaking, we will let the Shell expand the Environment
+ * Variables embedded in the user-supplied pathname.
+ * First, though, we will see if the expansion is necessary: Look
+ * for the telltale character, '$', in the input string. If
+ * it's not there, there are no Env't-V'bles, and no expansion
+ * is necessary. Return the pointer to the input string and
+ * we're done. Otherwise.....
+ * Acquire a temporary file-name. Construct a string of the form:
+ * echo input_string > temp_file_name
+ * and then issue that string as a command to the Shell.
+ * If that string generates a system-call failure, report an ERROR.
+ * Open the temporary file and read its contents. That will be
+ * the expansion of the input string. If its length exceeds
+ * the capacity of the expansion buffer, it's another ERROR.
+ * (Of course, don't forget to delete the temporary file.)
+ * Place the null-byte marker at the end of the expanded name,
+ * trimming off the terminating new-line.
+ * Success. Display the expanded name (as an Advisory message)
+ * Return the pointer to the expansion buffer and set the flag.
+ * (Did I mention don't forget to delete the temporary file?)
+ *
+ * Extraneous Remarks:
+ * This implementation approach turned out to be the simplest and
+ * cleanest way to accomplish our purpose. It also boasts the
+ * HUGE advantage of not requiring re-invention of a well-used
+ * (proverbial) wheel. Plus, any variations allowed by the
+ * shell (e.g.,: $PWD:h ) are automatically converted, too,
+ * depending on the System shell (e.g., not for Bourne shell).
+ * In order to spare you, the maintenance programmer, unnecessary
+ * agony, I will list a few other approaches I tested, with a
+ * brief note about the results of each:
+ * (1)
+ * I actually tried parsing the input line and passing each component
+ * V'ble to the getenv() function, accumulating the results into
+ * a conversion buffer. I needed to check for every possible
+ * delimiter, and handle curly-brace enclosures. The resultant
+ * code was *UGLY* ... you'd be appalled! The only good spot was
+ * that I was able to compensate for an open-curly-brace without
+ * a corresponding close-curly-brace (if close-c-b wasn't found,
+ * resume the search for other delimiters...) which, apparently,
+ * the System does not or will not do. It was, however, too
+ * small a compensation for all the awfulness entailed overall.
+ *
+ * I tried various approaches to using the Environment-Variables to
+ * convert and retrieve the input string:
+ * (2)
+ * Create a command-string that would set an Env't V'ble to the
+ * input-string, and pass the command-string to the system() call,
+ * then retrieve the Env't V'ble thus set via getenv(). No dice;
+ * the system() call operated in a separate sub-shell and could
+ * not export its Env't upwards.
+ * (3)
+ * Use the setenv() command to set an Env't V'ble to the input-string
+ * and retrieve it via getenv(). The returned string matched the
+ * input-string without converting it.
+ * (4)
+ * Use the setenv() command to set an Env't V'ble to a string like:
+ * `echo input_string`
+ * Again, the string retrieved via getenv() exactly matched the
+ * unconverted command-string, back-quotes and all.
+ *
+ * Of course, the equivalents of (2), (3) and (4) worked as desired
+ * when tested as direct commands to the Shell. UNIX can be
+ * funny that way...
+ *
+ * Oh! Also: we will slightly stretch the rules of well-structured
+ * code.
+ *
+ **************************************************************************** */
+
+static char *expand_pathname( const char *input_pathname)
+{
+ static const int buffer_max = GET_BUF_MAX * 2;
+
+ char *retval = (char *)input_pathname;
+ was_expanded = FALSE;
+
+ /* If no '$' is found, expansion is unnecessary. */
+ if ( strchr( input_pathname, '$') != NULL )
+ {
+ FILE *temp_file;
+ int syst_stat;
+ const char *temp_file_name = tmpnam( NULL);
+
+ /* Use the expansion buffer for our temporary command string */
+ sprintf( expansion_buffer,
+ "echo %s>%s\n", input_pathname, temp_file_name);
+ syst_stat = system( expansion_buffer);
+ if ( syst_stat != 0 )
+ {
+ tokenization_error( TKERROR,
+ "Expansion Syntax.\n");
+ /* The "File-Opening" error message will show the input string */
+ return( NULL);
+ }
+
+ temp_file = fopen( temp_file_name, "r"); /* Cannot fail. */
+ syst_stat = fread( expansion_buffer, 1, buffer_max, temp_file);
+ /* Error test. Length of what we read is not a good indicator;
+ * it's limited anyway by buffer_max.
+ * Valid test is if last character read was the new-line.
+ */
+ if ( expansion_buffer[syst_stat-1] != '\n' )
+ {
+ tokenization_error( TKERROR,
+ "Expansion buffer overflow. Max length is %d.\n",
+ buffer_max);
+ retval = NULL;
+ }else{
+ expansion_buffer[syst_stat-1] =0;
+ was_expanded = TRUE;
+ retval = expansion_buffer;
+ expanded_name();
+ }
+
+ fclose( temp_file);
+ remove( temp_file_name);
+ }
+
+ return( retval);
+}
+
+/* **************************************************************************
+ *
+ * Function name: open_expanded_file
+ * Synopsis: Open a file, expanding Environment-Variables that
+ * may be embedded in the given path-name.
+ *
+ * Inputs:
+ * Parameters:
+ * path_name The user-supplied path-name
+ * mode Mode-string to use; usually "r" or "rb"
+ * for_what Phrase to use in Messages
+ *
+ * Outputs:
+ * Returned Value: Pointer to FILE structure; NULL if failed
+ * Local Static Variables:
+ * was_expanded TRUE if expansion happened
+ * expansion_buffer Result of expansion
+ * Printout:
+ * Advisory message showing expansion
+ *
+ * Error Detection:
+ * If expansion or system-call for file-open failed,
+ * report Error and return NULL.
+ *
+ **************************************************************************** */
+
+FILE *open_expanded_file( const char *path_name, char *mode, char *for_what)
+{
+
+ FILE *retval = NULL;
+
+ char *infile_name = expand_pathname( path_name);
+ if ( infile_name != NULL )
+ {
+ retval = open_incl_list_file( infile_name, mode);
+ }
+
+ if ( retval == NULL )
+ {
+ expansion_error();
+ tokenization_error ( TKERROR,
+ "Failed to open file %s for %s\n", path_name, for_what );
+ }
+
+ finish_incl_list_scan( BOOLVAL( retval != NULL) );
+
+ return( retval);
+}
+
+/* **************************************************************************
+ *
+ * Function name: init_stream
+ * Synopsis: Open a file and make it the current source.
+ * This is called, not only at the start of tokenization,
+ * but also when a subsidiary file is FLOADed.
+ *
+ * Inputs:
+ * Parameters:
+ * name Name of the new Input File to open
+ * May be path-name containing
+ * embedded Environment-Variables.
+ * Global Variables:
+ * oname NULL if opening Primary Input File
+ * Local Static Variables:
+ * include_list_full_path Full Path to where the file was found
+ *
+ * Outputs:
+ * Returned Value: TRUE = opened and read file successfully
+ * Global Variables (Only changed if successful):
+ * iname Set to new Input File name
+ * lineno Re-initialized to 1
+ * Local Static Variables:
+ * no_files_missing Set FALSE if couldn't read input file
+ * include_list_full_path Retains full-path if file opened was
+ * the Primary Input File (as contrasted with an FLoaded
+ * Source file), in which case a call to init_output()
+ * is expected; the Full-Path Buffer will be freed there.
+ * Memory Allocated
+ * Duplicate of Input File name (becomes iname )
+ * A fresh input buffer; input file is copied to it.
+ * Becomes start by action of call to init_inbuf().
+ * When Freed?
+ * By close_stream()
+ * File Output:
+ * Write new Input File name to Load-List file.
+ * Writing to Missing-Files-List File if failure,
+ * or Full File path to Dependency-List File,
+ * is handled by called routine.
+ * Other Exotic Effects:
+ * Force a flush of stdout before printing ERROR messages
+ *
+ * Error Detection:
+ * Failure to open or read Input file: ERROR; suppress output;
+ * write Input File name to Missing-Files-List File.
+ *
+ * Process Explanation:
+ * Free local buffer on failure.
+ * Caller should only invoke close_stream() if this call succeeded.
+ * Some filesystems use zeros for new-line; we need to convert
+ * those zeros to line-feeds.
+ * Similarly for files that have carr-ret/line-feed; the carr-ret
+ * will cause havoc; replace it w/ a space.
+ *
+ * Revision History:
+ * Updated Thu, 07 Apr 2005 by David L. Paktor
+ * Restructured. If opened file, close it, even if can't read it.
+ * Return TRUE on success.
+ * Caller examines return value.
+ * Updated Wed, 13 Jul 2005 by David L. Paktor
+ * Replace carr-rets with spaces.
+ * Updated Sun, 27 Nov 2005 by David L. Paktor
+ * Write new Input File name to Load-List file.
+ * Updated Tue, 31 Jan 2006 by David L. Paktor
+ * Add support for embedded Environment-Variables in path name
+ * Updated Thu, 16 Feb 2006 David L. Paktor
+ * Collect missing (inaccessible) filenames
+ * Updated Fri, 17 Mar 2006 David L. O'Paktor
+ * Add support for Include-List search
+ *
+ * Still to be done:
+ * Set a flag when carr-ret has been replaced by space;
+ * when a string crosses a line, if this flag is set,
+ * issue a warning that an extra space has been inserted.
+ *
+ **************************************************************************** */
+
+bool init_stream( const char *name)
+{
+ FILE *infile;
+ u8 *newbuf;
struct stat finfo;
+ bool stat_succ = FALSE;
+ bool tried_stat = FALSE;
+ bool retval = FALSE;
+ bool inp_fil_acc_err = FALSE;
+ bool inp_fil_open_err = FALSE;
+ bool inp_fil_read_err = FALSE;
+
+ char *infile_name = expand_pathname( name);
+
+ if ( (infile_name != NULL) )
+ {
+ tried_stat = TRUE;
+ stat_succ = stat_incl_list_file( infile_name, &finfo);
+ }
+
+ if ( INVERSE( stat_succ) )
+ {
+ inp_fil_acc_err = TRUE;
+ }else{
- if (stat(name,&finfo))
- return -1;
+ infile = fopen( include_list_full_path, "r");
+ if ( infile == NULL )
+ {
+ inp_fil_open_err = TRUE;
+ }else{
ilen=finfo.st_size;
- start=malloc(ilen+1);
- if (!start)
- return -1;
+ newbuf = safe_malloc(ilen+1, "initting stream");
- infile=fopen(name,"r");
- if (!infile)
- return -1;
+ if ( fread( newbuf, ilen, 1, infile) != 1 )
+ {
+ inp_fil_read_err = TRUE;
+ free( newbuf );
+ } else {
+ unsigned int i;
- if (fread(start, ilen, 1, infile)!=1) {
- free(start);
- return -1;
+ retval = TRUE ;
+ /* Replace zeroes in the file with LineFeeds. */
+ /* Replace carr-rets with spaces. */
+ for (i=0; i<ilen; i++)
+ {
+ char test_c = newbuf[i];
+ if ( test_c == 0 ) newbuf[i] = 0x0a;
+ if ( test_c == 0x0d ) newbuf[i] = ' ';
}
+ newbuf[ilen]=0;
+ init_inbuf(newbuf, ilen);
+
+ /* If the -l option was specified, write the name of the
+ * new input-file to the Load-List file... UNLESS
+ * this is the first time through and we haven't yet
+ * opened the Load-List file, in which case we'll
+ * just open it here and wait until we create the
+ * output-file name (since the Load-List file name
+ * depends on the output-file name anyway) before
+ * we write the initial input-file name to it.
+ */
+ /* Looking for the option-flag _and_ for a non-NULL value
+ * of the file-structure pointer is redundandundant:
+ * The non-NULL pointer is sufficient, once the List
+ * File has been created...
+ */
+ /* Same thing applies if the -P option was specified,
+ * for the Dependency-List file, except there we'll
+ * write the full path to where the file was found.
+ */
+ /* We have a routine to do both of those. */
+ add_to_load_lists( name);
+ /*
+ * And... there's one slight complication: If this is
+ * the first time through, (i.e., we're opening the
+ * Primary Input File) then we haven't yet opened the
+ * Dependency-List file, and we need to preserve the
+ * Full file-name Buffer until the call to init_output()
+ * where the include-list scan will be "finish"ed.
+ * Actually, we want to postpone "finish"ing the inc-l scan
+ * for several reasons beyond the Dependency-List file,
+ * such as completing the File Name Announcement first.
+ * A NULL output-name buffer is our indicator.
+ */
+ if ( oname == NULL )
+ {
+ /* Quick way to suppress "finish"ing the i-l scan */
+ tried_stat = FALSE;
+ }
+ }
fclose(infile);
+ }
+ }
- /* no zeroes within the file. */
- for (i=0; i<ilen; i++) {
- /* start[i]=start[i]?start[i]:0x0a; */
- start[i] |= (((signed char)start[i] - 1) >> 7) & 0x0a;
+ FFLUSH_STDOUT /* Do this first */
+ /* Now we can deliver our postponed error and advisory messages */
+ if ( INVERSE( retval) )
+ {
+ file_is_missing( (char *)name);
+ if ( inp_fil_acc_err )
+ {
+ expansion_error();
+ tokenization_error( TKERROR,
+ "Could not access input file %s\n", name);
+ }else{
+ if ( inp_fil_open_err )
+ {
+ expansion_error();
+ could_not_open( TKERROR, (char *)name, "input");
+ }else{
+ if ( inp_fil_read_err )
+ {
+ expansion_error();
+ tokenization_error( TKERROR,
+ "Could not read input file %s\n", name);
+ }
+ }
}
- start[ilen]=0;
+ }
- pc=start;
- end=pc+ilen;
+ if ( tried_stat )
+ {
+ finish_incl_list_scan( stat_succ);
+ }
+ /* Don't change the input file name and line-number until after
+ * the Advisory showing where the file was found.
+ */
+ if ( retval )
+ {
iname=strdup(name);
-
lineno=1;
+ }
- return 0;
+ return ( retval );
}
-int init_output( const char *in_name, const char *out_name )
+/* **************************************************************************
+ *
+ * Function name: extend_filename
+ * Synopsis: Change the filename to the given extension
+ *
+ * Inputs:
+ * Parameters:
+ * base_name Name of the Input Base File
+ * new_ext New ext'n (with leading period)
+ *
+ * Outputs:
+ * Returned Value: Result filename
+ * Memory Allocated
+ * Buffer for result filename
+ * When Freed?
+ * At end of Tokenization, by close_output().
+ *
+ * Process Explanation:
+ * If the Input Base File Name has an extension, it will be replaced
+ * with the given new extension. If not, the new extension will
+ * simply be appended.
+ * If the Input Base File Name has an extension that matches the
+ * new extension, a duplicate of the extension will be appended.
+ *
+ * Extraneous Remarks:
+ * I only recently added protection against the situation where the
+ * Input Base File Name has no extension, but the Directory Path
+ * leading to it has a period in one of the directory names.
+ * Granted, this is a rare case, but not altogether impossible;
+ * I would have done it earlier except for the fact that the
+ * separator between directories may vary with different Host
+ * Operating Systems.
+ * However, at this point we have UNIX-centric assumptions hard-
+ * -coded in to so many other places that we might as well
+ * go with the slash here too.
+ *
+ **************************************************************************** */
+
+static char *extend_filename( const char *base_name, const char *new_ext)
{
- const char *ext;
+ char *retval;
+ char *ext;
unsigned int len; /* should this be size_t? */
+ const char *root;
+ root = strrchr(base_name, '/');
+ if ( root == NULL ) root = base_name;
+
+ ext = strrchr(root, '.');
+ if ( ext != NULL )
+ {
+ if ( strcasecmp(ext, new_ext) == 0 )
+ {
+ ext = NULL;
+ }
+ }
+
+ len = ext ? (ext - base_name) : (unsigned int)strlen(base_name) ;
+ retval = safe_malloc(len+strlen(new_ext)+1, "extending file-name");
+ memcpy( retval, base_name, len);
+ retval[len] = 0;
+ strcat(retval, new_ext);
+
+ return( retval);
+}
+
+/* **************************************************************************
+ *
+ * Function name: init_output
+ * Synopsis: After the Input Source File has been opened, assign
+ * the name for the Binary Output File; initialize
+ * the FCode Output Buffer; assign names for the
+ * FLoad List, Dependency-List, and Missing-Files
+ * List files; open them and write their first
+ * entries to them.
+ * Announce the Input and various output file names.
+ *
+ * Inputs:
+ * Parameters:
+ * in_name Name of the Input Source File
+ * out_name Name of the Binary Output File, if
+ * specified on the Command Line,
+ * or NULL if not.
+ * Global Variables:
+ * fload_list Whether to create an FLoad-List file
+ * dependency_list Whether to create a Dependency-List file
+ * Local Static Variables:
+ * include_list_full_path Full Path to the Input Source File;
+ * should still be valid from opening
+ * of Primary Source Input file, for
+ * first entry to Dependency-List file.
+ *
+ * Outputs:
+ * Returned Value: NONE
+ * Global Variables:
+ * oname Binary Output File Name
+ * ostart Start of FCode Output Buffer
+ * opc FCode Output Buffer Position Counter
+ * abs_token_no Initialized to 1
+ * Local Static Variables:
+ * load_list_name Name of the Load List File
+ * load_list_file FLoad List File Structure pointer
+ * depncy_list_name Name of the Dependency List File ptr
+ * depncy_file Dependency List File Structure
+ * missing_list_name Name of the Missing-Files-List File
+ * missing_list_file Missing-Files-List File Structure
+ * no_files_missing Initialized to TRUE
+ * Memory Allocated
+ * Binary Output File Name Buffer
+ * FCode Output Buffer
+ * FLoad List File Name Buffer
+ * Dependency List File Name Buffer
+ *
+ * When Freed?
+ * In close_output()
+ * File Output:
+ * FLoad List or Dependency List files are opened (if specified).
+ * Primary Source Input file name and path, respectively,
+ * are written as the first entry to each.
+ * Printout:
+ * (Announcement of input file name has already been made)
+ * Announce binary output, fload- and dependency- -list file names
+ *
+ * Error Detection:
+ * Failure to open FLoad List or Dependency List file: ERROR;
+ * suppress binary output. Further attempts to write to
+ * FLoad List or Dependency List files are prevented by
+ * the respective FILE_structure pointers being NULL.
+ * Failure to open Missing-Files-List file: WARNING
+ *
+ * Process Explanation:
+ * If no Output File Name was specified on the Command Line, the
+ * name of the Binary (FCode) Output File will be derived
+ * from the name of the Input File by replacing its extension
+ * with .fc , or, if the Input File had no extension, by
+ * merely appending the extension .fc
+ * In the odd case where the Input File name has an extension
+ * of .fc, we will merely append another .fc extension.
+ * If fload_list is TRUE (i.e., the "-l" option was specified on
+ * the command-line, the FLoad List File name will be derived
+ * from the name of the Output File by the same rules, only with
+ * an extension of .fl Open the FLoad List File. Write the
+ * name of the initial input file to the FLoad List File.
+ * Similarly if the "-P" command-line option was specified, the name
+ * of the Dependency List File will be derived with an extension
+ * of .P Open it and write the Full Path for the initial input
+ * file to it. NOTE: To do that, we need to have preserved the
+ * Full Path-name Buffer from the call to init_stream() We
+ * will "finish" it here, after we've used it.
+ * The Missing-Files-List File will be created if either option was
+ * specified. Its name will be derived similarly, with an
+ * extension of .fl.missing
+ *
+ **************************************************************************** */
+
+void init_output( const char *in_name, const char *out_name )
+{
/* preparing output */
- if( out_name )
- oname = (u8 *)strdup( out_name );
- else {
- ext=strrchr(in_name, '.');
- len=ext ? (unsigned int)(ext-in_name) : (unsigned int)strlen(in_name) ;
- oname=malloc(len+4);
- memcpy(oname, in_name, len);
- oname[len] = 0;
- strcat((char *)oname, ".fc");
+ if( out_name != NULL )
+ {
+ oname = strdup( out_name );
+ }else{
+ oname = extend_filename( in_name, ".fc");
}
/* output buffer size. this is 128k per default now, but we
* could reallocate if we run out. KISS for now.
*/
- ostart=malloc(OUTPUT_SIZE);
- if (!ostart) {
- free(oname);
- free(start);
- return -1;
+ olen = OUTPUT_SIZE;
+ ostart=safe_malloc(olen, "initting output buffer");
+
+ opc = 0;
+ init_emit(); /* Init'l'zns needed by our companion file, emit.c */
+
+ printf("Binary output to %s ", oname);
+ if ( fload_list )
+ {
+ load_list_name = extend_filename( oname, ".fl");
+ load_list_file = fopen( load_list_name,"w");
+ printf(" FLoad-list to %s ", load_list_name);
}
+ if ( dependency_list )
+ {
+ depncy_list_name = extend_filename( oname, ".P");
+ depncy_file = fopen( depncy_list_name,"w");
+ printf(" Dependency-list to %s ", depncy_list_name);
+ }
+ printf("\n");
- opc=oend=ostart;
- oend+=OUTPUT_SIZE;
+ add_to_load_lists( in_name);
- /* We're beginning a new output file, so we have to
- * start our own fcode numbers at 0x800 again.
- */
- nextfcode=0x800;
+ /* Let's avoid collisions between stdout and stderr */
+ FFLUSH_STDOUT
+
+ /* Now we can deliver our advisory and error messages */
- return 0;
+ {
+ /* Suspend showing filename in advisory and error messages. */
+ char *temp_iname = iname;
+ iname = NULL;
+
+ finish_incl_list_scan( TRUE);
+
+ if ( fload_list && (load_list_file == NULL) )
+ {
+ could_not_open( TKERROR, load_list_name, "Load-List");
+ free( load_list_name);
+ }
+ if ( dependency_list && (depncy_file == NULL) )
+ {
+ could_not_open( TKERROR, depncy_list_name,
+ "Dependency-List");
+ free( depncy_list_name);
}
-int close_stream(void)
+ if ( fload_list || dependency_list )
+ {
+ missing_list_name = extend_filename( oname, ".fl.missing");
+ missing_list_file = fopen( missing_list_name,"w");
+ no_files_missing = TRUE;
+
+ if ( missing_list_file == NULL )
+ {
+ could_not_open( WARNING, missing_list_name,
+ "Missing-Files List" );
+ free( missing_list_name);
+ }
+ }
+ iname = temp_iname;
+ }
+ abs_token_no = 1;
+}
+
+/* **************************************************************************
+ *
+ * Function name: increase_output_buffer
+ * Synopsis: Reallocate the Output Buffer to double its prior size
+ *
+ * Inputs:
+ * Parameters: NONE
+ * Global Variables:
+ * ostart Start-address of current Output Buffer
+ * olen Current size of the Output Buffer
+ * Local Static Variables:
+ *
+ * Outputs:
+ * Returned Value: NONE
+ * Local Static Variables:
+ * olen Doubled from value at input
+ * ostart Start-address of new Output Buffer
+ * Memory Allocated
+ * A new FCode Output Buffer, using the realloc() facility.
+ * When Freed?
+ * In close_output()
+ * Memory Freed
+ * Former FCode Output Buffer, also by means of realloc()
+ *
+ * Printout:
+ * Advisory message that this is taking place.
+ *
+ * Error Detection:
+ * FATAL if realloc() fails.
+ * FATAL if output buffer has been expanded to a size beyond
+ * what an INT can express. Unlikely? maybe; impossible? no...
+ *
+ * Process Explanation:
+ * Because we are allowing the Output Buffer to be relocated, we
+ * must take care to limit the exposure to external routines
+ * of its actual address. All references to locations within
+ * the Output Buffer should be made in terms of an _offset_.
+ *
+ * Extraneous Remarks:
+ * Unfortunately, it is not feasible to completely isolate the
+ * actual address of the Output Buffer, but we will keep the
+ * exposure limited to the routines in emit.c
+ * Similarly, it wasn't feasible to keep this routine isolated,
+ * nor the variable olen , but we will limit their exposure.
+ *
+ **************************************************************************** */
+void increase_output_buffer( void ); /* Keep the prototype local */
+void increase_output_buffer( void )
{
+ u8 *newout;
+
+ if ( olen == 0 )
+ {
+ tokenization_error( FATAL,
+ "Output Buffer reallocation overflow.");
+ }else{
+ unsigned int rea_len;
+ olen = olen * 2;
+ rea_len = olen;
+ if ( rea_len == 0 ) rea_len = (unsigned int)-1;
+ tokenization_error( INFO,
+ "Output Buffer overflow. "
+ "Relocating and increasing to %d bytes.\n", rea_len);
+
+ newout = realloc(ostart, rea_len);
+ if ( newout == NULL)
+ {
+ tokenization_error( FATAL,
+ "Could not reallocate %d bytes for Output Buffer", rea_len);
+ }
+
+ ostart = newout;
+ }
+}
+
+
+/* **************************************************************************
+ *
+ * Function name: close_stream
+ * Synopsis: Free-up the memory used for the current input file
+ * whenever it is closed. Reset pointers and
+ * line-counter. Close files as necessary.
+ *
+ * The dummy parameter is there to accommodate Macro-recursion protection.
+ * It's a long story; don't get me started...
+ *
+ **************************************************************************** */
+
+void close_stream( _PTR dummy)
+{
free(start);
free(iname);
- return 0;
+ start = NULL;
+ iname = NULL;
+ lineno = 0;
}
-int close_output(void)
+/* **************************************************************************
+ *
+ * Function name: close_output
+ * Synopsis: Write the Binary Output file, if appropriate.
+ * Return a "Failure" flag.
+ *
+ **************************************************************************** */
+
+
+bool close_output(void)
{
+ bool retval = TRUE; /* "Failure" */
+ if ( error_summary() )
+ {
+ if ( opc == 0 )
+{
+ retval = FALSE; /* "Not a problem" */
+ }else{
FILE *outfile;
- unsigned int len;
- len=(unsigned long)opc-(unsigned long)ostart;
+ outfile=fopen( oname,"w");
+ if (!outfile)
+ {
+ /* Don't do this as a tokenization_error( TKERROR
+ * because those are all counted, among other reasons...
+ */
+ printf( "Could not open file %s for output.\n", oname);
+ }else{
- outfile=fopen((char *)oname,"w");
- if (!outfile) {
- printf("toke: error opening output file.\n");
- return -1;
+ if ( fwrite(ostart, opc, 1, outfile) != 1 )
+ {
+ tokenization_error( FATAL, "While writing output.");
}
- if(fwrite(ostart, len, 1, outfile)!=1)
- printf ("toke: error while writing output.\n");
-
fclose(outfile);
- printf("toke: wrote %d bytes to bytecode file '%s'\n", len, oname);
+ printf("toke: wrote %d bytes to bytecode file '%s'\n",
+ opc, oname);
+ retval = FALSE; /* "No problem" */
+ }
+ }
+ }
free(oname);
- return 0;
+ free(ostart);
+ oname = NULL;
+ ostart = NULL;
+ opc = 0;
+ olen = OUTPUT_SIZE;
+
+ if ( load_list_file != NULL )
+ {
+ fclose(load_list_file);
+ free(load_list_name);
+ }
+ if ( depncy_file != NULL )
+ {
+ fclose(depncy_file);
+ free(depncy_list_name);
+ }
+ if ( missing_list_file != NULL )
+ {
+ fclose( missing_list_file);
+ if ( no_files_missing )
+ {
+ remove( missing_list_name);
+ }
+ free( missing_list_name);
+ }
+
+ load_list_file = NULL;
+ load_list_name = NULL;
+ missing_list_file = NULL;
+ missing_list_name = NULL;
+ depncy_file = NULL;
+ depncy_list_name = NULL;
+
+ return ( retval );
}
Modified: fcode-utils/toke/stream.h
===================================================================
--- fcode-utils/toke/stream.h 2006-08-18 09:45:11 UTC (rev 75)
+++ fcode-utils/toke/stream.h 2006-08-18 12:47:12 UTC (rev 76)
@@ -1,3 +1,6 @@
+#ifndef _H_STREAM
+#define _H_STREAM
+
/*
* OpenBIOS - free your system!
* ( FCode tokenizer )
@@ -24,15 +27,68 @@
*
*/
-#ifndef _H_STREAM
-#define _H_STREAM
+/* **************************************************************************
+ * Modifications made in 2005 by IBM Corporation
+ * (C) Copyright 2005 IBM Corporation. All Rights Reserved.
+ * Modifications Author: David L. Paktor dlpaktor(a)us.ibm.com
+ **************************************************************************** */
-int init_stream( const char *name );
-int close_stream(void);
-int init_output( const char *inname, const char *outname );
-int close_output(void);
+#include "types.h"
-extern unsigned int lineno;
+/* **************************************************************************
+ *
+ * Exported Global Variables
+ *
+ **************************************************************************** */
+
+/* input pointers */
+extern u8 *start;
+extern u8 *pc;
+extern u8 *end;
extern char *iname;
+extern unsigned int lineno; /* Line Number within current input file */
+extern unsigned int abs_token_no; /* Absolute Token Number in Source Input */
+/* output pointers */
+extern char *oname; /* output file name */
+
+extern unsigned int opc; /* output buffer position counter */
+
+/* **************************************************************************
+ *
+ * Note that the variables ostart and olen , as well as the routine
+ * increase_output_buffer are not listed here.
+ *
+ * We would have preferred to isolate them completely, but we would have
+ * to disrupt the organization of emit.c (which we'd rather not);
+ * in order to avoid exporting them any more widely than necessary,
+ * we will declare them extern only in the file where they are
+ * unavoidably needed.
+ *
+ **************************************************************************** */
+
+/* **************************************************************************
+ * Macro Name: OUTPUT_SIZE
+ * Initial size of the Output Buffer
+ *
+ **************************************************************************** */
+
+#define OUTPUT_SIZE 131072
+
+
+/* **************************************************************************
+ *
+ * Exported Functions
+ *
+ **************************************************************************** */
+
+void add_to_include_list( char *dir_compt);
+void display_include_list( void);
+FILE *open_expanded_file( const char *path_name, char *mode, char *for_what);
+bool init_stream( const char *name );
+void close_stream( _PTR dummy);
+void init_output( const char *inname, const char *outname );
+bool close_output(void);
+void init_inbuf(char *inbuf, unsigned int buflen);
+
#endif /* _H_STREAM */
Added: fcode-utils/toke/strsubvocab.c
===================================================================
--- fcode-utils/toke/strsubvocab.c (rev 0)
+++ fcode-utils/toke/strsubvocab.c 2006-08-18 12:47:12 UTC (rev 76)
@@ -0,0 +1,337 @@
+/*
+ * OpenBIOS - free your system!
+ * ( FCode tokenizer )
+ *
+ * This program is part of a free implementation of the IEEE 1275-1994
+ * Standard for Boot (Initialization Configuration) Firmware.
+ *
+ * Copyright (C) 2001-2005 Stefan Reinauer, <stepan(a)openbios.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA, 02110-1301 USA
+ *
+ */
+
+/* **************************************************************************
+ *
+ * General-purpose support functions for
+ * String-Substitution-type vocabularies
+ *
+ * (C) Copyright 2005 IBM Corporation. All Rights Reserved.
+ * Module Author: David L. Paktor dlpaktor(a)us.ibm.com
+ *
+ **************************************************************************** */
+
+/* **************************************************************************
+ *
+ * A String-Substitution vocabulary, as the name implies, is one in
+ * in which each an entry consists of two strings; one that is
+ * sought, and one that is returned as a substitute. Macros and
+ * aliases are implemented this way, as are also user-supplied
+ * command-line symbol definitions.
+ *
+ **************************************************************************** */
+
+/* **************************************************************************
+ *
+ * Functions Exported:
+ * init_str_sub_vocab Initialize a String-Substitution vocab
+ * add_str_sub_entry Add an entry to a Str-Subst vocab
+ * lookup_str_sub Look for a name in a String-Substitution
+ * vocab, return the substitution string.
+ * exists_in_str_sub Confirm whether a given name exists in a
+ * String-Substitution vocabulary
+ * create_str_sub_alias Duplicate the behavior of one name with
+ * another name. Return a "success" flag.
+ * reset_str_sub_vocab Reset a given Str-Subst vocab to its initial
+ * "Built-In" position.
+ *
+ *
+ **************************************************************************** */
+
+#include <stdio.h>
+#include <stdlib.h>
+#if defined(__linux__) && ! defined(__USE_BSD)
+#define __USE_BSD
+#endif
+#include <string.h>
+
+#include "errhandler.h"
+#include "strsubvocab.h"
+
+
+/* **************************************************************************
+ *
+ * Function name: init_str_sub_vocab
+ * Synopsis: Dynamically initialize the link-pointers
+ * of the.given String-Substitution vocabulary
+ *
+ * Inputs:
+ * Parameters:
+ * str_sub_vocab_tbl Pointer to the initial Str-Subst vocab array
+ * max_indx Maximum Index of the initial array.
+ *
+ * Outputs:
+ * Returned Value: None
+ * Global Variables:
+ * The link-fields of the initial Str-Subs vocab array entries
+ * will be filled in.
+ *
+ **************************************************************************** */
+
+void init_str_sub_vocab( str_sub_vocab_t *str_sub_vocab_tbl, int max_indx)
+{
+ int indx;
+ for ( indx = 1 ; indx < max_indx ; indx++ )
+ {
+ str_sub_vocab_tbl[indx].next = &str_sub_vocab_tbl[indx-1];
+ }
+}
+
+/* **************************************************************************
+ *
+ * Function name: add_str_sub_entry
+ * Synopsis: Add an entry to the given Str-Subst vocab
+ *
+ * Inputs:
+ * Parameters: Pointer to:
+ * ename space containing the name of the entry
+ * subst_str space containing the substitution string
+ * *str_sub_vocab the "tail" of the Str-Subst vocab-list
+ *
+ * Outputs:
+ * Returned Value: NONE
+ * Supplied Pointers:
+ * *str_sub_vocab Will point to new entry
+ * Memory Allocated:
+ * Memory for the new entry will be allocated.
+ * When Freed?
+ * When reset_str_sub_vocab() is applied to the same vocab-list.
+ * In some instances, the new entry will be freed upon end
+ * of tokenization; in others, only on termination of program.
+ *
+ * Error Detection:
+ * Failure to allocate memory is a Fatal Error.
+ *
+ * Process Explanation:
+ * The name and substitution-string pointers are presumed to already
+ * point to stable memory-spaces. Memory will be allocated
+ * for the entry itself; its pointers will be entered and the
+ * given pointer-to-the-tail-of-the-vocabulary will be updated.
+ *
+ * Extraneous Remarks:
+ * This might have been where we would have checked for re-aliasing,
+ * but the introduction of the approach to aliasing embodied in
+ * the various create_..._alias() routines neatly bypasses it.
+ *
+ **************************************************************************** */
+
+void add_str_sub_entry( char *ename,
+ char *subst_str,
+ str_sub_vocab_t **str_sub_vocab )
+{
+ str_sub_vocab_t *new_entry;
+
+ new_entry = safe_malloc(sizeof(str_sub_vocab_t), "adding str_sub_entry");
+ new_entry->name = ename;
+ new_entry->alias = subst_str;
+ new_entry->next = *str_sub_vocab;
+
+ *str_sub_vocab = new_entry;
+
+}
+
+
+/* **************************************************************************
+ *
+ * Function name: lookup_str_sub
+ * Synopsis: Look for a name in the given Str-Subst vocabulary
+ *
+ * Inputs:
+ * Parameters:
+ * tname The "target" name for which to look
+ * str_sub_vocab The Str-Subst vocab-list
+ *
+ * Outputs:
+ * Returned Value: Pointer to the substitution string, or
+ * NULL pointer if name not found.
+ * May be NULL if subst'n string is NULL.
+ *
+ **************************************************************************** */
+
+char *lookup_str_sub( char *tname, str_sub_vocab_t *str_sub_vocab )
+{
+ str_sub_vocab_t *curr;
+ char *retval = NULL;
+
+ for (curr = str_sub_vocab ; curr != NULL ; curr=curr->next)
+ {
+ if ( strcasecmp(tname, curr->name) == 0 )
+ {
+ retval = curr->alias;
+ break;
+ }
+ }
+ return ( retval ) ;
+}
+
+/* **************************************************************************
+ *
+ * Function name: exists_in_str_sub
+ * Synopsis: Confirm whether a given name exists in a given
+ * String-Substitution vocabulary
+ *
+ * Inputs:
+ * Parameters:
+ * tname The "target" name for which to look
+ * str_sub_vocab Pointer to the Str-Subst vocab-list
+ *
+ * Outputs:
+ * Returned Value: TRUE if the name is found
+ *
+ * Extraneous Remarks:
+ * Because the Returned Value of lookup_str_sub() may be NULL for
+ * other reasons than that the name was not found, we cannot
+ * rely on that routine, and must replicate the outer-shell
+ * of its structure.
+ *
+ **************************************************************************** */
+
+bool exists_in_str_sub( char *tname, str_sub_vocab_t *str_sub_vocab )
+{
+ str_sub_vocab_t *curr;
+ bool retval = FALSE;
+
+ for (curr = str_sub_vocab ; curr != NULL ; curr=curr->next)
+ {
+ if ( strcasecmp(tname, curr->name) == 0 )
+ {
+ retval = TRUE;
+ break;
+ }
+ }
+ return ( retval );
+
+}
+
+/* **************************************************************************
+ *
+ * Function name: create_str_sub_alias
+ * Synopsis: Create an Alias in a String-Substitution vocabulary
+ * Return a "success" flag.
+ *
+ * Associated FORTH word: ALIAS
+ *
+ * Inputs:
+ * Parameters:
+ * old_name Name of existing entry
+ * new_name New name for which to create an entry
+ * *str_sub_vocab Pointer to "tail" of Str-Subst vocab-list
+ *
+ * Outputs:
+ * Returned Value: TRUE if old_name found in str_sub_vocab
+ * Supplied Pointers:
+ * *str_sub_vocab Will be updated to point to the new entry
+ * Memory Allocated:
+ * A copy of the "old" name's substitution string.
+ * When Freed?
+ * When reset_str_sub_vocab() is applied to the same vocab-list.
+ * In some instances, the new entry will be freed when the
+ * device-node in which it was created is "finish"ed; in
+ * others, only on termination of the program.
+ *
+ * Process Explanation:
+ * The "new" name is presumed to point to a stable memory-space.
+ * If the given "old" name exists in the given Str-Subst vocab-list,
+ * duplicate the substitution string into newly-allocated memory
+ * and pass the duplicated string and the "new" name along to
+ * the add_str_sub_entry() routine and return TRUE.
+ * If the given "old" name does not exist in the given vocab-list,
+ * return FALSE.
+ *
+ * Extraneous Remarks:
+ * This neatly bypasses the question of re-aliasing... ;-)
+ *
+ * We can rely on testing for a returned NULL from lookup_str_sub()
+ * because we won't be applying this routine to any vocabulary
+ * that permits a NULL in its substitution string.
+ *
+ **************************************************************************** */
+
+bool create_str_sub_alias(char *new_name,
+ char *old_name,
+ str_sub_vocab_t **str_sub_vocab )
+{
+ bool retval = FALSE;
+ char *old_subst_str = lookup_str_sub( old_name, *str_sub_vocab );
+ if ( old_subst_str != NULL )
+ {
+ char *new_subst_str = strdup(old_subst_str );
+ add_str_sub_entry(new_name, new_subst_str, str_sub_vocab );
+ retval = TRUE ;
+ }
+
+ return ( retval );
+}
+
+
+/* **************************************************************************
+ *
+ * Function name: reset_str_sub_vocab
+ * Synopsis: Reset a given Str-Subst vocab to its initial
+ * "Built-In" position.
+ *
+ * Inputs:
+ * Parameters:
+ * *str_sub_vocab Pointer to the Str-Subst vocab-list
+ * reset_position Position to which to reset the list
+ *
+ * Outputs:
+ * Returned Value: NONE
+ * Supplied Pointers:
+ * *str_sub_vocab Reset to given "Built-In" position.
+ * Memory Freed
+ * All memory allocated by user-definitions will be freed
+ *
+ * Process Explanation:
+ * The "stable memory-spaces" to which the name and substitution
+ * string pointers point are presumed to have been acquired
+ * by allocation of memory, which is reasonable for entries
+ * created by the user as opposed to the built-in entries,
+ * which we are, in any case, not releasing.
+ * The substitution-string pointer may be null; watch out when
+ * we free() it; not all C implementations forgive that.
+ *
+ **************************************************************************** */
+
+void reset_str_sub_vocab(
+ str_sub_vocab_t **str_sub_vocab ,
+ str_sub_vocab_t *reset_position )
+{
+ str_sub_vocab_t *next_t;
+
+ next_t = *str_sub_vocab;
+ while ( next_t != reset_position )
+ {
+ next_t = (*str_sub_vocab)->next ;
+
+ free( (*str_sub_vocab)->name );
+ if ( !(*str_sub_vocab)->alias )
+ {
+ free( (*str_sub_vocab)->alias );
+ }
+ free( *str_sub_vocab );
+ *str_sub_vocab = next_t ;
+ }
+}
+
Added: fcode-utils/toke/strsubvocab.h
===================================================================
--- fcode-utils/toke/strsubvocab.h (rev 0)
+++ fcode-utils/toke/strsubvocab.h 2006-08-18 12:47:12 UTC (rev 76)
@@ -0,0 +1,85 @@
+#ifndef _TOKE_STRSUBVOCAB_H
+#define _TOKE_STRSUBVOCAB_H
+
+
+/*
+ * OpenBIOS - free your system!
+ * ( FCode tokenizer )
+ *
+ * This program is part of a free implementation of the IEEE 1275-1994
+ * Standard for Boot (Initialization Configuration) Firmware.
+ *
+ * Copyright (C) 2001-2005 Stefan Reinauer, <stepan(a)openbios.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA, 02110-1301 USA
+ *
+ */
+
+/* **************************************************************************
+ *
+ * Headers, general-purpose support structures, function prototypes
+ * and macros for String-Substitution-type vocabularies.
+ *
+ * (C) Copyright 2005 IBM Corporation. All Rights Reserved.
+ * Module Author: David L. Paktor dlpaktor(a)us.ibm.com
+ *
+ **************************************************************************** */
+
+/* **************************************************************************
+ *
+ * Structures:
+ * str_sub_vocab_t Entry in a String-Substitution-type vocab
+ *
+ * Macros:
+ * BUILTIN_STR_SUB Add an entry to the initial Str-Sub vocab.
+ *
+ **************************************************************************** */
+
+#include "types.h"
+
+
+typedef struct str_sub_vocab {
+ u8 *name;
+ u8 *alias;
+ struct str_sub_vocab *next;
+} str_sub_vocab_t;
+
+#if 0 /* On the way out */
+/*
+ * BUILTIN_STR_SUB Add an entry to the initial Str-Sub vocab.
+ *
+ * Arguments: (Both are strings)
+ * princ Principal name by which the string is known
+ * subst Substitution-string that replaces the Principal.
+ */
+#define BUILTIN_STR_SUB(princ, subst) \
+ { princ , subst , (str_sub_vocab_t *)NULL }
+#endif /* On the way out */
+
+
+void init_str_sub_vocab( str_sub_vocab_t *str_sub_vocab_tbl,
+ int max_indx);
+void add_str_sub_entry( char *ename,
+ char *subst_str,
+ str_sub_vocab_t **str_sub_vocab );
+char *lookup_str_sub( char *tname, str_sub_vocab_t *str_sub_vocab );
+bool create_str_sub_alias(char *new_name,
+ char *old_name,
+ str_sub_vocab_t **str_sub_vocab );
+bool exists_in_str_sub( char *tname, str_sub_vocab_t *str_sub_vocab );
+void reset_str_sub_vocab( str_sub_vocab_t **str_sub_vocab ,
+ str_sub_vocab_t *reset_position );
+
+
+#endif /* _TOKE_STRSUBVOCAB_H */
Added: fcode-utils/toke/ticvocab.c
===================================================================
--- fcode-utils/toke/ticvocab.c (rev 0)
+++ fcode-utils/toke/ticvocab.c 2006-08-18 12:47:12 UTC (rev 76)
@@ -0,0 +1,426 @@
+/*
+ * OpenBIOS - free your system!
+ * ( FCode tokenizer )
+ *
+ * This program is part of a free implementation of the IEEE 1275-1994
+ * Standard for Boot (Initialization Configuration) Firmware.
+ *
+ * Copyright (C) 2001-2005 Stefan Reinauer, <stepan(a)openbios.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA, 02110-1301 USA
+ *
+ */
+
+/* **************************************************************************
+ *
+ * General-purpose support functions for
+ * Threaded Interpretive Code (T. I. C.)-type vocabularies
+ *
+ * (C) Copyright 2005 IBM Corporation. All Rights Reserved.
+ * Module Author: David L. Paktor dlpaktor(a)us.ibm.com
+ *
+ **************************************************************************** */
+
+/* **************************************************************************
+ *
+ * We are going to implement a strategy that takes better advantage
+ * of the concept of Threaded Interpretive Code (well, okay,
+ * it won't really be interpretive ... ) We will use it to
+ * implement a small (but expandable) subset of FORTH-like
+ * commands in Tokenizer-Escape mode, as well as a few other
+ * things, such as conditional-tokenization.
+ *
+ * The Threaded Interpretive Code Header data structure is described
+ * in detail in the accompanying ticvocab.h header-file.
+ *
+ * In most cases, the contents of a beginning portion of the vocabulary
+ * are known at compile-time, and later parts are added by the
+ * user at run-time. (The linked-list structure is needed to allow
+ * for that.) We can initialize the known start of the vocabulary
+ * easily, except for the link-pointers, as an array.
+ * We can either explicitly state an index for each entry's link-pointer
+ * to the previous entry (which can become a problem to maintain) or
+ * have a function to initialize the links dynamically, at run-time.
+ * I think I will (regretfully, resignedly) choose the latter.
+ *
+ * We will define a few general-purpose functions for dealing with
+ * T. I. C. -type vocabularies. Eventually, it might be a good
+ * idea to convert all the vocabularies to this structure...
+ *
+ **************************************************************************** */
+
+/* **************************************************************************
+ *
+ *
+ * Revision History:
+ * Mon, 19 Dec 2005 by David L. Paktor
+ * Begin converting most, if not all, of the vocabularies to
+ * T. I. C. -type structure.
+ *
+ **************************************************************************** */
+
+
+/* **************************************************************************
+ *
+ * Functions Exported:
+ * init_tic_vocab Initialize a TIC_HDR -type vocabulary
+ * add_tic_entry Add an entry to a TIC_HDR -type vocabulary
+ * lookup_tic_entry Look for a name in a TIC_HDR -type vocabulary
+ * handle_tic_vocab Perform a function in a TIC_HDR -type vocab
+ * exists_in_tic_vocab Confirm whether a given name exists in a
+ * TIC_HDR -type vocabulary
+ * create_tic_alias Duplicate the behavior of one name with
+ * another name. Return a "success" flag.
+ * reset_tic_vocab Reset a given TIC_HDR -type vocabulary to
+ * its "Built-In" position.
+ *
+ **************************************************************************** */
+
+
+/* **************************************************************************
+ *
+ * Global Variables Exported
+ * tic_found The entry, in a TIC_HDR -type vocabulary,
+ * that has just been found and is being
+ * "handled". Needed for protection against
+ * recursion in a User-defined Macro (which
+ * should occur only rarely).
+ *
+ **************************************************************************** */
+
+
+#include <stdlib.h>
+#include <string.h>
+#include "ticvocab.h"
+#include "errhandler.h"
+
+tic_hdr_t *tic_found;
+
+/* **************************************************************************
+ *
+ * Function name: init_tic_vocab
+ * Synopsis: Dynamically initialize the link-pointers
+ * of the.given TIC_HDR -type vocabulary
+ *
+ * Inputs:
+ * Parameters:
+ * tic_vocab_tbl Pointer to the initial TIC_HDR vocab array
+ * max_indx Maximum Index of the initial array.
+ * tic_vocab_ptr Pointer to the vocab "tail"
+ *
+ * Outputs:
+ * Returned Value: None
+ * Global Variables:
+ * The link-fields of the initial TIC_HDR vocab array entries
+ * will be filled in.
+ * Supplied Pointers:
+ * *tic_vocab_ptr Points to the last element in the array
+ *
+ * Process Explanation:
+ * The value that tic_vocab_ptr has upon entry to the routine
+ * (which may point to the end of another array which is to
+ * precede this one in the voacbulary) gets entered into
+ * the link-pointer field of the first element of the array.
+ * For this reason, it is important that all TIC_HDR vocabulary
+ * pointers that will be pased to this routine have their
+ * initial values explicitly declared NULL.
+ *
+ **************************************************************************** */
+
+void init_tic_vocab( tic_hdr_t *tic_vocab_tbl,
+ int max_indx,
+ tic_hdr_t **tic_vocab_ptr)
+{
+ int indx;
+ for ( indx = 0 ; indx < max_indx ; indx++ )
+ {
+ tic_vocab_tbl[indx].next = *tic_vocab_ptr;
+ *tic_vocab_ptr = &tic_vocab_tbl[indx];
+ }
+}
+
+
+/* **************************************************************************
+ *
+ * Function name: add_tic_entry
+ * Synopsis: Add an entry to the given TIC_HDR -type vocabulary
+ *
+ * Inputs:
+ * Parameters:
+ * tname Pointer to space containing the name of the entry
+ * tfunct Pointer to the routine the new entry will call
+ * tparam The "parameter field" value (may be a pointer)
+ * fw_defr FWord Token of the entry's Definer
+ * pfldsiz Size of "param field" (if a pointer to alloc'd mem)
+ * ign_fnc Pointer to "ignoring" routine for new entry
+ * tic_vocab Pointer to ptr to "tail" of T.I.C.-type vocab-list
+ *
+ * Outputs:
+ * Returned Value: NONE
+ * Supplied Pointers:
+ * *tic_vocab Will point to new entry
+ * Memory Allocated:
+ * For the new entry.
+ * When Freed?
+ * When reset_tic_vocab() is applied to the same vocab-list.
+ *
+ * Error Detection:
+ * Failure to allocate memory is a Fatal Error.
+ *
+ * Process Explanation:
+ * The name pointer is presumed to already point to a stable,
+ * newly-allocated memory-space. If the parameter field is
+ * actually a pointer, it, too, is presumed to already have
+ * been allocated.
+ * Memory will be allocated for the entry itself; its pointers
+ * will be entered and the given pointer-to-the-tail-of-the-
+ * -vocabulary will be updated to point to the new entry.
+ *
+ **************************************************************************** */
+
+void add_tic_entry( char *tname,
+ void (*tfunct)(),
+ TIC_P_DEFLT_TYPE tparam,
+ fwtoken fw_defr,
+ int pfldsiz,
+ void (*ign_fnc)(),
+ tic_hdr_t **tic_vocab )
+{
+ tic_hdr_t *new_entry;
+
+ new_entry = safe_malloc(sizeof(tic_hdr_t), "adding tic_entry");
+ new_entry->name = tname;
+ new_entry->next = *tic_vocab;
+ new_entry->funct = tfunct;
+ new_entry->pfield.deflt_elem = tparam;
+ new_entry->fword_defr = fw_defr;
+ new_entry->ign_func = ign_fnc;
+ new_entry->pfld_size = pfldsiz;
+
+ *tic_vocab = new_entry;
+
+}
+
+/* **************************************************************************
+ *
+ * Function name: lookup_tic_entry
+ * Synopsis: Look for a name in the given TIC_HDR -type vocabulary
+ *
+ * Inputs:
+ * Parameters:
+ * tname The "target" name for which to look
+ * tic_vocab Pointer to the T. I. C. -type vocabulary
+ *
+ * Outputs:
+ * Returned Value: Pointer to the relevant entry, or
+ * NULL if name not found.
+ *
+ * Extraneous Remarks:
+ * We don't set the global tic_found here because this routine
+ * is not always called when the found function is going to
+ * be executed; sometimes it is called for error-detection,
+ * for instance...
+ *
+ **************************************************************************** */
+
+tic_hdr_t *lookup_tic_entry( char *tname, tic_hdr_t *tic_vocab )
+{
+ tic_hdr_t *curr ;
+
+ for (curr = tic_vocab ; curr != NULL ; curr=curr->next)
+ {
+ if ( strcasecmp(tname, curr->name) == 0 )
+ {
+ break;
+ }
+ }
+
+ return ( curr ) ;
+}
+
+/* **************************************************************************
+ *
+ * Function name: exists_in_tic_vocab
+ * Synopsis: Confirm whether the given name exists in the
+ * given TIC_HDR -type vocabulary
+ *
+ * Inputs:
+ * Parameters:
+ * tname The name for which to look
+ * tic_vocab Pointer to the T. I. C. -type vocabulary
+ *
+ * Outputs:
+ * Returned Value: TRUE if name is found,
+ *
+ **************************************************************************** */
+
+bool exists_in_tic_vocab( char *tname, tic_hdr_t *tic_vocab )
+{
+ tic_hdr_t *found ;
+ bool retval = FALSE;
+
+ found = lookup_tic_entry( tname, tic_vocab );
+ if ( found != NULL )
+ {
+ retval = TRUE;
+ }
+
+ return ( retval );
+}
+
+
+/* **************************************************************************
+ *
+ * Function name: create_tic_alias
+ * Synopsis: Create an Alias in a TIC_HDR -type vocabulary
+ * Return a "success" flag.
+ *
+ * Associated FORTH word: ALIAS
+ *
+ * Inputs:
+ * Parameters:
+ * old_name Name of existing entry
+ * new_name New name for which to create an entry
+ * *tic_vocab Pointer to the "tail" of the
+ * T. I. C. -type vocab-list
+ *
+ * Outputs:
+ * Returned Value: TRUE if old_name found in given vocab
+ * Supplied Pointers:
+ * *tic_vocab Will be updated to point to the new entry
+ * Memory Allocated:
+ * For the new entry, by the support routine.
+ * When Freed?
+ * When reset_tic_vocab() is applied to the same vocab-list.
+ *
+ * Process Explanation:
+ * Both the "old" and "new" names are presumed to already point to
+ * stable, freshly allocated memory-spaces.
+ * Even if the "old" entry's pfld_size is not zero, meaning its
+ * param-field is a pointer to allocated memory, we still do
+ * not need to copy it into a freshly allocated memory-space,
+ * as long as we make the new alias-entry's pfld_size zero:
+ * the reference to the old space will work, and the old
+ * entry's param-field memory space will not be freed with
+ * the alias-entry but only with the "old" entry.
+ *
+ **************************************************************************** */
+
+bool create_tic_alias( char *new_name, char *old_name, tic_hdr_t **tic_vocab )
+{
+ tic_hdr_t *found ;
+ bool retval = FALSE;
+
+ found = lookup_tic_entry( old_name, *tic_vocab );
+ if ( found != NULL )
+ {
+ add_tic_entry( new_name, found->funct,
+ found->pfield.deflt_elem,
+ found->fword_defr,
+ 0, found->ign_func, tic_vocab );
+ retval = TRUE;
+ }
+
+ return ( retval );
+}
+
+
+/* **************************************************************************
+ *
+ * Function name: handle_tic_vocab
+ * Synopsis: Perform the function associated with the given name
+ * in the given TIC_HDR -type vocabulary
+ *
+ * Inputs:
+ * Parameters:
+ * tname The "target" name for which to look
+ * tic_vocab Pointer to the T. I. C. -type vocabulary
+ *
+ * Outputs:
+ * Returned Value: TRUE if the given name is valid in the given vocab
+ * Global Variables:
+ * tic_found Points to the TIC entry of the "target"
+ * name, if it was found; else, NULL.
+ * Global Behavior:
+ * Whatever the associated function does...
+ *
+ * Process Explanation:
+ * Find the name and execute its associated function.
+ * If the name is not in the given vocabulary, return
+ * an indication; leave it to the calling routine
+ * to decide how to proceed.
+ *
+ **************************************************************************** */
+
+bool handle_tic_vocab( char *tname, tic_hdr_t *tic_vocab )
+{
+ bool retval = FALSE;
+
+ tic_found = lookup_tic_entry( tname, tic_vocab );
+ if ( tic_found != NULL )
+ {
+ tic_found->funct( tic_found->pfield);
+ retval = TRUE;
+ }
+
+ return ( retval ) ;
+}
+
+/* **************************************************************************
+ *
+ * Function name: reset_tic_vocab
+ * Synopsis: Reset a given TIC_HDR -type vocabulary to
+ * its given "Built-In" position.
+ *
+ * Inputs:
+ * Parameters:
+ * *tic_vocab Pointer to the T. I. C.-type vocab-list
+ * reset_position Position to which to reset the list
+ *
+ * Outputs:
+ * Returned Value: NONE
+ * Supplied Pointers:
+ * *tic_vocab Reset to given "Built-In" position.
+ * Memory Freed
+ * All memory allocated by user-definitions will be freed
+ *
+ * Process Explanation:
+ * The "stable memory-spaces" to which the name and parameter
+ * field pointers point are presumed to have been acquired
+ * by allocation of memory, which is reasonable for entries
+ * created by the user as opposed to the built-in entries,
+ * which we are, in any case, not releasing.
+ * The parameter-field size field tells us whether we need to
+ * free() the parameter-field pointer.
+ *
+ **************************************************************************** */
+
+void reset_tic_vocab( tic_hdr_t **tic_vocab, tic_hdr_t *reset_position )
+{
+ tic_hdr_t *next_t;
+
+ next_t = *tic_vocab;
+ while ( next_t != reset_position )
+ {
+ next_t = (*tic_vocab)->next ;
+
+ free( (*tic_vocab)->name );
+ if ( (*tic_vocab)->pfld_size != 0 )
+ {
+ free( (*tic_vocab)->pfield.chr_ptr );
+ }
+ free( *tic_vocab );
+ *tic_vocab = next_t ;
+ }
+}
Added: fcode-utils/toke/ticvocab.h
===================================================================
--- fcode-utils/toke/ticvocab.h (rev 0)
+++ fcode-utils/toke/ticvocab.h 2006-08-18 12:47:12 UTC (rev 76)
@@ -0,0 +1,478 @@
+#ifndef _TOKE_TICVOCAB_H
+#define _TOKE_TICVOCAB_H
+
+/*
+ * OpenBIOS - free your system!
+ * ( FCode tokenizer )
+ *
+ * This program is part of a free implementation of the IEEE 1275-1994
+ * Standard for Boot (Initialization Configuration) Firmware.
+ *
+ * Copyright (C) 2001-2005 Stefan Reinauer, <stepan(a)openbios.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA, 02110-1301 USA
+ *
+ */
+
+/* **************************************************************************
+ *
+ * General-purpose support structures and function prototypes for
+ * Threaded Interpretive Code (T. I. C.)-type vocabularies.
+ * See ticvocab.c
+ *
+ * (C) Copyright 2005 IBM Corporation. All Rights Reserved.
+ * Module Author: David L. Paktor dlpaktor(a)us.ibm.com
+ *
+ **************************************************************************** */
+
+/* **************************************************************************
+ *
+ * Structures:
+ *
+ * The Threaded Interpretive Code Header data structure consists of:
+ * (1) A pointer to the function name as seen in the source
+ * (2) A link to the next (well, preceding) element
+ * (3) A Pointer to the routine to run as the function's behavior
+ * during active processing. It takes the "parameter field"
+ * item as its argument and has no return-value.
+ * (4) The "parameter field" item, which will be passed as an
+ * argument to the function. It may be an FCode- or FWord-
+ * -token, or an item of another type, or a pointer to data.
+ * The function may re-cast it as needed.
+ * (5) The "Definer" of the entry; a member of the subset of FWord-
+ * -tokens that may be Definers.
+ * (6) A Pointer to a routine to be run when the word is encountered
+ * in a Conditional Compilation section that is being ignored.
+ * Certain functions still need to be recognized in that state,
+ * and will require special behaviors; those that can be simply
+ * ignored will have a NULL pointer in this field. The function
+ * in this field, also, takes the "parameter field" item as its
+ * argument and has no return-value.
+ * (7) The size of the data pointed to by the "parameter field" item,
+ * if it is a pointer to allocated data; used to allocate space
+ * for a copy of the p.f. when making an alias, and to indicate
+ * whether the space needs to be freed. Automatic procedures
+ * are too often fooled, so we don't leave things to chance...
+ * To accommodate C's insistence on strong-typing, we might need
+ * to define different "parameter field" structure-types; see
+ * description of "Parameter Field as a union", below.
+ *
+ * It's not an exact name, but we'll still call it a T. I. C. Header
+ *
+ * We will use this structure for most of our vocabularies...
+ *
+ ****************************************************************************
+ *
+ * The "Parameter Field" is a union of several alternative types,
+ * for convenience, to avert excessive type-casting. It may
+ * either be the Parameter Data itself (if it is small enough)
+ * or a pointer to Parameter Data.
+ * In the case where the Parameter Field is the data itself, or is a
+ * pointer to hard-coded (non-allocated) data, the "size" field
+ * will be zero, to indicate that no space allocation is required.
+ * The types are (starting with the default for initialization)
+ * A long integer (including an FCode Token)
+ * An FWord Token
+ * A pointer to a boolean variable
+ * A pointer to a character or a character string
+ * If the parameter field value is intended to be a single character,
+ * it must be recast as a long integer, in order to preserve
+ * portability across big- and little- -endian platforms.
+ *
+ **************************************************************************** */
+
+/* ************************************************************************** *
+ *
+ * Macros:
+ * NO_PARAM_TIC Create an entry in the initial "Built-In"
+ * portion of a TIC-type vocabulary with
+ * an empty "param field".
+ * NO_PARAM_IGN Create an entry with an empty "param field"
+ * whose action- and "Ignore"- -functions
+ * are the same.
+ * VALPARAM_TIC " ... with a literal value for the "param field"
+ * DUALFUNC_TIC " ... with a literal "param" and both an action-
+ * and an "Ignore"- -function.
+ * DUFNC_FWT_PARM A tic_fwt_hdr_t -type entry with a literal
+ * "param" and both an action-function and an
+ * "Ignore"-function.
+ * FWORD_TKN_TIC " ... with an FWord Token for the "param field"
+ * DUALFUNC_FWT_TIC " " ... and both action- and "Ignore"- -function
+ * BUILTIN_MAC_TIC A tic_mac_hdr_t -type entry with a Macro-
+ * -Substitution-String "param"
+ * BUILTIN_BOOL_TIC A tic_bool_hdr_t -type entry with a boolean-
+ * -variable-pointer "param"
+ *
+ **************************************************************************** */
+
+#include "types.h"
+#include "dictionary.h"
+
+/* **************************************************************************
+ *
+ * In order to work around C's limitations regarding data-typing
+ * during initialization, we need to create some alternative
+ * data-structures that exactly match the layout of tic_hdr_t
+ * as defined above, but have a different default-type for
+ * the parameter field.
+ * I apologize in advance for any maintenance awkwardnesses this
+ * might engender; I would have come up with a more convenient
+ * way to do this if I could. At least, the pieces that need
+ * to be co-ordinated are in close proximity to each other...
+ *
+ **************************************************************************** */
+
+/* **************************************************************************
+ *
+ * The differences are all centered in the "parameter field" of
+ * the TIC header structure. In order to make sure all the
+ * alternative types map smoothly into each other, we will
+ * create a series of "union" types, differing only in what
+ * their default type is. We will keep the "parameter field"
+ * item the size of a Long Integer.
+ *
+ **************************************************************************** */
+
+/* **************************************************************************
+ *
+ * This form is the default type.
+ *
+ **************************************************************************** */
+
+#define TIC_P_DEFLT_TYPE long
+typedef union tic_param
+ {
+ TIC_P_DEFLT_TYPE deflt_elem ; /* The "default element" aspect. */
+ long long_val ; /* Explicitly specifying "long" */
+ fwtoken fw_token ; /* FWord Token */
+ bool *bool_ptr ; /* Pointer to a boolean variable */
+ char *chr_ptr ; /* Pointer to a character string */
+
+ /* The "character value" aspect behaves differently on big-
+ * versus little- -endian platforms (for initialization,
+ * anyway), so we cannot actually use it.
+ * Keep this commented-out, as a reminder.
+ */
+ /* char char_val ; */
+ /* We will recast "character value" as an integer. */
+
+ } tic_param_t ;
+
+typedef struct tic_hdr
+ {
+ char *name;
+ struct tic_hdr *next;
+ void (*funct)(); /* Function for active processing */
+ tic_param_t pfield;
+ fwtoken fword_defr; /* FWord Token of entry's Definer */
+ void (*ign_func)(); /* Function in "Ignored" segment */
+ int pfld_size;
+ } tic_hdr_t ;
+
+/* **************************************************************************
+ *
+ * This form is for initialization of an FWord Token list.
+ *
+ **************************************************************************** */
+
+#define TIC_FWT_P_DEFLT_TYPE fwtoken
+typedef union tic_fwt_param
+ {
+ TIC_FWT_P_DEFLT_TYPE deflt_elem ; /* "Default element" aspect. */
+ long long_val ; /* Long integer */
+ fwtoken fw_token ; /* Explicit FWord Token */
+ bool *bool_ptr ; /* Pointer to a boolean variable */
+ char *chr_ptr ; /* Pointer to a character string */
+ } tic_fwt_param_t ;
+
+typedef struct tic_fwt_hdr
+ {
+ char *name;
+ struct tic_fwt_hdr *next;
+ void (*funct)(); /* Function for active processing */
+ tic_fwt_param_t pfield;
+ fwtoken fword_defr; /* FWord Token of entry's Definer */
+ void (*ign_func)(); /* Function in "Ignored" segment */
+ int pfld_size;
+ } tic_fwt_hdr_t ;
+
+
+/* **************************************************************************
+ *
+ * The third form is for initialization of Built-in Macros. Its
+ * default parameter field type is a pointer to a compiled-in
+ * (i.e., constant) character string. Its pfld_size can be
+ * left as zero, because no allocated-memory copies of the
+ * string will be needed, even for aliases. (User-created
+ * macros, however, will need to allocate strings; we will
+ * deal with that elsewhere...)
+ *
+ **************************************************************************** */
+
+#define TIC_MAC_P_DEFLT_TYPE char *
+typedef union tic_mac_param
+ {
+ TIC_MAC_P_DEFLT_TYPE deflt_elem ; /* "Default element" aspect. */
+ long long_val ; /* Long integer */
+ fwtoken fw_token ; /* FWord Token */
+ bool *bool_ptr ; /* Pointer to a boolean variable */
+ char *chr_ptr ; /* Explicit Pointer to char str. */
+ } tic_mac_param_t ;
+
+typedef struct tic_mac_hdr
+ {
+ char *name;
+ struct tic_mac_hdr *next;
+ void (*funct)();
+ tic_mac_param_t pfield;
+ fwtoken fword_defr;
+ void (*ign_func)();
+ int pfld_size;
+ } tic_mac_hdr_t ;
+
+/* **************************************************************************
+ *
+ * The next form is for initialization of Condtionals. Its default
+ * parameter field type is a pointer to a boolean variable.
+ *
+ **************************************************************************** */
+
+#define TIC_BOOL_P_DEFLT_TYPE bool *
+typedef union tic_bool_param
+ {
+ TIC_BOOL_P_DEFLT_TYPE deflt_elem ; /* "Default element" aspect. */
+ long long_val ; /* Long integer */
+ fwtoken fw_token ; /* FWord Token */
+ bool *bool_ptr ; /* Explicit Ptr to boolean v'ble */
+ char *chr_ptr ; /* Pointer to a character string */
+ } tic_bool_param_t ;
+
+typedef struct tic_bool_hdr
+ {
+ char *name;
+ struct tic_bool_hdr *next;
+ void (*funct)();
+ tic_bool_param_t pfield;
+ fwtoken fword_defr;
+ void (*ign_func)();
+ int pfld_size;
+ } tic_bool_hdr_t ;
+
+
+
+/* **************************************************************************
+ *
+ * Various macros to create an entry in the initial "Built-In" portion
+ * of a vocabulary-list, specified as an array of one of the
+ * matching forms of a T. I. C. Header; each macro adjusts type
+ * casting as needed.
+ * In all cases, the "size" field will be set to zero, indicating that
+ * the "param field" item is either the complete data or a pointer
+ * to a hard-coded (non-allocated) data item.
+ *
+ **************************************************************************** */
+
+/* **************************************************************************
+ * Macro Name: NO_PARAM_TIC
+ * Create an entry in the initial "Built-In" portion
+ * of a TIC_HDR -type vocabulary with an empty
+ * "param field"
+ *
+ * Arguments:
+ * nam (string) Name of the entry as seen in the source
+ * func (routine-name) Name of internal function to call
+ *
+ **************************************************************************** */
+#define NO_PARAM_TIC(nam, func ) \
+ { nam , (tic_hdr_t *)NULL , func , { 0 }, UNSPECIFIED , NULL , 0 }
+
+
+/* **************************************************************************
+ * Macro Name: NO_PARAM_IGN
+ * Create an entry with an empty "param field"
+ * whose action-function and "Ignore"-function
+ * are the same.
+ *
+ * Arguments:
+ * nam (string) Name of the entry as seen in the source
+ * func (routine-name) Name of internal function to call for both
+ *
+ *
+ **************************************************************************** */
+#define NO_PARAM_IGN(nam, func ) \
+ { nam , (tic_hdr_t *)NULL , func , { 0 }, UNSPECIFIED , func , 0 }
+
+
+/* **************************************************************************
+ *
+ * Variations on the above, to compensate for Type-Casting complications
+ *
+ **************************************************************************** */
+
+/* **************************************************************************
+ * Macro Name: VALPARAM_TIC
+ * Create an entry in the initial "Built-In" portion
+ * of a TIC_HDR -type vocabulary with a literal
+ * value for the "param field" and a specifiable
+ * "definer".
+ * Arguments:
+ * nam (string) Name of the entry as seen in the source
+ * func (routine-name) Name of internal function to call
+ * pval (integer) The "param field" item
+ * definr (fword_token) "Definer" of the entry
+ *
+ * The "param field" item will be recast to the required default type.
+ *
+ **************************************************************************** */
+
+#define VALPARAM_TIC(nam, func, pval, definr ) \
+ { nam , (tic_hdr_t *)NULL , func , \
+ { (TIC_P_DEFLT_TYPE)(pval) }, definr , NULL , 0 }
+
+
+/* **************************************************************************
+ * Macro Name: DUALFUNC_TIC
+ * Create an entry in the initial "Built-In" portion
+ * of a TIC_HDR -type vocabulary with both an
+ * "active" and an "ignoring" function, a literal
+ * value for the "param field" and a specifiable
+ * "definer".
+ *
+ * Arguments:
+ * nam (string) Name of the entry as seen in the source
+ * afunc (routine-name) Name of internal "active" function
+ * pval (integer) The "param field" item
+ * ifunc (routine-name) Name of "ignoring" function
+ * definr (fword_token) "Definer" of the entry
+ *
+ * The "param field" item will be recast to the required default type.
+ *
+ **************************************************************************** */
+#define DUALFUNC_TIC(nam, afunc, pval, ifunc, definr ) \
+ { nam , (tic_hdr_t *)NULL , afunc , \
+ { (TIC_P_DEFLT_TYPE)(pval) }, definr , ifunc , 0 }
+
+/* Similar but a tic_fwt_hdr_t type structure */
+#define DUFNC_FWT_PARM(nam, afunc, pval, ifunc, definr ) \
+ { nam , (tic_fwt_hdr_t *)NULL , afunc , \
+ { (TIC_FWT_P_DEFLT_TYPE)(pval) }, definr , ifunc , 0 }
+
+
+/* **************************************************************************
+ * Macro Name: FWORD_TKN_TIC
+ * Create an entry in the initial "Built-In" portion
+ * of an FWord Token list of tic_fwt_hdr_t type.
+ *
+ * Arguments:
+ * nam (string) Name of the entry as seen in the source
+ * func (routine-name) Name of internal function to call
+ * fw_tokval (fword_token) Value of the FWord Token
+ * definr (fword_token) "Definer" of the entry
+ *
+ * The "param field" item should not need be recast.
+ *
+ **************************************************************************** */
+
+#define FWORD_TKN_TIC(nam, func, fw_tokval, definr ) \
+ { nam , (tic_fwt_hdr_t *)NULL , func , { fw_tokval }, definr , NULL , 0 }
+
+/* **************************************************************************
+ * Macro Name: DUALFUNC_FWT_TIC
+ * Create an entry in the initial "Built-In" portion
+ * of an FWord Token list of tic_fwt_hdr_t type
+ * with both an action- and an "Ignore"- -function.
+ *
+ * Arguments:
+ * nam (string) Name of the entry as seen in the source
+ * afunc (routine-name) Name of internal "Action" function
+ * fw_tokval (fword_token) Value of the FWord Token
+ * ifunc (routine-name) Name of "ignoring" function
+ * definr (fword_token) "Definer" of the entry
+ *
+ * The "param field" item should not need be recast.
+ *
+ **************************************************************************** */
+#define DUALFUNC_FWT_TIC(nam, afunc, fw_tokval, ifunc, definr ) \
+ { nam , (tic_fwt_hdr_t *)NULL , afunc , { fw_tokval }, definr , ifunc , 0 }
+
+/* **************************************************************************
+ * Macro Name: BUILTIN_MAC_TIC
+ * Create an entry in the initial "Built-In" portion
+ * of a Macros vocabulary of tic_mac_hdr_t type.
+ *
+ * Arguments:
+ * nam (string) Name of the entry as seen in the source
+ * func (routine-name) Name of internal function to call
+ * alias (string) Macro-Substitution string
+ *
+ * The "param field" item should not need be recast.
+ * The "definer" will be MACRO_DEF
+ * Builtin Macros do not need to be expanded while Ignoring, so
+ * the ign_func will be NULL
+ *
+ **************************************************************************** */
+
+#define BUILTIN_MAC_TIC(nam, func, alias ) \
+ { nam , (tic_mac_hdr_t *)NULL , func , { alias }, MACRO_DEF , NULL , 0 }
+
+
+/* **************************************************************************
+ * Macro Name: BUILTIN_BOOL_TIC
+ * Create an entry in the initial "Built-In" portion
+ * of a Condtionals list of tic_bool_hdr_t type.
+ *
+ * Arguments:
+ * nam (string) Name of the entry as seen in the source
+ * func (routine-name) Name of internal function to call
+ * bool_vbl (boolean v'ble) Name of the boolean variable.
+ *
+ * The "param field" item should not need be recast.
+ * For all of the Condtionals, the "Ignoring" function is the same
+ * as the "Active" function.
+ * The "definer" will be COMMON_FWORD
+ *
+ **************************************************************************** */
+
+#define BUILTIN_BOOL_TIC(nam, func, bool_vbl ) \
+ { nam , (tic_bool_hdr_t *)NULL , func , { &bool_vbl }, \
+ COMMON_FWORD , func , 0 }
+
+
+/* **************************************************************************
+ *
+ * Exported Variables and Function Prototypes the rest of the way...
+ *
+ **************************************************************************** */
+
+extern tic_hdr_t *tic_found;
+
+void init_tic_vocab( tic_hdr_t *tic_vocab_tbl,
+ int max_indx,
+ tic_hdr_t **tic_vocab_ptr);
+void add_tic_entry( char *tname,
+ void (*tfunct)(),
+ TIC_P_DEFLT_TYPE tparam,
+ fwtoken fw_defr,
+ int pfldsiz,
+ void (*ign_fnc)(),
+ tic_hdr_t **tic_vocab );
+tic_hdr_t *lookup_tic_entry( char *tname, tic_hdr_t *tic_vocab );
+bool exists_in_tic_vocab( char *tname, tic_hdr_t *tic_vocab );
+bool handle_tic_vocab( char *tname, tic_hdr_t *tic_vocab );
+bool create_tic_alias( char *new_name,
+ char *old_name,
+ tic_hdr_t **tic_vocab );
+void reset_tic_vocab( tic_hdr_t **tic_vocab, tic_hdr_t *reset_position );
+
+#endif /* _TOKE_TICVOCAB_H */
Modified: fcode-utils/toke/toke.c
===================================================================
--- fcode-utils/toke/toke.c 2006-08-18 09:45:11 UTC (rev 75)
+++ fcode-utils/toke/toke.c 2006-08-18 12:47:12 UTC (rev 76)
@@ -7,7 +7,7 @@
* This program is part of a free implementation of the IEEE 1275-1994
* Standard for Boot (Initialization Configuration) Firmware.
*
- * Copyright (C) 2001-2005 by Stefan Reinauer <stepan(a)openbios.org>
+ * Copyright (C) 2001-2006 by Stefan Reinauer <stepan(a)openbios.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -24,6 +24,12 @@
*
*/
+/* **************************************************************************
+ * Modifications made in 2005 by IBM Corporation
+ * (C) Copyright 2005 IBM Corporation. All Rights Reserved.
+ * Modifications Author: David L. Paktor dlpaktor(a)us.ibm.com
+ **************************************************************************** */
+
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@@ -34,47 +40,214 @@
#include <getopt.h>
#endif
+#include "types.h"
#include "toke.h"
#include "stream.h"
#include "stack.h"
#include "emit.h"
-#define TOKE_VERSION "0.6.10"
+#define TOKE_VERSION "1.0.0"
-int verbose=0;
-int noerrors=0;
+#include "vocabfuncts.h"
+#include "scanner.h"
+#include "errhandler.h"
+#include "usersymbols.h"
+#include "clflags.h"
+#include "tracesyms.h"
+#define CORE_COPYR "(C) Copyright 2001-2006 Stefan Reinauer.\n" \
+ "(C) Copyright 2006 coresystems GmbH <info(a)coresystems.de>"
+#define IBM_COPYR "(C) Copyright 2005 IBM Corporation. All Rights Reserved."
+
+/* Temporary hack during development... See DATE_STAMP line below... */
+#ifdef DEVEL
+#include "date_stamp.h"
+#endif /* DEVEL */
+
+/* **************************************************************************
+ *
+ * Global Variables Exported:
+ * verbose If true, enable optional messages.
+ * noerrors If true, create binary even if error(s) encountered.
+ * fload_list If true, create an "FLoad-List" file
+ * dependency_list If true, create a "Dependencies-List" file
+ *
+ **************************************************************************** */
+
+bool verbose = FALSE;
+bool noerrors = FALSE;
+bool fload_list = FALSE;
+bool dependency_list = FALSE;
+
+/* **************************************************************************
+ *
+ * Internal Static Variables
+ * outputname Name of output file supplied on command-line
+ * with the optional -o switch.
+ * Internal System Variable
+ * optind Index into argv vector of first param after options,
+ * from which input file names will be taken.
+ *
+ **************************************************************************** */
+
+static char *outputname = NULL;
+
+/* **************************************************************************
+ *
+ * Print the copyright message.
+ *
+ **************************************************************************** */
static void print_copyright(void)
{
- printf( "Welcome to toke - OpenBIOS tokenizer v%s\nCopyright (c)"
- " 2001-2005 by Stefan Reinauer <stepan(a)openbios.org>\n"
+ printf( "Welcome to toke - OpenBIOS tokenizer v" TOKE_VERSION "\n"
+ CORE_COPYR "\n" IBM_COPYR "\n"
"This program is free software; you may redistribute it "
"under the terms of\nthe GNU General Public License. This "
- "program has absolutely no warranty.\n\n", TOKE_VERSION);
+ "program has absolutely no warranty.\n\n");
+#ifdef DEVEL
+ /* Temporary hack during development... */
+ printf( "\tTokenizer Compiled " DATE_STAMP "\n" );
+#endif /* DEVEL */
+
}
+/* **************************************************************************
+ *
+ * Function name: usage
+ * Synopsis: Print convenient usage-help message
+ *
+ **************************************************************************** */
+
static void usage(char *name)
{
- printf("usage: %s [-v] [-i] [-o target] <forth-file>\n\n",name);
- printf(" -v|--verbose print debug messages\n");
- printf(" -i|--ignore-errors don't bail out after an error\n");
+ printf("usage: %s [-v] [-i] [-l] [-P] [-o target] <[-d name[=value]]> "
+ "<[-f [no]flagname]> <[-I dir-path]> "
+ "<[-T symbol]> <forth-file>\n\n",name);
+ printf(" -v|--verbose print Advisory messages\n");
+ printf(" -i|--ignore-errors don't suppress output after errors\n");
+ printf(" -l|--load-list create list of FLoaded file names\n");
+ printf(" -P|--dependencies create dePendency-list file\n");
+ printf(" -o|--output-name send output to filename given\n");
+ printf(" -d|--define create user-defined symbol\n");
+ printf(" -f|--flag set (or clear) Special-Feature flag\n");
+ printf(" -I|--Include add a directory to the Include-List\n");
+ printf(" -T|--Trace add a symbol to the Trace List\n");
printf(" -h|--help print this help message\n\n");
-
+ printf(" -f|--flag help Help for Special-Feature flags\n");
}
-int main(int argc, char **argv)
+/* **************************************************************************
+ *
+ * Function name: get_args
+ * Synopsis: Parse the Command-Line option switches
+ *
+ * Inputs:
+ * Parameters: NONE
+ * Global Variables:
+ * argc Counter of command-line arguments
+ * argv Vector pointing to command-line arguments
+ * Command-Line Items: The entire command-line will be parsed
+ *
+ * Outputs:
+ * Returned Value: NONE
+ * Global Variables:
+ * verbose set by "-v" switch
+ * noerrors set by "-i" switch
+ * fload_list set by "-l" switch
+ * dependency_list set by "-P" switch
+ * Internal Static Variables
+ * outputname set by "-o" switch
+ * Internal System Variable
+ * optind Index into argv vector of the position
+ * from which to take input file names.
+ * Printout:
+ * (Copyright was already printed by the main body as a
+ * matter of course, rather than here depending on
+ * the Verbose flag, because getopt() prints its
+ * own error messages and we want to be sure to show
+ * the Copyright notice before any error messages.)
+ * Rules for Usage and Flags-list or Flags-help display:
+ * Usage message on Help-Request or error.
+ * Ask for usage help, get Usage plus list of Flag Names.
+ * Ask for Flags-help alone, get Flags-help (names plus
+ * explanations)
+ * Ask for usage help and for Flags-help, get Usage plus
+ * Flags-help, without redundant list of Flag Names.
+ * Any help-request, exit Zero
+ * Error in Option switches, or missing input-file name,
+ * get error-description plus Usage
+ * Error in Flag Names, get list of Flag Names.
+ * Any error, exit One.
+ * Behavior:
+ * Exit (non-failure) after printing "Help" message
+ *
+ * Error Detection: Exit with failure status on:
+ * Unknown Option switches or Flag Names
+ * Missing input file name
+ *
+ * Process Explanation:
+ * The following switches are recognized:
+ * v
+ * h
+ * ?
+ * i
+ * I
+ * l
+ * P
+ * o
+ * d
+ * f
+ * T
+ * The conditions they set remain in effect through
+ * the entire program run.
+ *
+ * Revision History:
+ * Updated Fri, 15 Jul 2005 by David L. Paktor
+ * Don't bail on first invalid option.
+ * Flags to control special features
+ * Usage messages for "special-feature" flags
+ * Updated Mon, 18 Jul 2005 by David L. Paktor
+ * Fine-tune Usage and Flags-list or Flags-help display.
+ * Updated Sun, 27 Nov 2005 by David L. Paktor
+ * Add FLoad-List flag
+ * Updated Wed, 29 Nov 2005 by David L. Paktor
+ * Make getopt() case-insensitive
+ * Updated Fri, 17 Mar 2006 by David L. O'Paktor
+ * Make getopt() case-sensitive again,
+ * add include-list support and dePendency-list switch
+ *
+ * Extraneous Remarks:
+ * We were originally thinking about defining various classes
+ * of "Warning" Messages and (somehow) controlling their
+ * display, but now that we have "special-feature" flags
+ * that control the generation of specific messages, that
+ * step has become unnecessary...
+ *
+ **************************************************************************** */
+
+static void get_args( int argc, char **argv )
{
- const char *optstring="vhio:?";
- char *outputname = NULL;
+ const char *optstring="vhilPo:d:f:I:T:?";
int c;
+ int argindx = 0;
+ bool inval_opt = FALSE;
+ bool help_mssg = FALSE;
+ bool cl_flag_error = FALSE;
while (1) {
#ifdef __GLIBC__
int option_index = 0;
static struct option long_options[] = {
{ "verbose", 0, 0, 'v' },
+ { "help", 0, 0, 'h' },
{ "ignore-errors", 0, 0, 'i' },
- { "help", 0, 0, 'h' },
+ { "load-list", 0, 0, 'l' },
+ { "dependencies", 0, 0, 'P' },
+ { "output-name", 1, 0, 'o' },
+ { "define", 1, 0, 'd' },
+ { "flag", 1, 0, 'f' },
+ { "Include", 1, 0, 'I' },
+ { "Trace", 1, 0, 'T' },
{ 0, 0, 0, 0 }
};
@@ -86,63 +259,169 @@
if (c == -1)
break;
+ argindx++;
switch (c) {
case 'v':
- verbose=1;
+ verbose=TRUE;
break;
case 'o':
outputname = optarg;
break;
case 'i':
- noerrors=1;
+ noerrors = TRUE;
break;
+ case 'l':
+ fload_list = TRUE;
+ break;
+ case 'P':
+ dependency_list = TRUE;
+ break;
+ case 'd':
+ {
+ char *user_symb = optarg;
+ add_user_symbol(user_symb);
+ }
+ break;
+ case 'f':
+ cl_flag_error = set_cl_flag(optarg, FALSE) ;
+ break;
+ case 'I':
+ {
+ char *incl_list_elem = optarg;
+ add_to_include_list(incl_list_elem);
+ }
+ break;
+ case 'T':
+ add_to_trace_list(optarg);
+ break;
+ case '?':
+ /* Distinguish between a '?' from the user
+ * and one getopt() returned
+ */
+ if ( argv[argindx][1] != '?' )
+ {
+ inval_opt = TRUE;
+ break;
+ }
case 'h':
- case '?':
- print_copyright();
- usage(argv[0]);
- return 0;
+ case 'H':
+ help_mssg = TRUE;
+ break;
default:
- print_copyright();
+ /* This is never executed
+ * because getopt() prints the
+ * "unknown option -- X"
+ * message and returns a '?'
+ */
printf ("%s: unknown options.\n",argv[0]);
usage(argv[0]);
- return 1;
+ exit( 1 );
}
}
- if (verbose)
- print_copyright();
+ if ( help_mssg )
+ {
+ usage(argv[0]);
+ if ( ! clflag_help )
+ {
+ list_cl_flag_names();
+ }
+ }
+ if ( clflag_help ) cl_flags_help();
+ if ( help_mssg || clflag_help )
+ {
+ exit( 0 );
+ }
- if (optind >= argc) {
- print_copyright();
- printf ("%s: filename missing.\n",argv[0]);
+ if ( inval_opt ) printf ("unknown options.\n");
+ if (optind >= argc) printf ("Input file name missing.\n");
+ if ( inval_opt || (optind >= argc) )
+ {
usage(argv[0]);
- return 1;
}
+ if ( cl_flag_error ) list_cl_flag_names();
+ if ( inval_opt || (optind >= argc) || cl_flag_error )
+ {
+ exit( 1);
+ }
+
+ if (verbose)
+ {
+ list_user_symbols();
+ list_cl_flag_settings();
+ display_include_list();
+ }
+ save_cl_flags();
+}
+
+/* **************************************************************************
+ *
+ * Main body of program. Return 0 for success, 1 for failure.
+ *
+ * Still to be done:
+ * Devise a syntax to allow the command-line to specify multiple
+ * input files together with an output file name for each.
+ * Currently, the syntax allows only one output file name to be
+ * specified; when multiple input file names are specified,
+ * the specification of an output file name is disallowed,
+ * and only the default output file names are permitted.
+ * While this works around the immediate problem, a more
+ * elegant solution could be devised...
+ *
+ **************************************************************************** */
+
+int main(int argc, char **argv)
+{
+ int retval = 0;
+
+ print_copyright();
+ get_args( argc, argv );
+
init_stack();
init_dictionary();
- init_macros();
+
init_scanner();
- while (optind < argc) {
- if (init_stream(argv[optind])) {
- printf ("%s: warning: could not open file \"%s\"\n",
- argv[0], argv[optind]);
- optind++;
- continue;
+ if ( outputname != NULL )
+ {
+ if ( argc > optind + 1 )
+ {
+ /* Multiple input file names w/ single output file name */
+ /* Work-around */
+ printf( "Cannot specify single output file name "
+ "with multiple input file names.\n"
+ "Please either remove output-file-name specification,\n"
+ "or use multiple commands.\n");
+ exit ( -2 );
+ }
}
+
+ for ( ; optind < argc ; optind++ )
+ {
+ bool stream_ok ;
+
+ printf("\nTokenizing %s ", argv[optind]);
+ init_error_handler();
+ stream_ok = init_stream( argv[optind]);
+ if ( stream_ok )
+ {
init_output(argv[optind], outputname);
+ init_scan_state();
+
+ reset_vocabs();
+ reset_cl_flags();
+
tokenize();
finish_headers();
- close_output();
- close_stream();
-
- optind++;
+ close_stream( NULL);
+ if ( close_output() ) retval = 1;
+ }
}
exit_scanner();
- return 0;
+ return retval;
}
Modified: fcode-utils/toke/toke.h
===================================================================
--- fcode-utils/toke/toke.h 2006-08-18 09:45:11 UTC (rev 75)
+++ fcode-utils/toke/toke.h 2006-08-18 12:47:12 UTC (rev 76)
@@ -1,3 +1,6 @@
+#ifndef _TOKE_TOKE_H
+#define _TOKE_TOKE_H
+
/*
* OpenBIOS - free your system!
* ( FCode tokenizer )
@@ -24,30 +27,25 @@
*
*/
-#ifndef _H_TOKE
-#define _H_TOKE
+/* **************************************************************************
+ * Modifications made in 2005 by IBM Corporation
+ * (C) Copyright 2005 IBM Corporation. All Rights Reserved.
+ * Modifications Author: David L. Paktor dlpaktor(a)us.ibm.com
+ **************************************************************************** */
-#define u8 unsigned char
-#define u16 unsigned short
-#define u32 unsigned int
-#define s16 short
-#define bool int
-#define TRUE (-1)
-#define FALSE (0)
-#define ANSI_ONLY
-extern void init_scanner( void );
-extern void exit_scanner( void );
+#include "types.h"
-extern void init_dictionary( void );
-extern void init_macros( void );
-extern void tokenize( void );
-extern u16 lookup_token(char *name);
-extern u16 lookup_fword(char *name);
-extern char *lookup_macro(char *name);
-extern int add_token(u16 number, char *name);
+/* ************************************************************************** *
+ *
+ * Global Variables Exported
+ *
+ **************************************************************************** */
-extern int add_macro(char *name, char *alias);
+extern bool verbose;
+extern bool noerrors;
+extern bool fload_list;
+extern bool dependency_list;
-#endif /* _H_TOKE */
+#endif /* _TOKE_TOKE_H */
Added: fcode-utils/toke/tokzesc.c
===================================================================
--- fcode-utils/toke/tokzesc.c (rev 0)
+++ fcode-utils/toke/tokzesc.c 2006-08-18 12:47:12 UTC (rev 76)
@@ -0,0 +1,771 @@
+/*
+ * OpenBIOS - free your system!
+ * ( FCode tokenizer )
+ *
+ * This program is part of a free implementation of the IEEE 1275-1994
+ * Standard for Boot (Initialization Configuration) Firmware.
+ *
+ * Copyright (C) 2001-2005 Stefan Reinauer, <stepan(a)openbios.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA, 02110-1301 USA
+ *
+ */
+
+/* **************************************************************************
+ *
+ * Process activity inside "Tokenizer Escape" mode.
+ *
+ * (C) Copyright 2005 IBM Corporation. All Rights Reserved.
+ * Module Author: David L. Paktor dlpaktor(a)us.ibm.com
+ *
+ **************************************************************************** */
+
+/* **************************************************************************
+ *
+ * Functions Exported:
+ * init_tokz_esc_vocab Initialize the relevant vocabulary.
+ * enter_tokz_esc Enter "Tokenizer Escape" mode
+ * handle_tokz_esc Perform a function in the
+ * "Tokenizer Escape" Vocabulary
+ * exists_in_tokz_esc Confirm whether a given name exists in
+ * the "Tokz_Esc_Vocabulary"
+ * create_tokz_esc_alias Add an alias to "Tokenizer Escape" space
+ * reset_tokz_esc Reset the "Tokenizer Escape" Vocabulary
+ * to its "Built-In" position.
+ *
+ **************************************************************************** */
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include "ticvocab.h"
+#include "tokzesc.h"
+#include "stack.h"
+#include "emit.h"
+#include "stream.h"
+#include "scanner.h"
+#include "errhandler.h"
+#include "strsubvocab.h"
+#include "nextfcode.h"
+
+#undef TOKZTEST /* Define for testing only; else undef */
+#ifdef TOKZTEST /* For testing only */
+ #include "vocabfuncts.h"
+ #include "date_stamp.h"
+#endif /* For testing only */
+
+/* **************************************************************************
+ *
+ * Global Variables Imported
+ * in_tokz_esc State of the tokenization operation.
+ * Value is FALSE if it's operating normally
+ * or TRUE if it's in "Tokenizer Escape" mode.
+ * nextfcode
+ * statbuf
+ * dstack Pointer to current item on top of Data Stack.
+ * base Current tokenizer numeric conversion radix
+ *
+ **************************************************************************** */
+
+/* **************************************************************************
+ *
+ * We are going to implement a mini-forth using a strategy based
+ * on the concept of Threaded Interpretive Code (well, okay,
+ * it won't really be interpretive ... )
+ *
+ **************************************************************************** */
+
+/* **************************************************************************
+ *
+ * Internal Static Variables -- (well, almost)
+ * tokz_esc_vocab Pointer to "tail" of "Tokenizer Escape" Vocab
+ *
+ * While we would prefer to keep tokz_esc_vocab private to this file,
+ * we find we need it in one other place, namely, macros.c
+ * We will declare it "extern" within that file, rather than
+ * exporting it widely by including it in a .h file
+ *
+ **************************************************************************** */
+
+/* **************************************************************************
+ *
+ * We will define and initialize a structure consisting of all the
+ * functions we initially support for "Tokenizer Escape" mode,
+ * called tokz_esc_vocab_tbl for "Tokenizer Escape Vocab Table".
+ * I expect we can initialize its body, but I don't think there's a
+ * convenient way in "C" to initialize its links; we'll have to
+ * do that dynamically, at run-time. Oh, well...
+ *
+ * We'll call the pointer to it the "Tokenizer Escape" Vocabulary.
+ * We have to declare it here, because we need to refer to it in
+ * a function that will be entered into the Table.
+ *
+ * We would like to pre-initialize it; to do so, we would have to
+ * declare it extern here, then later create its instance and
+ * assign its initial value. That would be all well and good,
+ * except that some linkers don't handle that very well, so, to
+ * accommodate those, we have to include its initialization in
+ * the same routine where we initialize the Table's links.
+ *
+ * Revision History:
+ * Updated Wed, 04 Jan 2006 by David L. Paktor
+ * Initialization of tokz_esc_vocab is now included with
+ * the call to init_tic_vocab()
+ *
+ **************************************************************************** */
+
+tic_hdr_t *tokz_esc_vocab = NULL ;
+
+/* **************************************************************************
+ *
+ * We'll give short prologs to the simpler functions that will be
+ * used in the "Tokenizer Escape" Vocabulary.
+ *
+ * All these take, as an argument, the "parameter field" pointer.
+ * To satisfy C's strong-typing, it will always be declared
+ * of a consistent type. The routine itself can internally
+ * recast -- or ignore -- it, as needed.
+ * Many of these will refer to the Global Variable statbuf . It
+ * all such cases, it is used for Error reporting.
+ *
+ **************************************************************************** */
+
+/* **************************************************************************
+ *
+ * Function name: enter_tokz_esc
+ * Synopsis: When you start "Tokenizer Escape" mode.
+ *
+ * Associated Tokenizer directive: TOKENIZER[
+ *
+ * Process Explanation:
+ * Enter "Tokenizer Escape" mode ... Save the current tokenizer
+ * numeric conversion radix, and set the radix to sixteen
+ * (hexadecimal)
+ *
+ **************************************************************************** */
+
+static int saved_base ; /* Place to save the numeric conversion radix */
+
+void enter_tokz_esc( void )
+{
+ saved_base = base ;
+ base = 16;
+ in_tokz_esc = TRUE;
+}
+
+/* **************************************************************************
+ *
+ * Function name: end_tokz_esc
+ * Synopsis: When you've reached the end of "Tokenizer Escape" mode.
+ *
+ * Associated Tokenizer directive: ]TOKENIZER
+ *
+ * Process Explanation:
+ * Exit "Tokenizer Escape" mode, resume "Normal"-mode behavior.
+ * Restore the tokenizer numeric conversion radix to the value
+ * saved by tokenizer[ and exit "Tokenizer Escape" mode . . .
+ *
+ **************************************************************************** */
+
+static void end_tokz_esc( tic_param_t pfield )
+{
+ in_tokz_esc = FALSE;
+ base = saved_base ;
+}
+
+/* **************************************************************************
+ *
+ * Function name: tokz_esc_emit_byte
+ * Synopsis: Emit the byte found on the data-stack
+ *
+ * Associated Tokenizer directive: EMIT-BYTE
+ *
+ * Error Detection:
+ * If number on stack is larger than a byte: Truncate and Warn
+ *
+ **************************************************************************** */
+
+static void tokz_esc_emit_byte ( tic_param_t pfield )
+{
+ long num_on_stk = dpop();
+ u8 byt_to_emit = (u8)num_on_stk;
+ if ( byt_to_emit != num_on_stk )
+ {
+ tokenization_error( WARNING,
+ "Value on stack for %s command is 0x%0x. "
+ "Truncating to 0x%02x.\n",
+ strupr(statbuf), num_on_stk, byt_to_emit);
+ }
+ user_emit_byte(byt_to_emit);
+}
+
+/* **************************************************************************
+ *
+ * Function name: get_fcode_from_stack
+ * Synopsis: Retrieve an FCode value from the data-stack.
+ * Indicate if erroneous
+ *
+ * Inputs:
+ * Parameters:
+ * the_num Pointer to where to put the number
+ * the_action Phrase to be used in ERROR message
+ * Data-Stack Items:
+ * Top: Value to be retrieved
+ *
+ * Outputs:
+ * Returned Value: TRUE if number is within valid FCode range
+ * Supplied Pointers:
+ * *the_num Value retrieved from the data-stack
+ *
+ * Error Detection:
+ * If the number on the stack is larger than 16 bits, truncate
+ * it, with a WARNING message.
+ * If the (possibly truncated) number from the stack is larger
+ * than the legal maximum for an FCode (0x0fff), or
+ * less than the legal minimum (0x0800), issue an ERROR,
+ * leave the_num unchanged and return FALSE.
+ *
+ **************************************************************************** */
+
+static bool get_fcode_from_stack( u16 *the_num, char *the_action)
+{
+ bool retval = FALSE;
+ long num_on_stk = dpop();
+ u16 test_fcode = (u16)num_on_stk;
+ if ( test_fcode != num_on_stk )
+ {
+ tokenization_error( WARNING,
+ "Value on stack for %s command is 0x%0x. "
+ "Truncating to 0x%03x.\n",
+ strupr(statbuf), num_on_stk, test_fcode);
+ }
+ if ( ( test_fcode >= 0x800 ) && ( test_fcode <= 0xfff ) )
+ {
+ retval = TRUE;
+ *the_num = test_fcode;
+ }else{ tokenization_error( TKERROR, "Attempt to %s "
+ "0x%x, which violates limit specified by IEEE-1275. "
+ "Disallowing.\n", the_action, test_fcode );
+ }
+ return( retval );
+}
+
+
+/* **************************************************************************
+ *
+ * Function name: tokz_esc_next_fcode
+ * Synopsis: Set the next-fcode to the value on the data-stack
+ *
+ * Associated Tokenizer Directive: next-fcode
+ *
+ * Error Detection:
+ * If the number on the stack is not legal for an FCode, as
+ * detected by get_fcode_from_stack(), issue an ERROR
+ * message and don't change nextfcode.
+ *
+ * Printout:
+ * Advisory showing change in FCode token Assignment Counter
+ *
+ **************************************************************************** */
+
+static void tokz_esc_next_fcode( tic_param_t pfield )
+{
+ u16 test_fcode;
+
+ if ( get_fcode_from_stack( &test_fcode, "set next fcode to") )
+ {
+ if ( test_fcode == nextfcode )
+ {
+ tokenization_error( INFO, "FCode-token Assignment Counter "
+ "is unchanged from 0x%x.\n",
+ nextfcode);
+ }else{
+ tokenization_error( INFO, "FCode-token Assignment Counter "
+ "was 0x%x; has been %s to 0x%x.\n",
+ nextfcode,
+ test_fcode > nextfcode ? "advanced" : "reset",
+ test_fcode );
+ set_next_fcode( test_fcode);
+ }
+ }
+}
+
+/* **************************************************************************
+ *
+ * Function name: tokz_emit_fcode
+ * Synopsis: Emit the value on the data-stack as an FCode token
+ *
+ * Associated Tokenizer Directive: emit-fcode
+ *
+ * Error Detection:
+ * If the number on the stack is not legal for an FCode, as
+ * detected by get_fcode_from_stack(), issue an ERROR
+ * message and don't emit anything.
+ *
+ * Printout:
+ * Advisory showing FCode being emitted.
+ *
+ **************************************************************************** */
+
+static void tokz_emit_fcode( tic_param_t pfield )
+{
+ u16 test_fcode;
+
+ if ( get_fcode_from_stack( &test_fcode, "Emit FCode value of") )
+ {
+ tokenization_error( INFO,
+ "Emitting FCode value of 0x%x\n", test_fcode);
+ emit_fcode( test_fcode);
+ }
+}
+
+
+/* **************************************************************************
+ *
+ * Function name: zero_equals
+ * Synopsis: Boolean-inversion of item on top of stack.
+ * If zero, make it minus-one; if non-zero, make it zero.
+ *
+ * Associated FORTH word-name: 0=
+ *
+ **************************************************************************** */
+
+static void zero_equals ( tic_param_t pfield )
+{
+ *dstack = (*dstack == 0) ? -1 : 0 ;
+}
+
+/* **************************************************************************
+ *
+ * Function name: tokz_esc_swap
+ * Synopsis: "Tokenizer Escape" mode-time data-stack SWAP operation
+ *
+ * Associated FORTH word-name: swap
+ *
+ **************************************************************************** */
+
+static void tokz_esc_swap ( tic_param_t pfield )
+{
+ swap();
+}
+
+/* **************************************************************************
+ *
+ * Function name: tokz_esc_two_swap
+ * Synopsis: "Tokenizer Escape" mode-time data-stack 2SWAP operation
+ *
+ * Associated FORTH word-name: 2swap
+ *
+ **************************************************************************** */
+
+static void tokz_esc_two_swap ( tic_param_t pfield )
+{
+ two_swap();
+}
+
+/* **************************************************************************
+ *
+ * Function name: tokz_esc_noop
+ * Synopsis: "Tokenizer Escape" mode-time non-operation
+ *
+ * Associated FORTH word-name: noop
+ *
+ **************************************************************************** */
+
+static void tokz_esc_noop ( tic_param_t pfield )
+{
+ return;
+}
+
+#ifdef TOKZTEST /* For testing only */
+
+ static void tokz_esc_emit_string( tic_param_t pfield )
+ {
+ int lenny ;
+ lenny = strlen ( pfield.chr_ptr );
+ emit_token("b(\")");
+ emit_string(pfield.chr_ptr, lenny);
+ }
+
+#endif /* For testing only */
+
+/* **************************************************************************
+ *
+ * Function name: do_constant
+ * Synopsis: The function to perform when a named constant
+ * that was defined in "Tokenizer Escape" mode
+ * is invoked in "Tokenizer Escape" mode
+ *
+ * Associated FORTH word: A user-defined constant
+ *
+ * Inputs:
+ * Parameters:
+ * The param-field of the table-entry contains
+ * the value of the constant
+ *
+ * Outputs:
+ * Returned Value: NONE
+ * Items Pushed onto Data-Stack:
+ * Top: The table-entry's param-field's value
+ *
+ * Error Detection:
+ * An attempt, while operating in normal tokenization mode, to invoke
+ * a named constant that was defined in "Tokenizer Escape" mode
+ * will be detected by the main scanning loop, and need not
+ * concern us here.
+ *
+ **************************************************************************** */
+
+static void do_constant ( tic_param_t pfield )
+{
+ dpush( pfield.long_val );
+}
+
+/* **************************************************************************
+ *
+ * Function name: create_constant
+ * Synopsis: Create a user-defined constant that will be
+ * recognized in "Tokenizer Escape" mode
+ *
+ * Associated FORTH word-name: CONSTANT (when issued
+ * in "Tokenizer Escape" mode)
+ *
+ * Inputs:
+ * Parameters: NONE
+ * Global Variables:
+ * statbuf The constant's name will be taken from the
+ * next word in the input stream.
+ * do_constant The function assigned to the definition
+ * tokz_esc_vocab The "Tokenizer Escape" Vocabulary pointer
+ * Data-Stack Items:
+ * Top: The constant's value is popped from the stack
+ *
+ * Outputs:
+ * Returned Value: NONE
+ * Global Variables:
+ * statbuf Advanced to the next word in the input stream.
+ * tokz_esc_vocab Updated to point to new vocab entry.
+ * Memory Allocated:
+ * for the name and for the new entry.
+ * When Freed?
+ * When RESET-SYMBOLS is issued in "Tokenizer Escape" mode,
+ * or upon end of tokenization.
+ * Data-Stack, # of Items Popped: 1
+ *
+ * Error Detection:
+ * Failure to allocate memory is a Fatal Error.
+ * Warning on excessively long name
+ * Warning on duplicate name
+ * Name to be defined not in same file, ERROR
+ *
+ * Process Explanation:
+ * Get the next word, STRDUP it (which implicitly allocates memory).
+ * Get the number popped off the stack.
+ * Pass the pointer and the value to the add_tic_entry() routine.
+ *
+ **************************************************************************** */
+
+static void create_constant( tic_param_t pfield )
+{
+ char *c_name_space ; /* Space for copy of the name */
+ long valu ; /* Value, popped off the stack */
+ signed long wlen;
+
+ /* Get the name that is to be defined */
+ wlen = get_word();
+ if ( wlen <= 0 )
+ {
+ warn_unterm( TKERROR, "Constant definition", lineno);
+ return;
+ }
+
+ valu = dpop();
+
+ /* If ever we implement more than just this one
+ * defining-word in "Tokenizer Escape" mode,
+ * the lines from here to the end of the
+ * routine should be re-factored...
+ */
+ trace_creation( CONST, statbuf);
+
+ warn_if_duplicate( statbuf );
+ check_name_length( wlen );
+
+ c_name_space = strdup( statbuf );
+
+ add_tic_entry(
+ c_name_space,
+ do_constant,
+ (TIC_P_DEFLT_TYPE)valu,
+ CONST ,
+ 0 , NULL,
+ &tokz_esc_vocab );
+
+}
+
+/* **************************************************************************
+ *
+ * Let's create usable named constants for "Tokenizer Escape" mode.
+ * It's useful, it's easy and ... well, you get the idea.
+ *
+ **************************************************************************** */
+/* I don't think we need to any more
+static const int zero = 0 ;
+static const int minus_one = -1 ;
+static const char double_quote = '"' ;
+static const char close_paren = ')' ;
+ * Except for this next one, of course... */
+#ifdef TOKZTEST /* For testing only */
+ static const char date_me[] = DATE_STAMP;
+#endif /* For testing only */
+
+/* **************************************************************************
+ *
+ * Here, at long last, we define and initialize the structure containing
+ * all the functions we support in "Tokenizer Escape" mode.
+ * Let's call it the "Tokenizer Escape Vocabulary Table" and the
+ * pointer to it, the "Tokenizer Escape" Vocabulary.
+ * We can initialize the start of the "Tokenizer Escape" Vocabulary
+ * easily, except for the link-pointers, as an array.
+ *
+ **************************************************************************** */
+
+#define TKZESC_CONST(nam, pval) \
+ VALPARAM_TIC(nam, do_constant, pval, CONST )
+#define TKZ_ESC_FUNC(nam, afunc, pval, ifunc) \
+ DUALFUNC_TIC(nam, afunc, pval, ifunc, UNSPECIFIED)
+
+static tic_hdr_t tokz_esc_vocab_tbl[] = {
+ NO_PARAM_IGN( "]tokenizer" , end_tokz_esc ) ,
+
+ /* An IBM-ish synonym. */
+ NO_PARAM_IGN( "f]" , end_tokz_esc ) ,
+ /* An alternate synonym. */
+ NO_PARAM_IGN( "]f" , end_tokz_esc ) ,
+
+ NO_PARAM_TIC( "emit-byte" , tokz_esc_emit_byte ) ,
+ NO_PARAM_TIC( "next-fcode" , tokz_esc_next_fcode ) ,
+ NO_PARAM_TIC( "emit-fcode" , tokz_emit_fcode ) ,
+ NO_PARAM_TIC( "constant" , create_constant ) ,
+ NO_PARAM_TIC( "0=" , zero_equals ) ,
+ NO_PARAM_TIC( "swap" , tokz_esc_swap ) ,
+ NO_PARAM_TIC( "2swap" , tokz_esc_two_swap ) ,
+ NO_PARAM_TIC( "noop" , tokz_esc_noop ) ,
+ TKZESC_CONST( "false" , 0 ) ,
+ TKZESC_CONST( "true" , -1 ) ,
+ TKZ_ESC_FUNC( ".(" , user_message, ')', skip_user_message ) ,
+ TKZ_ESC_FUNC( ".\"" , user_message, '"', skip_user_message ) ,
+#ifdef TOKZTEST /* For testing only */
+ /* Data is a pointer to a constant string in the compiler; */
+ /* no need to copy, hence data_size can remain zero. */
+ /* We could almost use the Macro macro, except for the type. */
+ TKZ_ESC_FUNC( "emit-date" , tokz_esc_emit_string, date_me , NULL ) ,
+#endif /* For testing only */
+};
+
+/* **************************************************************************
+ *
+ * Also, keep a pointer to the "Built-In" position of
+ * the "Tokenizer Escape" Vocabulary
+ *
+ **************************************************************************** */
+
+static const tic_hdr_t *built_in_tokz_esc =
+ &tokz_esc_vocab_tbl[(sizeof(tokz_esc_vocab_tbl)/sizeof(tic_hdr_t))-1];
+
+/* **************************************************************************
+ *
+ * Function name: init_tokz_esc_vocab
+ * Synopsis: Initialize the "Tokenizer Escape" Vocabulary
+ * link-pointers dynamically.
+ *
+ **************************************************************************** */
+
+void init_tokz_esc_vocab ( void )
+{
+ static const int tokz_esc_vocab_max_indx =
+ sizeof(tokz_esc_vocab_tbl)/sizeof(tic_hdr_t) ;
+
+ tokz_esc_vocab = NULL ; /* Belt-and-suspenders... */
+ init_tic_vocab(tokz_esc_vocab_tbl,
+ tokz_esc_vocab_max_indx,
+ &tokz_esc_vocab );
+}
+
+/* **************************************************************************
+ *
+ * Function name: handle_tokz_esc
+ * Synopsis: Perform a function in the "Tokenizer Escape" Vocabulary
+ * Indicate whether the name is valid in this vocabulary.
+ * Handle "Tokenizer Escape" aliases implicitly.
+ *
+ * Inputs:
+ * Parameters:
+ * tname The name to handle
+ * Global Variables:
+ * tokz_esc_vocab Pointer to "Tokenizer Escape" Vocabulary
+ *
+ * Outputs:
+ * Returned Value: TRUE if the given name is valid in tokz_esc
+ *
+ * Process Explanation:
+ * Find the name and execute its associated function.
+ * If the name is not in the "Tokenizer Escape" Vocabulary,
+ * let the calling routine determine whether to try it
+ * out as a number or to print an error message.
+ *
+ **************************************************************************** */
+
+bool handle_tokz_esc( char *tname )
+{
+ bool retval = handle_tic_vocab( tname, tokz_esc_vocab );
+ return ( retval ) ;
+}
+
+
+/* **************************************************************************
+ *
+ * Function name: lookup_tokz_esc
+ * Synopsis: Return a pointer to the data-structure of the named
+ * word in the"Tokenizer Escape" Vocabulary
+ *
+ * Inputs:
+ * Parameters:
+ * name The given name for which to look
+ * Local Static Variables:
+ * tokz_esc_vocab Pointer to "Tokenizer Escape" Vocabulary
+ *
+ * Outputs:
+ * Returned Value: TRUE if name is found,
+ *
+ **************************************************************************** */
+
+tic_hdr_t *lookup_tokz_esc(char *name)
+{
+ tic_hdr_t *retval = lookup_tic_entry( name, tokz_esc_vocab );
+ return ( retval );
+}
+
+
+/* **************************************************************************
+ *
+ * Function name: exists_in_tokz_esc
+ * Synopsis: Confirm whether a given name exists in the
+ * "Tokenizer Escape" Vocabulary
+ *
+ * Inputs:
+ * Parameters:
+ * name The given name to confirm
+ * Global Variables:
+ * tokz_esc_vocab Pointer to "Tokenizer Escape" Vocabulary
+ *
+ * Outputs:
+ * Returned Value: TRUE if name is found,
+ *
+ **************************************************************************** */
+
+bool exists_in_tokz_esc(char *name)
+{
+ bool retval = exists_in_tic_vocab( name, tokz_esc_vocab );
+ return ( retval );
+}
+
+
+/* **************************************************************************
+ *
+ * Function name: create_tokz_esc_alias
+ * Synopsis: Create an alias in the "Tokenizer Escape" Vocabulary
+ *
+ * Associated FORTH word: ALIAS (in "Tokenizer Escape" mode)
+ *
+ * Inputs:
+ * Parameters:
+ * old_name Name of existing entry
+ * new_name New name for which to create an entry
+ *
+ * Outputs:
+ * Returned Value: TRUE if old_name found in "Tok Esc" vocab
+ * Global Variables:
+ * tokz_esc_vocab Will point to the new entry
+ * Memory Allocated:
+ * Memory for the new entry will be allocated
+ * by the support routine
+ * When Freed?
+ * When RESET-SYMBOLS is issued in "Tokenizer Escape" mode,
+ * or upon end of tokenization.
+ *
+ **************************************************************************** */
+
+bool create_tokz_esc_alias(char *new_name, char *old_name)
+{
+ bool retval = create_tic_alias( new_name, old_name, &tokz_esc_vocab );
+ return ( retval );
+}
+
+
+/* **************************************************************************
+ *
+ * Function name: reset_tokz_esc
+ * Synopsis: Reset the "Tokenizer Escape" Vocabulary to
+ * its "Built-In" position.
+ *
+ * Associated Tokenizer directive: RESET-SYMBOLS (when issued
+ * in "Tokenizer Escape" mode)
+ *
+ * Inputs:
+ * Parameters: NONE
+ * Global Variables:
+ * tokz_esc_vocab Pointer to "Tokenizer Escape" Vocabulary
+ * built_in_tokz_esc Pointer to "Built-In" position
+ *
+ * Outputs:
+ * Returned Value: NONE
+ * Global Variables:
+ * tokz_esc_vocab Reset to "Built-In" position
+ * Memory Freed
+ * Memory will be freed by the support routine
+ *
+ **************************************************************************** */
+
+void reset_tokz_esc( void )
+{
+ reset_tic_vocab( &tokz_esc_vocab, (tic_hdr_t *)built_in_tokz_esc);
+}
+
+/* **************************************************************************
+ *
+ * Function name: pop_next_fcode
+ * Synopsis: Vector off to the tokz_esc_next_fcode function,
+ * but without the pseudo-param. A retro-fit...
+ *
+ * Associated Tokenizer directive: FCODE-POP (issued in either mode)
+ *
+ * Inputs:
+ * Parameters: NONE
+ * Data-Stack Items:
+ * Top: Next FCode value, presumably saved
+ * by an FCODE-PUSH issued earlier.
+ *
+ * Outputs:
+ * Returned Value:
+ * Global Variables:
+ * nextfcode FCode token Assignment Counter
+ *
+ **************************************************************************** */
+
+void pop_next_fcode( void)
+{
+ tic_param_t dummy_param;
+ tokz_esc_next_fcode( dummy_param);
+}
Added: fcode-utils/toke/tokzesc.h
===================================================================
--- fcode-utils/toke/tokzesc.h (rev 0)
+++ fcode-utils/toke/tokzesc.h 2006-08-18 12:47:12 UTC (rev 76)
@@ -0,0 +1,50 @@
+#ifndef _TOKE_TOKZESC_H
+#define _TOKE_TOKZESC_H
+
+/*
+ * OpenBIOS - free your system!
+ * ( FCode tokenizer )
+ *
+ * This program is part of a free implementation of the IEEE 1275-1994
+ * Standard for Boot (Initialization Configuration) Firmware.
+ *
+ * Copyright (C) 2001-2005 Stefan Reinauer, <stepan(a)openbios.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA, 02110-1301 USA
+ *
+ */
+
+/* **************************************************************************
+ *
+ * External and Prototype definitions for functions that process
+ * activity in "Tokenizer Escape" mode
+ *
+ * (C) Copyright 2005 IBM Corporation. All Rights Reserved.
+ * Module Author: David L. Paktor dlpaktor(a)us.ibm.com
+ *
+ **************************************************************************** */
+
+#include "types.h"
+#include "ticvocab.h"
+
+void init_tokz_esc_vocab( void );
+bool create_tokz_esc_alias(char *new_name, char *old_name);
+void enter_tokz_esc( void );
+bool handle_tokz_esc( char *tname );
+tic_hdr_t *lookup_tokz_esc(char *name);
+bool exists_in_tokz_esc(char *name);
+void reset_tokz_esc( void );
+void pop_next_fcode( void);
+
+#endif /* _TOKE_TOKZESC_H */
Added: fcode-utils/toke/tracesyms.c
===================================================================
--- fcode-utils/toke/tracesyms.c (rev 0)
+++ fcode-utils/toke/tracesyms.c 2006-08-18 12:47:12 UTC (rev 76)
@@ -0,0 +1,172 @@
+/*
+ * OpenBIOS - free your system!
+ * ( FCode tokenizer )
+ *
+ * This program is part of a free implementation of the IEEE 1275-1994
+ * Standard for Boot (Initialization Configuration) Firmware.
+ *
+ * Copyright (C) 2001-2005 Stefan Reinauer, <stepan(a)openbios.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA, 02110-1301 USA
+ *
+ */
+
+/* **************************************************************************
+ *
+ * Support routines for "Trace-Symbols" debugging feature
+ *
+ * (C) Copyright 2006 IBM Corporation. All Rights Reserved.
+ * Module Author: David L. Paktor dlpaktor(a)us.ibm.com
+ *
+ **************************************************************************** */
+
+/* **************************************************************************
+ *
+ * Functions Exported:
+ * add_to_trace_list Add the given name to the Trace List
+ * show_initial_traces Show pre-defined names the user
+ * asked to Trace (if any)
+ * is_on_trace_list Indicate whether the given name is
+ * on the Trace List
+ *
+ **************************************************************************** */
+
+#include <string.h>
+
+#include "tracesyms.h"
+#include "errhandler.h"
+
+
+/* **************************************************************************
+ *
+ * Internal Static Variables
+ * trace_list Pointer to last entry in the Trace List linked-list
+ * data structure
+ *
+ *
+ *
+ **************************************************************************** */
+
+/* **************************************************************************
+ *
+ * Internal (Static) Structures:
+ * trace_entry_t Linked-list of entries in the Trace List
+ *
+ * Fields:
+ * tracee Name of the symbol to be traced
+ * prev Pointer to previous entry in the linked-list
+ *
+ **************************************************************************** */
+
+typedef struct trace_entry {
+ char *tracee;
+ struct trace_entry *prev;
+} trace_entry_t;
+
+static trace_entry_t *trace_list = NULL;
+
+
+
+/* **************************************************************************
+ *
+ * Function name: add_to_trace_list
+ * Synopsis: Add the given name to the Trace List
+ *
+ *
+ * Inputs:
+ * Parameters:
+ * trace_symb Name of the symbol to be added
+ * Local Static Variables:
+ * trace_list Pointer to the Trace List
+ *
+ * Outputs:
+ * Returned Value: NONE
+ * Local Static Variables:
+ * trace_list Points to new entry in Trace List
+ * Memory Allocated
+ * For Trace List entry
+ * For copy of Symbol Name
+ * When Freed?
+ * Never. Well, only on termination of the program. Trace-list
+ * endures for the entire batch of tokenizations.
+ *
+ * Error Detection:
+ * Memory allocation failure is a FATAL error.
+ *
+ **************************************************************************** */
+
+void add_to_trace_list( char *trace_symb)
+{
+ trace_entry_t *new_t_l_entry = safe_malloc( sizeof( trace_entry_t),
+ "adding to trace-list");
+ new_t_l_entry->tracee = strdup( trace_symb);
+ new_t_l_entry->prev = trace_list;
+
+ trace_list = new_t_l_entry;
+}
+
+
+/* **************************************************************************
+ *
+ * Function name: is_on_trace_list
+ * Synopsis: Indicate whether the given name is on the Trace List
+ *
+ * Inputs:
+ * Parameters:
+ * symb_name Symbol-name to test
+ * Local Static Variables:
+ * trace_list Pointer to the Trace List
+ *
+ * Outputs:
+ * Returned Value: TRUE if Symbol-name is on the Trace List
+ *
+ **************************************************************************** */
+
+bool is_on_trace_list( char *symb_name)
+{
+ bool retval = FALSE;
+ trace_entry_t *test_entry = trace_list;
+ while ( test_entry != NULL )
+ {
+ if ( strcasecmp( symb_name, test_entry->tracee) == 0 )
+ {
+ retval = TRUE;
+ break;
+ }
+ test_entry = test_entry->prev;
+ }
+ return ( retval );
+}
+
+
+/* **************************************************************************
+ *
+ * Still to be done:
+ * Implement a function -- name it show_initial_traces --
+ * that will show any pre-defined names the user asked
+ * to Trace. That is, if any of the names the user asked
+ * to Trace belongs to a pre-defined function, macro or
+ * directive, then, at the beginning of the output, issue
+ * Advisory Messages identifying the scope of those names.
+ *
+ * E.g, if the user had -T 3DUP -T SWAP the function would
+ * issue Messages like:
+ * 3DUP is pre-defined as a Macro with Global scope
+ * SWAP is pre-defined with Global scope
+ * SWAP is pre-defined in Tokenizer-Escape mode
+ *
+ * The names would, of course, remain on the Trace List and
+ * any re-definitions of them would be reported.
+ *
+ **************************************************************************** */
Added: fcode-utils/toke/tracesyms.h
===================================================================
--- fcode-utils/toke/tracesyms.h (rev 0)
+++ fcode-utils/toke/tracesyms.h 2006-08-18 12:47:12 UTC (rev 76)
@@ -0,0 +1,48 @@
+#ifndef _TOKE_TRACESYMS_H
+#define _TOKE_TRACESYMS_H
+
+/*
+ * OpenBIOS - free your system!
+ * ( FCode tokenizer )
+ *
+ * This program is part of a free implementation of the IEEE 1275-1994
+ * Standard for Boot (Initialization Configuration) Firmware.
+ *
+ * Copyright (C) 2001-2005 Stefan Reinauer, <stepan(a)openbios.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA, 02110-1301 USA
+ *
+ */
+
+/* **************************************************************************
+ *
+ * External/Prototype/Structure definitions for "Trace-Symbols" feature
+ *
+ * (C) Copyright 2005 IBM Corporation. All Rights Reserved.
+ * Module Author: David L. Paktor dlpaktor(a)us.ibm.com
+ *
+ **************************************************************************** */
+
+#include "types.h"
+
+/* ************************************************************************** *
+ *
+ * Function Prototypes / Functions Exported:
+ *
+ **************************************************************************** */
+
+void add_to_trace_list( char *trace_symb);
+bool is_on_trace_list( char *symb_name);
+
+#endif /* _TOKE_TRACESYMS_H */
Added: fcode-utils/toke/usersymbols.c
===================================================================
--- fcode-utils/toke/usersymbols.c (rev 0)
+++ fcode-utils/toke/usersymbols.c 2006-08-18 12:47:12 UTC (rev 76)
@@ -0,0 +1,363 @@
+/*
+ * OpenBIOS - free your system!
+ * ( FCode tokenizer )
+ *
+ * This program is part of a free implementation of the IEEE 1275-1994
+ * Standard for Boot (Initialization Configuration) Firmware.
+ *
+ * Copyright (C) 2001-2005 Stefan Reinauer, <stepan(a)openbios.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA, 02110-1301 USA
+ *
+ */
+
+/* **************************************************************************
+ *
+ * General-purpose support functions for
+ * User-defined command-line compilation-control symbols
+ *
+ * (C) Copyright 2005 IBM Corporation. All Rights Reserved.
+ * Module Author: David L. Paktor dlpaktor(a)us.ibm.com
+ *
+ **************************************************************************** */
+
+/* **************************************************************************
+ *
+ * The syntax for user-defined command-line compilation-control symbols
+ * is <NAME>[=<VALUE>]
+ *
+ * The name is always required; the equal-sign and value is optional.
+ * If you wish the "value" to contain spaces or quotes, you can
+ * accomplish that using the shell escape conventions.
+ *
+ * The operations that can be performed upon these symbols will be
+ * described by the operators that use them as operands, but,
+ * broadly speaking, the tests will either be to simply verify
+ * the existence of a symbol, or to evaluate the defined value.
+ *
+ * Once a symbol is defined on the command-line, it stays in effect
+ * for the duration of the entire batch of tokenizations (i.e.,
+ * if there are multiple input files named on the command line).
+ * Also, there are no symbols defined at the outset. Therefore,
+ * there is no need for either an "init" or a "reset" routine.
+ *
+ **************************************************************************** */
+
+/* **************************************************************************
+ *
+ * User-defined command-line compilation-control symbols are
+ * implemented as a String-Substitution-type vocabulary.
+ *
+ **************************************************************************** */
+
+/* **************************************************************************
+ *
+ * Functions Exported:
+ * add_user_symbol Add a user-defined symbol to the list
+ * lookup_user_symbol Look for a user-defined symbol, return
+ * the assigned value.
+ * exists_as_user_symbol Confirm whether a given name exists
+ * as a user-defined symbol.
+ * eval_user_symbol Tokenize the value assigned to a user
+ * symbol.
+ * list_user_symbols Print the list of user-defined symbols
+ * for the Logfile.
+ *
+ **************************************************************************** */
+
+/* **************************************************************************
+ *
+ * Still to be done:
+ * Convert the handling of user-defined symbols to the T.I.C.
+ * data-structure and its support routines. This should
+ * eliminate any further need of String-Substitution-type
+ * vocabularies. User-defined symbols will, however, still
+ * need to be a separate vocabulary from the Global, because
+ * they are required to stay in effect for the duration of
+ * the entire batch of tokenizations...
+ * (Afterthought: This is only true for user-defined symbols that
+ * were created on the command-line; if we ever allow symbols
+ * to be defined in the Source file, they should be as volatile
+ * as anything else that comes from a source file...
+ * Putting source-file-derived user-defined symbols into the Global
+ * Vocabulary could be a quasi-simple way to accomplish this.)
+ *
+ * Enable the definition of user-symbols from the Source file, using
+ * a syntax like: [define] symbol or [define] symbol=<value>
+ * (How to allow spaces into the <value>? Maybe make the syntax
+ * [define] symbol = <value components to end of line>
+ * delimited in a manner similar to Macro definitions.
+ * There might be a need to be able to [undefine] a user-symbol
+ * that would entail defining an unlink_tic_entry function.
+ * Not difficult; just keeping this around as a reminder...
+ *
+ **************************************************************************** */
+
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#if defined(__linux__) && ! defined(__USE_BSD)
+#define __USE_BSD
+#endif
+#include <string.h>
+
+#include "errhandler.h"
+#include "strsubvocab.h"
+#include "usersymbols.h"
+#include "scanner.h"
+
+
+/* **************************************************************************
+ *
+ * Internal Static Variables
+ * user_symbol_list Pointer to the "tail" of the list of
+ * user-defined symbols.
+ * user_symbol_count Count of how many are defined
+ *
+ **************************************************************************** */
+
+static str_sub_vocab_t *user_symbol_list = NULL;
+static int user_symbol_count = 0;
+
+/* **************************************************************************
+ *
+ * Function name: add_user_symbol
+ * Synopsis: Add a user-defined symbol to the list
+ *
+ * Inputs:
+ * Parameters:
+ * raw_symb The string as supplied on the command-line.
+ * Local Static Variables:
+ * user_symbol_list Pointer to the list of user-defined symbols.
+ *
+ * Outputs:
+ * Returned Value: NONE
+ * Local Static Variables:
+ * user_symbol_list Will be updated.
+ * user_symbol_count Will be incremented
+ * Memory Allocated:
+ * for the string(s) and the new entry
+ * When Freed?
+ * Never. Well, only on termination of the program. User-defined
+ * symbols endure for the entire batch of tokenizations.
+ *
+ * Process Explanation:
+ * The string in raw_symb may or may not include the optional
+ * equal-sign and value pair. If the equal-sign is present,
+ * the remainder of the string will become the "value" that
+ * will be returned by the "lookup" routine.
+ * Memory for the name string and for the value, if there is one,
+ * will be allocated here, in one step. Memory for the data
+ * structure itself will be allocated by the support routine.
+ *
+ **************************************************************************** */
+
+void add_user_symbol(char *raw_symb)
+{
+ char *symb_nam;
+ char *symb_valu;
+
+ symb_nam = strdup(raw_symb);
+ symb_valu = strchr(symb_nam,'=');
+ if ( symb_valu != NULL )
+ {
+ *symb_valu = 0;
+ symb_valu++;
+ }
+ add_str_sub_entry(symb_nam, symb_valu, &user_symbol_list );
+ user_symbol_count++;
+}
+
+
+/* **************************************************************************
+ *
+ * Function name: lookup_user_symbol
+ * Synopsis: Look for the given name as user-defined symbol, return
+ * the assigned value.
+ *
+ * Inputs:
+ * Parameters:
+ * symb_nam The name for which to look.
+ * Local Static Variables:
+ * user_symbol_list Pointer to the list of user-defined symbols.
+ *
+ * Outputs:
+ * Returned Value: Pointer to the "value" string, or NULL
+ * pointer if the name was not found.
+ * May also be NULL if "value" is NULL.
+ *
+ **************************************************************************** */
+
+char *lookup_user_symbol(char *symb_nam)
+{
+ char *symb_valu;
+
+ symb_valu = lookup_str_sub(symb_nam, user_symbol_list );
+ return (symb_valu);
+}
+
+/* **************************************************************************
+ *
+ * Function name: exists_as_user_symbol
+ * Synopsis: Confirm whether a given name exists
+ * as a user-defined symbol.
+ *
+ * Inputs:
+ * Parameters:
+ * symb_nam The name for which to look.
+ * Local Static Variables:
+ * user_symbol_list Pointer to the list of user-defined symbols.
+ *
+ * Outputs:
+ * Returned Value: TRUE if the name is found
+ *
+ **************************************************************************** */
+
+bool exists_as_user_symbol(char *symb_nam)
+{
+ bool retval;
+
+ retval = exists_in_str_sub(symb_nam, user_symbol_list );
+ return (retval);
+}
+
+/* **************************************************************************
+ *
+ * Function name: eval_user_symbol
+ * Synopsis: Tokenize the value assigned to a user-symbol.
+ *
+ * Associated Tokenizer directive (synonyms): [DEFINED]
+ * #DEFINED
+ * [#DEFINED]
+ *
+ * Syntax Notes:
+ * (1) The User-Defined-Symbol must appear
+ * on the same line as the directive.
+ * (2) This is not (yet) implemented in contexts that
+ * directly read input from the stream, e.g.,
+ * after ['] or after H# etc.
+ *
+ * Inputs:
+ * Parameters:
+ * symbol The User-Defined-Symbol to evaluate
+ * Local Static Variables:
+ * user_symbol_list Pointer to the list of user-defined symbols.
+ *
+ * Outputs:
+ * Returned Value: NONE
+ * The assigned value will be tokenized.
+ *
+ * Error Detection:
+ * Calling routine is responsible for verifying that the user-symbol
+ * is on the same line as the directive.
+ * WARNING if the symbol is not found or has no assigned value.
+ *
+ * Process Explanation:
+ * Look up the parameter in the User Symbol List, and retrieve
+ * its associated value.
+ * If it is not found, or if it has no associated value, issue
+ * a WARNING and do nothing further. Otherwise...
+ * Interpret the associated value as though it were source.
+ *
+ * Still to be done:
+ * Hook-in this routine to the processing of: ['] F['] H# FLOAD
+ * etc., and wherever else it might be needed or useful.
+ *
+ **************************************************************************** */
+
+void eval_user_symbol(char *symbol )
+{
+ char *symb_valu;
+ symb_valu = lookup_user_symbol(symbol );
+ if ( symb_valu == NULL )
+ {
+ tokenization_error ( WARNING,
+ "No value assigned to command-line symbol %s\n", symbol );
+ }else{
+ eval_string( symb_valu );
+ }
+
+}
+/* **************************************************************************
+ *
+ * Function name: list_user_symbols
+ * Synopsis: Print the list of user symbols for the Logfile.
+ *
+ * Inputs:
+ * Parameters: NONE
+ * Local Static Variables:
+ * user_symbol_list Pointer to the list of user-defined symbols.
+ * user_symbol_count Count of user-defined symbols.
+ *
+ * Outputs:
+ * Returned Value: NONE
+ * Printout: List of user symbols and their definitions;
+ * nothing if user_symbol_list is NULL.
+ *
+ * Process Explanation:
+ * We want to display the symbols in the same order they were created.
+ * We will:
+ * Allocate a temporary array of pointers.
+ * Step backwards through the linked-list of symbols, and
+ * enter their pointers into the array.
+ * Collect the maximum length of the symbol names.
+ * Step through the array in the reverse order, printing
+ * as we go.
+ * Use the max name length to space the equal-signs evenly
+ * Free the temporary array.
+ *
+ **************************************************************************** */
+
+void list_user_symbols(void )
+{
+ str_sub_vocab_t *curr;
+
+ if ( user_symbol_list != NULL )
+ {
+ /* Collect the pointers and max length */
+ str_sub_vocab_t **symb_ptr;
+ int indx = 0;
+ int maxlen = 0;
+
+ symb_ptr = (str_sub_vocab_t **)safe_malloc(
+ (sizeof(str_sub_vocab_t *) * user_symbol_count),
+ "collecting user-symbol pointers" );
+
+ for (curr = user_symbol_list ; curr != NULL ; curr=curr->next)
+ {
+ symb_ptr[indx] = curr;
+ indx++;
+ if ( strlen(curr->name) > maxlen ) maxlen = strlen(curr->name);
+ }
+
+ /* Now print 'em out */
+ printf("\nUser-Defined Symbols:\n");
+ while ( indx > 0 )
+ {
+ indx--;
+ curr = symb_ptr[indx];
+ printf("\t%s",curr->name);
+ if ( curr->alias != NULL )
+ {
+ int strindx;
+ for ( strindx = strlen(curr->name) ;
+ strindx < maxlen ; strindx++ ) printf(" ");
+ printf(" = %s",curr->alias);
+ }
+ printf("\n");
+ }
+ free(symb_ptr);
+ }
+}
Added: fcode-utils/toke/usersymbols.h
===================================================================
--- fcode-utils/toke/usersymbols.h (rev 0)
+++ fcode-utils/toke/usersymbols.h 2006-08-18 12:47:12 UTC (rev 76)
@@ -0,0 +1,46 @@
+#ifndef _TOKE_USERSYMBOLS_H
+#define _TOKE_USERSYMBOLS_H
+
+
+/*
+ * OpenBIOS - free your system!
+ * ( FCode tokenizer )
+ *
+ * This program is part of a free implementation of the IEEE 1275-1994
+ * Standard for Boot (Initialization Configuration) Firmware.
+ *
+ * Copyright (C) 2001-2005 Stefan Reinauer, <stepan(a)openbios.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA, 02110-1301 USA
+ *
+ */
+
+/* **************************************************************************
+ *
+ * Prototype/External Declarations for general-purpose functions
+ * for support of User-defined command-line compilation-control
+ * symbols, as defined in usersymbols.c
+ *
+ * (C) Copyright 2005 IBM Corporation. All Rights Reserved.
+ * Module Author: David L. Paktor dlpaktor(a)us.ibm.com
+ *
+ **************************************************************************** */
+
+void add_user_symbol(char *raw_symb);
+char *lookup_user_symbol(char *symb_nam);
+bool exists_as_user_symbol(char *symb_nam);
+void eval_user_symbol(char *symbol );
+void list_user_symbols(void );
+
+#endif /* _TOKE_USERSYMBOLS_H */
Added: fcode-utils/toke/vocabfuncts.h
===================================================================
--- fcode-utils/toke/vocabfuncts.h (rev 0)
+++ fcode-utils/toke/vocabfuncts.h 2006-08-18 12:47:12 UTC (rev 76)
@@ -0,0 +1,92 @@
+#ifndef _TOKE_VOCABFUNCTS_H
+#define _TOKE_VOCABFUNCTS_H
+
+/*
+ * OpenBIOS - free your system!
+ * ( FCode tokenizer )
+ *
+ * This program is part of a free implementation of the IEEE 1275-1994
+ * Standard for Boot (Initialization Configuration) Firmware.
+ *
+ * Copyright (C) 2001-2005 Stefan Reinauer, <stepan(a)openbios.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA, 02110-1301 USA
+ *
+ */
+
+/* **************************************************************************
+ *
+ * External/Prototype definitions for Vocabulary functions
+ * in dictionary.c for Tokenizer
+ *
+ * (C) Copyright 2005 IBM Corporation. All Rights Reserved.
+ * Module Author: David L. Paktor dlpaktor(a)us.ibm.com
+ *
+ **************************************************************************** */
+
+
+#include "types.h"
+#include "ticvocab.h"
+
+
+/* ************************************************************************** *
+ *
+ * Global Variables Exported
+ *
+ **************************************************************************** */
+
+extern bool scope_is_global;
+
+/* ************************************************************************** *
+ *
+ * Function Prototypes / Functions Exported:
+ *
+ **************************************************************************** */
+
+
+tic_hdr_t *lookup_core_word( char *tname);
+bool exists_in_core( char *name);
+bool handle_core_word( char *tname );
+bool create_core_alias( char *new_name, char *old_name);
+
+void enter_global_scope( void );
+void resume_device_scope( void );
+
+tic_hdr_t *lookup_current( char *name);
+bool exists_in_current( char *tname);
+bool handle_current( char *tname );
+tic_hdr_t *lookup_in_dev_node( char *tname);
+void add_to_current( char *name,
+ TIC_P_DEFLT_TYPE fc_token,
+ fwtoken definer,
+ bool define_token);
+void hide_last_colon ( void );
+void reveal_last_colon ( void );
+bool create_current_alias( char *new_name, char *old_name );
+
+void emit_token( const char *fc_name);
+tic_hdr_t *lookup_token( char *tname);
+bool entry_is_token( tic_hdr_t *test_entry );
+void token_entry_warning( tic_hdr_t *t_entry);
+
+tic_hdr_t *lookup_shared_word( char *tname);
+bool handle_shared_word( char *tname );
+tic_hdr_t *lookup_shared_f_exec_word( char *tname);
+
+void init_dictionary( void );
+void reset_normal_vocabs( void );
+void reset_vocabs( void );
+
+
+#endif /* _TOKE_VOCABFUNCTS_H */
1
0
Author: stepan
Date: 2006-08-18 11:45:11 +0200 (Fri, 18 Aug 2006)
New Revision: 75
Modified:
fcode-utils/romheaders/romheaders.c
Log:
add missing header
Modified: fcode-utils/romheaders/romheaders.c
===================================================================
--- fcode-utils/romheaders/romheaders.c 2006-08-18 09:07:34 UTC (rev 74)
+++ fcode-utils/romheaders/romheaders.c 2006-08-18 09:45:11 UTC (rev 75)
@@ -1,3 +1,27 @@
+/*
+ * OpenBIOS - free your system!
+ * ( romheaders utility )
+ *
+ * This program is part of a free implementation of the IEEE 1275-1994
+ * Standard for Boot (Initialization Configuration) Firmware.
+ *
+ * Copyright (C) 2001-2005 Stefan Reinauer, <stepan(a)openbios.org>
+ * Copyright (C) 2006 coresystems GmbH <info(a)coresystems.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA, 02110-1301 USA
+ *
+ */
#include <stdio.h>
@@ -12,9 +36,6 @@
#define PCI_DATA_HDR (u32) ( ('R' << 24) | ('I' << 16) | ('C' << 8) | 'P' )
-char *rom=NULL;
-size_t romlen=0;
-
typedef struct {
u16 signature;
u8 reserved[0x16];
@@ -37,6 +58,8 @@
u16 reserved_2;
} pci_data_t;
+char *rom=NULL;
+size_t romlen=0;
/* make this endian safe without fancy system headers */
static u16 little_word(u16 val)
1
0