summaryrefslogtreecommitdiff
path: root/src/bin/embryo
diff options
context:
space:
mode:
authorVincent Torri <vincent.torri@gmail.com>2012-10-26 09:01:52 +0000
committerVincent Torri <vincent.torri@gmail.com>2012-10-26 09:01:52 +0000
commit5bdb5d376373dab8bf624388cac520094be95b63 (patch)
treee494c3a000eeb506e63cd55a77f310767633e0d8 /src/bin/embryo
parent124e0d4afdff0937d8be8014f4dea5f78aa9f76f (diff)
merge: add embryo
please check and report problems (not cosmetic ones) someone should update the efl.spec.in file, i don't know that stuff SVN revision: 78512
Diffstat (limited to 'src/bin/embryo')
-rw-r--r--src/bin/embryo/Makefile.am49
-rw-r--r--src/bin/embryo/embryo_cc_amx.h226
-rw-r--r--src/bin/embryo/embryo_cc_osdefs.h0
-rw-r--r--src/bin/embryo/embryo_cc_prefix.c61
-rw-r--r--src/bin/embryo/embryo_cc_prefix.h6
-rw-r--r--src/bin/embryo/embryo_cc_sc.h673
-rw-r--r--src/bin/embryo/embryo_cc_sc1.c4083
-rw-r--r--src/bin/embryo/embryo_cc_sc2.c2779
-rw-r--r--src/bin/embryo/embryo_cc_sc3.c2438
-rw-r--r--src/bin/embryo/embryo_cc_sc4.c1310
-rw-r--r--src/bin/embryo/embryo_cc_sc5.c156
-rw-r--r--src/bin/embryo/embryo_cc_sc5.scp317
-rw-r--r--src/bin/embryo/embryo_cc_sc6.c1080
-rw-r--r--src/bin/embryo/embryo_cc_sc7.c688
-rw-r--r--src/bin/embryo/embryo_cc_sc7.scp1473
-rw-r--r--src/bin/embryo/embryo_cc_scexpand.c53
-rw-r--r--src/bin/embryo/embryo_cc_sclist.c293
-rw-r--r--src/bin/embryo/embryo_cc_scvars.c88
18 files changed, 15773 insertions, 0 deletions
diff --git a/src/bin/embryo/Makefile.am b/src/bin/embryo/Makefile.am
new file mode 100644
index 0000000000..e31a5bee62
--- /dev/null
+++ b/src/bin/embryo/Makefile.am
@@ -0,0 +1,49 @@
1
2MAINTAINERCLEANFILES = Makefile.in
3
4AM_CPPFLAGS = \
5-I$(top_srcdir)/src/lib/eina \
6-I$(top_srcdir)/src/lib/embryo \
7-I$(top_builddir)/src/lib/eina \
8-I$(top_builddir)/src/lib/embryo \
9-DPACKAGE_BIN_DIR=\"$(bindir)\" \
10-DPACKAGE_LIB_DIR=\"$(libdir)\" \
11-DPACKAGE_DATA_DIR=\"$(datadir)/$(PACKAGE)\" \
12@EFL_CFLAGS@
13
14if HAVE_WINDOWS
15AM_CPPFLAGS += \
16-I$(top_srcdir)/src/lib/evil \
17-I$(top_builddir)/src/lib/evil
18endif
19
20bin_PROGRAMS = embryo_cc
21
22embryo_cc_SOURCES = \
23embryo_cc_amx.h \
24embryo_cc_sc.h \
25embryo_cc_sc1.c \
26embryo_cc_sc2.c \
27embryo_cc_sc3.c \
28embryo_cc_sc4.c \
29embryo_cc_sc5.c \
30embryo_cc_sc6.c \
31embryo_cc_sc7.c \
32embryo_cc_scexpand.c \
33embryo_cc_sclist.c \
34embryo_cc_scvars.c \
35embryo_cc_prefix.c \
36embryo_cc_prefix.h
37
38embryo_cc_LDADD = \
39$(top_builddir)/src/lib/embryo/libembryo.la \
40$(top_builddir)/src/lib/eina/libeina.la \
41-lm
42
43if HAVE_WINDOWS
44embryo_cc_LDADD += $(top_builddir)/src/lib/evil/libevil.la
45endif
46
47EXTRA_DIST = \
48embryo_cc_sc5.scp \
49embryo_cc_sc7.scp
diff --git a/src/bin/embryo/embryo_cc_amx.h b/src/bin/embryo/embryo_cc_amx.h
new file mode 100644
index 0000000000..0118e2d2af
--- /dev/null
+++ b/src/bin/embryo/embryo_cc_amx.h
@@ -0,0 +1,226 @@
1/* Abstract Machine for the Small compiler
2 *
3 * Copyright (c) ITB CompuPhase, 1997-2003
4 *
5 * This software is provided "as-is", without any express or implied warranty.
6 * In no event will the authors be held liable for any damages arising from
7 * the use of this software.
8 *
9 * Permission is granted to anyone to use this software for any purpose,
10 * including commercial applications, and to alter it and redistribute it
11 * freely, subject to the following restrictions:
12 *
13 * 1. The origin of this software must not be misrepresented; you must not
14 * claim that you wrote the original software. If you use this software in
15 * a product, an acknowledgment in the product documentation would be
16 * appreciated but is not required.
17 * 2. Altered source versions must be plainly marked as such, and must not be
18 * misrepresented as being the original software.
19 * 3. This notice may not be removed or altered from any source distribution.
20 *
21 * Version: $Id$
22 */
23
24#ifndef EMBRYO_CC_AMX_H
25#define EMBRYO_CC_AMX_H
26
27#include <sys/types.h>
28
29/* calling convention for all interface functions and callback functions */
30
31/* File format version Required AMX version
32 * 0 (original version) 0
33 * 1 (opcodes JUMP.pri, SWITCH and CASETBL) 1
34 * 2 (compressed files) 2
35 * 3 (public variables) 2
36 * 4 (opcodes SWAP.pri/alt and PUSHADDR) 4
37 * 5 (tagnames table) 4
38 * 6 (reformatted header) 6
39 * 7 (name table, opcodes SYMTAG & SYSREQ.D) 7
40 */
41#define CUR_FILE_VERSION 7 /* current file version; also the current AMX version */
42#define MIN_FILE_VERSION 6 /* lowest supported file format version for the current AMX version */
43#define MIN_AMX_VERSION 7 /* minimum AMX version needed to support the current file format */
44
45#if !defined CELL_TYPE
46#define CELL_TYPE
47 typedef unsigned int ucell;
48 typedef int cell;
49#endif
50
51 struct tagAMX;
52 typedef cell(*AMX_NATIVE) (struct tagAMX * amx,
53 cell * params);
54 typedef int (* AMX_CALLBACK) (struct tagAMX * amx, cell index,
55 cell * result, cell * params);
56 typedef int (* AMX_DEBUG) (struct tagAMX * amx);
57
58 typedef struct
59 {
60 char *name;
61 AMX_NATIVE func ;
62 } AMX_NATIVE_INFO ;
63
64#define AMX_USERNUM 4
65#define sEXPMAX 19 /* maximum name length for file version <= 6 */
66#define sNAMEMAX 31 /* maximum name length of symbol name */
67
68#if defined (_MSC_VER) || (defined (__SUNPRO_C) && __SUNPRO_C < 0x5100)
69# pragma pack(1)
70# define EMBRYO_STRUCT_PACKED
71#elif defined (__GNUC__) || (defined (__SUNPRO_C) && __SUNPRO_C >= 0x5100)
72# define EMBRYO_STRUCT_PACKED __attribute__((packed))
73#else
74# define EMBRYO_STRUCT_PACKED
75#endif
76
77 typedef struct tagAMX_FUNCSTUB
78 {
79 unsigned int address;
80 char name[sEXPMAX + 1];
81 } EMBRYO_STRUCT_PACKED AMX_FUNCSTUB;
82
83/* The AMX structure is the internal structure for many functions. Not all
84 * fields are valid at all times; many fields are cached in local variables.
85 */
86 typedef struct tagAMX
87 {
88 unsigned char *base; /* points to the AMX header ("amxhdr") plus the code, optionally also the data */
89 unsigned char *data; /* points to separate data+stack+heap, may be NULL */
90 AMX_CALLBACK callback;
91 AMX_DEBUG debug ; /* debug callback */
92 /* for external functions a few registers must be accessible from the outside */
93 cell cip ; /* instruction pointer: relative to base + amxhdr->cod */
94 cell frm ; /* stack frame base: relative to base + amxhdr->dat */
95 cell hea ; /* top of the heap: relative to base + amxhdr->dat */
96 cell hlw ; /* bottom of the heap: relative to base + amxhdr->dat */
97 cell stk ; /* stack pointer: relative to base + amxhdr->dat */
98 cell stp ; /* top of the stack: relative to base + amxhdr->dat */
99 int flags ; /* current status, see amx_Flags() */
100 /* for assertions and debug hook */
101 cell curline ;
102 cell curfile ;
103 int dbgcode ;
104 cell dbgaddr ;
105 cell dbgparam ;
106 char *dbgname;
107 /* user data */
108 long usertags[AMX_USERNUM];
109 void *userdata[AMX_USERNUM];
110 /* native functions can raise an error */
111 int error ;
112 /* the sleep opcode needs to store the full AMX status */
113 cell pri ;
114 cell alt ;
115 cell reset_stk ;
116 cell reset_hea ;
117 cell *syscall_d; /* relocated value/address for the SYSCALL.D opcode */
118 } EMBRYO_STRUCT_PACKED AMX;
119
120/* The AMX_HEADER structure is both the memory format as the file format. The
121 * structure is used internaly.
122 */
123 typedef struct tagAMX_HEADER
124 {
125 int size ; /* size of the "file" */
126 unsigned short magic ; /* signature */
127 char file_version ; /* file format version */
128 char amx_version ; /* required version of the AMX */
129 unsigned short flags ;
130 unsigned short defsize ; /* size of a definition record */
131 int cod ; /* initial value of COD - code block */
132 int dat ; /* initial value of DAT - data block */
133 int hea ; /* initial value of HEA - start of the heap */
134 int stp ; /* initial value of STP - stack top */
135 int cip ; /* initial value of CIP - the instruction pointer */
136 int publics ; /* offset to the "public functions" table */
137 int natives ; /* offset to the "native functions" table */
138 int libraries ; /* offset to the table of libraries */
139 int pubvars ; /* the "public variables" table */
140 int tags ; /* the "public tagnames" table */
141 int nametable ; /* name table, file version 7 only */
142 } EMBRYO_STRUCT_PACKED AMX_HEADER;
143
144#if defined _MSC_VER || (defined (__SUNPRO_C) && __SUNPRO_C < 0x5100)
145# pragma pack()
146#endif
147
148#define AMX_MAGIC 0xf1e0
149
150 enum
151 {
152 AMX_ERR_NONE,
153 /* reserve the first 15 error codes for exit codes of the abstract machine */
154 AMX_ERR_EXIT, /* forced exit */
155 AMX_ERR_ASSERT, /* assertion failed */
156 AMX_ERR_STACKERR, /* stack/heap collision */
157 AMX_ERR_BOUNDS, /* index out of bounds */
158 AMX_ERR_MEMACCESS, /* invalid memory access */
159 AMX_ERR_INVINSTR, /* invalid instruction */
160 AMX_ERR_STACKLOW, /* stack underflow */
161 AMX_ERR_HEAPLOW, /* heap underflow */
162 AMX_ERR_CALLBACK, /* no callback, or invalid callback */
163 AMX_ERR_NATIVE, /* native function failed */
164 AMX_ERR_DIVIDE, /* divide by zero */
165 AMX_ERR_SLEEP, /* go into sleepmode - code can be restarted */
166
167 AMX_ERR_MEMORY = 16, /* out of memory */
168 AMX_ERR_FORMAT, /* invalid file format */
169 AMX_ERR_VERSION, /* file is for a newer version of the AMX */
170 AMX_ERR_NOTFOUND, /* function not found */
171 AMX_ERR_INDEX, /* invalid index parameter (bad entry point) */
172 AMX_ERR_DEBUG, /* debugger cannot run */
173 AMX_ERR_INIT, /* AMX not initialized (or doubly initialized) */
174 AMX_ERR_USERDATA, /* unable to set user data field (table full) */
175 AMX_ERR_INIT_JIT, /* cannot initialize the JIT */
176 AMX_ERR_PARAMS, /* parameter error */
177 AMX_ERR_DOMAIN, /* domain error, expression result does not fit in range */
178 };
179
180 enum
181 {
182 DBG_INIT, /* query/initialize */
183 DBG_FILE, /* file number in curfile, filename in name */
184 DBG_LINE, /* line number in curline, file number in curfile */
185 DBG_SYMBOL, /* address in dbgaddr, class/type in dbgparam */
186 DBG_CLRSYM, /* stack address below which locals should be removed. stack address in stk */
187 DBG_CALL, /* function call, address jumped to in dbgaddr */
188 DBG_RETURN, /* function returns */
189 DBG_TERMINATE, /* program ends, code address in dbgaddr, reason in dbgparam */
190 DBG_SRANGE, /* symbol size and dimensions (arrays); level in dbgaddr (!); length in dbgparam */
191 DBG_SYMTAG, /* tag of the most recent symbol (if non-zero), tag in dbgparam */
192 };
193
194#define AMX_FLAG_CHAR16 0x01 /* characters are 16-bit */
195#define AMX_FLAG_DEBUG 0x02 /* symbolic info. available */
196#define AMX_FLAG_COMPACT 0x04 /* compact encoding */
197#define AMX_FLAG_BIGENDIAN 0x08 /* big endian encoding */
198#define AMX_FLAG_NOCHECKS 0x10 /* no array bounds checking */
199#define AMX_FLAG_BROWSE 0x4000 /* browsing/relocating or executing */
200#define AMX_FLAG_RELOC 0x8000 /* jump/call addresses relocated */
201
202#define AMX_EXEC_MAIN -1 /* start at program entry point */
203#define AMX_EXEC_CONT -2 /* continue from last address */
204
205#define AMX_USERTAG(a,b,c,d) ((a) | ((b)<<8) | ((long)(c)<<16) | ((long)(d)<<24))
206
207#define AMX_EXPANDMARGIN 64
208
209/* for native functions that use floating point parameters, the following
210 * two macros are convenient for casting a "cell" into a "float" type _without_
211 * changing the bit pattern
212 */
213#define amx_ftoc(f) ( * ((cell*)&f) ) /* float to cell */
214#define amx_ctof(c) ( * ((float*)&c) ) /* cell to float */
215
216#define amx_StrParam(amx,param,result) { \
217 cell *amx_cstr_; int amx_length_; \
218 amx_GetAddr((amx), (param), &amx_cstr_); \
219 amx_StrLen(amx_cstr_, &amx_length_); \
220 if (amx_length_ > 0 && \
221 ((result) = (char *)alloca(amx_length_ + 1))) \
222 amx_GetString((result), amx_cstr_); \
223 else (result) = NULL; \
224}
225
226#endif /* __AMX_H */
diff --git a/src/bin/embryo/embryo_cc_osdefs.h b/src/bin/embryo/embryo_cc_osdefs.h
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/src/bin/embryo/embryo_cc_osdefs.h
diff --git a/src/bin/embryo/embryo_cc_prefix.c b/src/bin/embryo/embryo_cc_prefix.c
new file mode 100644
index 0000000000..9b57704617
--- /dev/null
+++ b/src/bin/embryo/embryo_cc_prefix.c
@@ -0,0 +1,61 @@
1#ifdef HAVE_CONFIG_H
2# include <config.h>
3#endif
4
5#include <Eina.h>
6
7#include "embryo_cc_prefix.h"
8
9/* local subsystem functions */
10
11/* local subsystem globals */
12
13static Eina_Prefix *pfx = NULL;
14
15/* externally accessible functions */
16int
17e_prefix_determine(char *argv0)
18{
19 if (pfx) return 1;
20 eina_init();
21 pfx = eina_prefix_new(argv0, e_prefix_determine,
22 "EMBRYO", "embryo", "include/default.inc",
23 PACKAGE_BIN_DIR,
24 PACKAGE_LIB_DIR,
25 PACKAGE_DATA_DIR,
26 PACKAGE_DATA_DIR);
27 if (!pfx) return 0;
28 return 1;
29}
30
31void
32e_prefix_shutdown(void)
33{
34 eina_prefix_free(pfx);
35 pfx = NULL;
36 eina_shutdown();
37}
38
39const char *
40e_prefix_get(void)
41{
42 return eina_prefix_get(pfx);
43}
44
45const char *
46e_prefix_bin_get(void)
47{
48 return eina_prefix_bin_get(pfx);
49}
50
51const char *
52e_prefix_data_get(void)
53{
54 return eina_prefix_data_get(pfx);
55}
56
57const char *
58e_prefix_lib_get(void)
59{
60 return eina_prefix_lib_get(pfx);
61}
diff --git a/src/bin/embryo/embryo_cc_prefix.h b/src/bin/embryo/embryo_cc_prefix.h
new file mode 100644
index 0000000000..d6dc7b2a31
--- /dev/null
+++ b/src/bin/embryo/embryo_cc_prefix.h
@@ -0,0 +1,6 @@
1int e_prefix_determine(char *argv0);
2void e_prefix_shutdown(void);
3const char *e_prefix_get(void);
4const char *e_prefix_bin_get(void);
5const char *e_prefix_data_get(void);
6const char *e_prefix_lib_get(void);
diff --git a/src/bin/embryo/embryo_cc_sc.h b/src/bin/embryo/embryo_cc_sc.h
new file mode 100644
index 0000000000..9eaf6b86e0
--- /dev/null
+++ b/src/bin/embryo/embryo_cc_sc.h
@@ -0,0 +1,673 @@
1/* Small compiler
2 *
3 * Drafted after the Small-C compiler Version 2.01, originally created
4 * by Ron Cain, july 1980, and enhanced by James E. Hendrix.
5 *
6 * This version comes close to a complete rewrite.
7 *
8 * Copyright R. Cain, 1980
9 * Copyright J.E. Hendrix, 1982, 1983
10 * Copyright T. Riemersma, 1997-2003
11 *
12 * Version: $Id$
13 *
14 * This software is provided "as-is", without any express or implied warranty.
15 * In no event will the authors be held liable for any damages arising from
16 * the use of this software.
17 *
18 * Permission is granted to anyone to use this software for any purpose,
19 * including commercial applications, and to alter it and redistribute it
20 * freely, subject to the following restrictions:
21 *
22 * 1. The origin of this software must not be misrepresented; you must not
23 * claim that you wrote the original software. If you use this software in
24 * a product, an acknowledgment in the product documentation would be
25 * appreciated but is not required.
26 * 2. Altered source versions must be plainly marked as such, and must not be
27 * misrepresented as being the original software.
28 * 3. This notice may not be removed or altered from any source distribution.
29 */
30
31#ifndef EMBRYO_CC_SC_H
32#define EMBRYO_CC_SC_H
33
34#include <limits.h>
35#include <stdarg.h>
36#include <stdio.h>
37#include <setjmp.h>
38
39#ifndef _MSC_VER
40# include <stdint.h>
41#else
42# include <stddef.h>
43# include <Evil.h>
44#endif
45
46#include "embryo_cc_amx.h"
47
48/* Note: the "cell" and "ucell" types are defined in AMX.H */
49
50#define PUBLIC_CHAR '@' /* character that defines a function "public" */
51#define CTRL_CHAR '\\' /* default control character */
52
53#define DIRSEP_CHAR '/' /* directory separator character */
54
55#define sDIMEN_MAX 2 /* maximum number of array dimensions */
56#define sDEF_LITMAX 500 /* initial size of the literal pool, in "cells" */
57#define sLINEMAX (640 * 1024) /* input line length (in characters) */
58#define sDEF_AMXSTACK 4096 /* default stack size for AMX files */
59#define sSTKMAX 80 /* stack for nested #includes and other uses */
60#define PREPROC_TERM '\x7f' /* termination character for preprocessor expressions (the "DEL" code) */
61#define sDEF_PREFIX "default.inc" /* default prefix filename */
62
63typedef intptr_t stkitem; /* type of items stored on the stack */
64
65typedef struct __s_arginfo
66{ /* function argument info */
67 char name[sNAMEMAX + 1];
68 char ident; /* iVARIABLE, iREFERENCE, iREFARRAY or iVARARGS */
69 char usage; /* uCONST */
70 int *tags; /* argument tag id. list */
71 int numtags; /* number of tags in the tag list */
72 int dim[sDIMEN_MAX];
73 int numdim; /* number of dimensions */
74 unsigned char hasdefault; /* bit0: is there a default value? bit6: "tagof"; bit7: "sizeof" */
75 union
76 {
77 cell val; /* default value */
78 struct
79 {
80 char *symname; /* name of another symbol */
81 short level; /* indirection level for that symbol */
82 } size; /* used for "sizeof" default value */
83 struct
84 {
85 cell *data; /* values of default array */
86 int size; /* complete length of default array */
87 int arraysize; /* size to reserve on the heap */
88 cell addr; /* address of the default array in the data segment */
89 } array;
90 } defvalue; /* default value, or pointer to default array */
91 int defvalue_tag; /* tag of the default value */
92} arginfo;
93
94/* Equate table, tagname table, library table */
95typedef struct __s_constvalue
96{
97 struct __s_constvalue *next;
98 char name[sNAMEMAX + 1];
99 cell value;
100 short index;
101} constvalue;
102
103/* Symbol table format
104 *
105 * The symbol name read from the input file is stored in "name", the
106 * value of "addr" is written to the output file. The address in "addr"
107 * depends on the class of the symbol:
108 * global offset into the data segment
109 * local offset relative to the stack frame
110 * label generated hexadecimal number
111 * function offset into code segment
112 */
113typedef struct __s_symbol
114{
115 struct __s_symbol *next;
116 struct __s_symbol *parent; /* hierarchical types (multi-dimensional arrays) */
117 char name[sNAMEMAX + 1];
118 unsigned int hash; /* value derived from name, for quicker searching */
119 cell addr; /* address or offset (or value for constant, index for native function) */
120 char vclass; /* sLOCAL if "addr" refers to a local symbol */
121 char ident; /* see below for possible values */
122 char usage; /* see below for possible values */
123 int compound; /* compound level (braces nesting level) */
124 int tag; /* tagname id */
125 union
126 {
127 int declared; /* label: how many local variables are declared */
128 int idxtag; /* array: tag of array indices */
129 constvalue *lib; /* native function: library it is part of *///??? use "stringlist"
130 } x; /* 'x' for 'extra' */
131 union
132 {
133 arginfo *arglist; /* types of all parameters for functions */
134 struct
135 {
136 cell length; /* arrays: length (size) */
137 short level; /* number of dimensions below this level */
138 } array;
139 } dim; /* for 'dimension', both functions and arrays */
140 int fnumber; /* static global variables: file number in which the declaration is visible */
141 struct __s_symbol **refer; /* referrer list, functions that "use" this symbol */
142 int numrefers; /* number of entries in the referrer list */
143} symbol;
144
145/* Possible entries for "ident". These are used in the "symbol", "value"
146 * and arginfo structures. Not every constant is valid for every use.
147 * In an argument list, the list is terminated with a "zero" ident; labels
148 * cannot be passed as function arguments, so the value 0 is overloaded.
149 */
150#define iLABEL 0
151#define iVARIABLE 1 /* cell that has an address and that can be fetched directly (lvalue) */
152#define iREFERENCE 2 /* iVARIABLE, but must be dereferenced */
153#define iARRAY 3
154#define iREFARRAY 4 /* an array passed by reference (i.e. a pointer) */
155#define iARRAYCELL 5 /* array element, cell that must be fetched indirectly */
156#define iARRAYCHAR 6 /* array element, character from cell from array */
157#define iEXPRESSION 7 /* expression result, has no address (rvalue) */
158#define iCONSTEXPR 8 /* constant expression (or constant symbol) */
159#define iFUNCTN 9
160#define iREFFUNC 10 /* function passed as a parameter */
161#define iVARARGS 11 /* function specified ... as argument(s) */
162
163/* Possible entries for "usage"
164 *
165 * This byte is used as a serie of bits, the syntax is different for
166 * functions and other symbols:
167 *
168 * VARIABLE
169 * bits: 0 (uDEFINE) the variable is defined in the source file
170 * 1 (uREAD) the variable is "read" (accessed) in the source file
171 * 2 (uWRITTEN) the variable is altered (assigned a value)
172 * 3 (uCONST) the variable is constant (may not be assigned to)
173 * 4 (uPUBLIC) the variable is public
174 * 6 (uSTOCK) the variable is discardable (without warning)
175 *
176 * FUNCTION
177 * bits: 0 (uDEFINE) the function is defined ("implemented") in the source file
178 * 1 (uREAD) the function is invoked in the source file
179 * 2 (uRETVALUE) the function returns a value (or should return a value)
180 * 3 (uPROTOTYPED) the function was prototyped
181 * 4 (uPUBLIC) the function is public
182 * 5 (uNATIVE) the function is native
183 * 6 (uSTOCK) the function is discardable (without warning)
184 * 7 (uMISSING) the function is not implemented in this source file
185 *
186 * CONSTANT
187 * bits: 0 (uDEFINE) the symbol is defined in the source file
188 * 1 (uREAD) the constant is "read" (accessed) in the source file
189 * 3 (uPREDEF) the constant is pre-defined and should be kept between passes
190 */
191#define uDEFINE 0x01
192#define uREAD 0x02
193#define uWRITTEN 0x04
194#define uRETVALUE 0x04 /* function returns (or should return) a value */
195#define uCONST 0x08
196#define uPROTOTYPED 0x08
197#define uPREDEF 0x08 /* constant is pre-defined */
198#define uPUBLIC 0x10
199#define uNATIVE 0x20
200#define uSTOCK 0x40
201#define uMISSING 0x80
202/* uRETNONE is not stored in the "usage" field of a symbol. It is
203 * used during parsing a function, to detect a mix of "return;" and
204 * "return value;" in a few special cases.
205 */
206#define uRETNONE 0x10
207
208#define uTAGOF 0x40 /* set in the "hasdefault" field of the arginfo struct */
209#define uSIZEOF 0x80 /* set in the "hasdefault" field of the arginfo struct */
210
211#define uMAINFUNC "main"
212
213#define sGLOBAL 0 /* global/local variable/constant class */
214#define sLOCAL 1
215#define sSTATIC 2 /* global life, local scope */
216
217typedef struct
218{
219 symbol *sym; /* symbol in symbol table, NULL for (constant) expression */
220 cell constval; /* value of the constant expression (if ident==iCONSTEXPR)
221 * also used for the size of a literal array */
222 int tag; /* tagname id (of the expression) */
223 char ident; /* iCONSTEXPR, iVARIABLE, iARRAY, iARRAYCELL,
224 * iEXPRESSION or iREFERENCE */
225 char boolresult; /* boolean result for relational operators */
226 cell *arrayidx; /* last used array indices, for checking self assignment */
227} value;
228
229/* "while" statement queue (also used for "for" and "do - while" loops) */
230enum
231{
232 wqBRK, /* used to restore stack for "break" */
233 wqCONT, /* used to restore stack for "continue" */
234 wqLOOP, /* loop start label number */
235 wqEXIT, /* loop exit label number (jump if false) */
236 /* --- */
237 wqSIZE /* "while queue" size */
238};
239
240#define wqTABSZ (24*wqSIZE) /* 24 nested loop statements */
241
242enum
243{
244 statIDLE, /* not compiling yet */
245 statFIRST, /* first pass */
246 statWRITE, /* writing output */
247 statSKIP, /* skipping output */
248};
249
250typedef struct __s_stringlist
251{
252 struct __s_stringlist *next;
253 char *line;
254} stringlist;
255
256typedef struct __s_stringpair
257{
258 struct __s_stringpair *next;
259 char *first;
260 char *second;
261 int matchlength;
262} stringpair;
263
264/* macros for code generation */
265#define opcodes(n) ((n)*sizeof(cell)) /* opcode size */
266#define opargs(n) ((n)*sizeof(cell)) /* size of typical argument */
267
268/* Tokens recognized by lex()
269 * Some of these constants are assigned as well to the variable "lastst"
270 */
271#define tFIRST 256 /* value of first multi-character operator */
272#define tMIDDLE 279 /* value of last multi-character operator */
273#define tLAST 320 /* value of last multi-character match-able token */
274/* multi-character operators */
275#define taMULT 256 /* *= */
276#define taDIV 257 /* /= */
277#define taMOD 258 /* %= */
278#define taADD 259 /* += */
279#define taSUB 260 /* -= */
280#define taSHL 261 /* <<= */
281#define taSHRU 262 /* >>>= */
282#define taSHR 263 /* >>= */
283#define taAND 264 /* &= */
284#define taXOR 265 /* ^= */
285#define taOR 266 /* |= */
286#define tlOR 267 /* || */
287#define tlAND 268 /* && */
288#define tlEQ 269 /* == */
289#define tlNE 270 /* != */
290#define tlLE 271 /* <= */
291#define tlGE 272 /* >= */
292#define tSHL 273 /* << */
293#define tSHRU 274 /* >>> */
294#define tSHR 275 /* >> */
295#define tINC 276 /* ++ */
296#define tDEC 277 /* -- */
297#define tELLIPS 278 /* ... */
298#define tDBLDOT 279 /* .. */
299/* reserved words (statements) */
300#define tASSERT 280
301#define tBREAK 281
302#define tCASE 282
303#define tCHAR 283
304#define tCONST 284
305#define tCONTINUE 285
306#define tDEFAULT 286
307#define tDEFINED 287
308#define tDO 288
309#define tELSE 289
310#define tENUM 290
311#define tEXIT 291
312#define tFOR 292
313#define tFORWARD 293
314#define tGOTO 294
315#define tIF 295
316#define tNATIVE 296
317#define tNEW 297
318#define tOPERATOR 298
319#define tPUBLIC 299
320#define tRETURN 300
321#define tSIZEOF 301
322#define tSLEEP 302
323#define tSTATIC 303
324#define tSTOCK 304
325#define tSWITCH 305
326#define tTAGOF 306
327#define tWHILE 307
328/* compiler directives */
329#define tpASSERT 308 /* #assert */
330#define tpDEFINE 309
331#define tpELSE 310 /* #else */
332#define tpEMIT 311
333#define tpENDIF 312
334#define tpENDINPUT 313
335#define tpENDSCRPT 314
336#define tpFILE 315
337#define tpIF 316 /* #if */
338#define tINCLUDE 317
339#define tpLINE 318
340#define tpPRAGMA 319
341#define tpUNDEF 320
342/* semicolon is a special case, because it can be optional */
343#define tTERM 321 /* semicolon or newline */
344#define tENDEXPR 322 /* forced end of expression */
345/* other recognized tokens */
346#define tNUMBER 323 /* integer number */
347#define tRATIONAL 324 /* rational number */
348#define tSYMBOL 325
349#define tLABEL 326
350#define tSTRING 327
351#define tEXPR 328 /* for assigment to "lastst" only */
352
353/* (reversed) evaluation of staging buffer */
354#define sSTARTREORDER 1
355#define sENDREORDER 2
356#define sEXPRSTART 0xc0 /* top 2 bits set, rest is free */
357#define sMAXARGS 64 /* relates to the bit pattern of sEXPRSTART */
358
359/* codes for ffabort() */
360#define xEXIT 1 /* exit code in PRI */
361#define xASSERTION 2 /* abort caused by failing assertion */
362#define xSTACKERROR 3 /* stack/heap overflow */
363#define xBOUNDSERROR 4 /* array index out of bounds */
364#define xMEMACCESS 5 /* data access error */
365#define xINVINSTR 6 /* invalid instruction */
366#define xSTACKUNDERFLOW 7 /* stack underflow */
367#define xHEAPUNDERFLOW 8 /* heap underflow */
368#define xCALLBACKERR 9 /* no, or invalid, callback */
369#define xSLEEP 12 /* sleep, exit code in PRI, tag in ALT */
370
371/* Miscellaneous */
372#if !defined TRUE
373#define FALSE 0
374#define TRUE 1
375#endif
376#define sIN_CSEG 1 /* if parsing CODE */
377#define sIN_DSEG 2 /* if parsing DATA */
378#define sCHKBOUNDS 1 /* bit position in "debug" variable: check bounds */
379#define sSYMBOLIC 2 /* bit position in "debug" variable: symbolic info */
380#define sNOOPTIMIZE 4 /* bit position in "debug" variable: no optimization */
381#define sRESET 0 /* reset error flag */
382#define sFORCESET 1 /* force error flag on */
383#define sEXPRMARK 2 /* mark start of expression */
384#define sEXPRRELEASE 3 /* mark end of expression */
385
386#if INT_MAX<0x8000u
387#define PUBLICTAG 0x8000u
388#define FIXEDTAG 0x4000u
389#else
390#define PUBLICTAG 0x80000000Lu
391#define FIXEDTAG 0x40000000Lu
392#endif
393#define TAGMASK (~PUBLICTAG)
394
395
396/*
397 * Functions you call from the "driver" program
398 */
399 int sc_compile(int argc, char **argv);
400 int sc_addconstant(char *name, cell value, int tag);
401 int sc_addtag(char *name);
402
403/*
404 * Functions called from the compiler (to be implemented by you)
405 */
406
407/* general console output */
408 int sc_printf(const char *message, ...);
409
410/* error report function */
411 int sc_error(int number, char *message, char *filename,
412 int firstline, int lastline, va_list argptr);
413
414/* input from source file */
415 void *sc_opensrc(char *filename); /* reading only */
416 void sc_closesrc(void *handle); /* never delete */
417 void sc_resetsrc(void *handle, void *position); /* reset to a position marked earlier */
418 char *sc_readsrc(void *handle, char *target, int maxchars);
419 void *sc_getpossrc(void *handle); /* mark the current position */
420 int sc_eofsrc(void *handle);
421
422/* output to intermediate (.ASM) file */
423 void *sc_openasm(int fd); /* read/write */
424 void sc_closeasm(void *handle);
425 void sc_resetasm(void *handle);
426 int sc_writeasm(void *handle, char *str);
427 char *sc_readasm(void *handle, char *target, int maxchars);
428
429/* output to binary (.AMX) file */
430 void *sc_openbin(char *filename);
431 void sc_closebin(void *handle, int deletefile);
432 void sc_resetbin(void *handle);
433 int sc_writebin(void *handle, void *buffer, int size);
434 long sc_lengthbin(void *handle); /* return the length of the file */
435
436/* function prototypes in SC1.C */
437symbol *fetchfunc(char *name, int tag);
438char *operator_symname(char *symname, char *opername, int tag1,
439 int tag2, int numtags, int resulttag);
440char *funcdisplayname(char *dest, char *funcname);
441int constexpr(cell * val, int *tag);
442constvalue *append_constval(constvalue * table, char *name, cell val,
443 short index);
444constvalue *find_constval(constvalue * table, char *name, short index);
445void delete_consttable(constvalue * table);
446void add_constant(char *name, cell val, int vclass, int tag);
447void exporttag(int tag);
448
449/* function prototypes in SC2.C */
450void pushstk(stkitem val);
451stkitem popstk(void);
452int plungequalifiedfile(char *name); /* explicit path included */
453int plungefile(char *name, int try_currentpath, int try_includepaths); /* search through "include" paths */
454void preprocess(void);
455void lexinit(void);
456int lex(cell * lexvalue, char **lexsym);
457void lexpush(void);
458void lexclr(int clreol);
459int matchtoken(int token);
460int tokeninfo(cell * val, char **str);
461int needtoken(int token);
462void stowlit(cell value);
463int alphanum(char c);
464void delete_symbol(symbol * root, symbol * sym);
465void delete_symbols(symbol * root, int level, int del_labels,
466 int delete_functions);
467int refer_symbol(symbol * entry, symbol * bywhom);
468void markusage(symbol * sym, int usage);
469unsigned int namehash(char *name);
470symbol *findglb(char *name);
471symbol *findloc(char *name);
472symbol *findconst(char *name);
473symbol *finddepend(symbol * parent);
474symbol *addsym(char *name, cell addr, int ident, int vclass,
475 int tag, int usage);
476symbol *addvariable(char *name, cell addr, int ident, int vclass,
477 int tag, int dim[], int numdim, int idxtag[]);
478int getlabel(void);
479char *itoh(ucell val);
480
481/* function prototypes in SC3.C */
482int check_userop(void (*oper) (void), int tag1, int tag2,
483 int numparam, value * lval, int *resulttag);
484int matchtag(int formaltag, int actualtag, int allowcoerce);
485int expression(int *constant, cell * val, int *tag,
486 int chkfuncresult);
487int hier14(value * lval1); /* the highest expression level */
488
489/* function prototypes in SC4.C */
490void writeleader(void);
491void writetrailer(void);
492void begcseg(void);
493void begdseg(void);
494void setactivefile(int fnumber);
495cell nameincells(char *name);
496void setfile(char *name, int fileno);
497void setline(int line, int fileno);
498void setlabel(int index);
499void endexpr(int fullexpr);
500void startfunc(char *fname);
501void endfunc(void);
502void alignframe(int numbytes);
503void defsymbol(char *name, int ident, int vclass, cell offset,
504 int tag);
505void symbolrange(int level, cell size);
506void rvalue(value * lval);
507void address(symbol * ptr);
508void store(value * lval);
509void memcopy(cell size);
510void copyarray(symbol * sym, cell size);
511void fillarray(symbol * sym, cell size, cell value);
512void const1(cell val);
513void const2(cell val);
514void moveto1(void);
515void push1(void);
516void push2(void);
517void pushval(cell val);
518void pop1(void);
519void pop2(void);
520void swap1(void);
521void ffswitch(int label);
522void ffcase(cell value, char *labelname, int newtable);
523void ffcall(symbol * sym, int numargs);
524void ffret(void);
525void ffabort(int reason);
526void ffbounds(cell size);
527void jumplabel(int number);
528void defstorage(void);
529void modstk(int delta);
530void setstk(cell value);
531void modheap(int delta);
532void setheap_pri(void);
533void setheap(cell value);
534void cell2addr(void);
535void cell2addr_alt(void);
536void addr2cell(void);
537void char2addr(void);
538void charalign(void);
539void addconst(cell value);
540
541/* Code generation functions for arithmetic operators.
542 *
543 * Syntax: o[u|s|b]_name
544 * | | | +--- name of operator
545 * | | +----- underscore
546 * | +--------- "u"nsigned operator, "s"igned operator or "b"oth
547 * +------------- "o"perator
548 */
549void os_mult(void); /* multiplication (signed) */
550void os_div(void); /* division (signed) */
551void os_mod(void); /* modulus (signed) */
552void ob_add(void); /* addition */
553void ob_sub(void); /* subtraction */
554void ob_sal(void); /* shift left (arithmetic) */
555void os_sar(void); /* shift right (arithmetic, signed) */
556void ou_sar(void); /* shift right (logical, unsigned) */
557void ob_or(void); /* bitwise or */
558void ob_xor(void); /* bitwise xor */
559void ob_and(void); /* bitwise and */
560void ob_eq(void); /* equality */
561void ob_ne(void); /* inequality */
562void relop_prefix(void);
563void relop_suffix(void);
564void os_le(void); /* less or equal (signed) */
565void os_ge(void); /* greater or equal (signed) */
566void os_lt(void); /* less (signed) */
567void os_gt(void); /* greater (signed) */
568
569void lneg(void);
570void neg(void);
571void invert(void);
572void nooperation(void);
573void inc(value * lval);
574void dec(value * lval);
575void jmp_ne0(int number);
576void jmp_eq0(int number);
577void outval(cell val, int newline);
578
579/* function prototypes in SC5.C */
580int error(int number, ...);
581void errorset(int code);
582
583/* function prototypes in SC6.C */
584void assemble(FILE * fout, FILE * fin);
585
586/* function prototypes in SC7.C */
587void stgbuffer_cleanup(void);
588void stgmark(char mark);
589void stgwrite(char *st);
590void stgout(int index);
591void stgdel(int index, cell code_index);
592int stgget(int *index, cell * code_index);
593void stgset(int onoff);
594int phopt_init(void);
595int phopt_cleanup(void);
596
597/* function prototypes in SCLIST.C */
598stringpair *insert_alias(char *name, char *alias);
599stringpair *find_alias(char *name);
600int lookup_alias(char *target, char *name);
601void delete_aliastable(void);
602stringlist *insert_path(char *path);
603char *get_path(int index);
604void delete_pathtable(void);
605stringpair *insert_subst(char *pattern, char *substitution,
606 int prefixlen);
607int get_subst(int index, char **pattern, char **substitution);
608stringpair *find_subst(char *name, int length);
609int delete_subst(char *name, int length);
610void delete_substtable(void);
611
612/* external variables (defined in scvars.c) */
613extern symbol loctab; /* local symbol table */
614extern symbol glbtab; /* global symbol table */
615extern cell *litq; /* the literal queue */
616extern char pline[]; /* the line read from the input file */
617extern char *lptr; /* points to the current position in "pline" */
618extern constvalue tagname_tab; /* tagname table */
619extern constvalue libname_tab; /* library table (#pragma library "..." syntax) *///??? use "stringlist" type
620extern constvalue *curlibrary; /* current library */
621extern symbol *curfunc; /* pointer to current function */
622extern char *inpfname; /* name of the file currently read from */
623extern char outfname[]; /* output file name */
624extern char sc_ctrlchar; /* the control character (or escape character) */
625extern int litidx; /* index to literal table */
626extern int litmax; /* current size of the literal table */
627extern int stgidx; /* index to the staging buffer */
628extern int labnum; /* number of (internal) labels */
629extern int staging; /* true if staging output */
630extern cell declared; /* number of local cells declared */
631extern cell glb_declared; /* number of global cells declared */
632extern cell code_idx; /* number of bytes with generated code */
633extern int ntv_funcid; /* incremental number of native function */
634extern int errnum; /* number of errors */
635extern int warnnum; /* number of warnings */
636extern int sc_debug; /* debug/optimization options (bit field) */
637extern int charbits; /* number of bits for a character */
638extern int sc_packstr; /* strings are packed by default? */
639extern int sc_asmfile; /* create .ASM file? */
640extern int sc_listing; /* create .LST file? */
641extern int sc_compress; /* compress bytecode? */
642extern int sc_needsemicolon; /* semicolon required to terminate expressions? */
643extern int sc_dataalign; /* data alignment value */
644extern int sc_alignnext; /* must frame of the next function be aligned? */
645extern int curseg; /* 1 if currently parsing CODE, 2 if parsing DATA */
646extern cell sc_stksize; /* stack size */
647extern int freading; /* is there an input file ready for reading? */
648extern int fline; /* the line number in the current file */
649extern int fnumber; /* number of files in the file table (debugging) */
650extern int fcurrent; /* current file being processed (debugging) */
651extern int intest; /* true if inside a test */
652extern int sideeffect; /* true if an expression causes a side-effect */
653extern int stmtindent; /* current indent of the statement */
654extern int indent_nowarn; /* skip warning "217 loose indentation" */
655extern int sc_tabsize; /* number of spaces that a TAB represents */
656extern int sc_allowtags; /* allow/detect tagnames in lex() */
657extern int sc_status; /* read/write status */
658extern int sc_rationaltag; /* tag for rational numbers */
659extern int rational_digits; /* number of fractional digits */
660
661extern FILE *inpf; /* file read from (source or include) */
662extern FILE *inpf_org; /* main source file */
663extern FILE *outf; /* file written to */
664
665extern jmp_buf errbuf; /* target of longjmp() on a fatal error */
666
667#define sc_isspace(x) isspace ((int)((unsigned char)x))
668#define sc_isalpha(x) isalpha ((int)((unsigned char)x))
669#define sc_isdigit(x) isdigit ((int)((unsigned char)x))
670#define sc_isupper(x) isupper ((int)((unsigned char)x))
671#define sc_isxdigit(x) isxdigit((int)((unsigned char)x))
672
673#endif
diff --git a/src/bin/embryo/embryo_cc_sc1.c b/src/bin/embryo/embryo_cc_sc1.c
new file mode 100644
index 0000000000..53baf36539
--- /dev/null
+++ b/src/bin/embryo/embryo_cc_sc1.c
@@ -0,0 +1,4083 @@
1/* Small compiler
2 * Function and variable definition and declaration, statement parser.
3 *
4 * Copyright (c) ITB CompuPhase, 1997-2003
5 *
6 * This software is provided "as-is", without any express or implied
7 * warranty. In no event will the authors be held liable for any
8 * damages arising from the use of this software. Permission is granted
9 * to anyone to use this software for any purpose, including commercial
10 * applications, and to alter it and redistribute it freely, subject to
11 * the following restrictions:
12 *
13 * 1. The origin of this software must not be misrepresented;
14 * you must not claim that you wrote the original software.
15 * If you use this software in a product, an acknowledgment in the
16 * product documentation would be appreciated but is not required.
17 * 2. Altered source versions must be plainly marked as such, and
18 * must not be misrepresented as being the original software.
19 * 3. This notice may not be removed or altered from any source
20 * distribution.
21 * Version: $Id$
22 */
23
24
25#ifdef HAVE_CONFIG_H
26# include <config.h>
27#endif
28
29#include <assert.h>
30#include <ctype.h>
31#include <limits.h>
32#include <stdarg.h>
33#include <stdio.h>
34#include <stdlib.h>
35#include <string.h>
36
37#ifdef HAVE_UNISTD_H
38# include <unistd.h>
39#endif
40
41#ifdef HAVE_EVIL
42# include <Evil.h>
43#endif
44
45#include <Eina.h>
46
47#include "embryo_cc_sc.h"
48#include "embryo_cc_prefix.h"
49
50#define VERSION_STR "2.4"
51#define VERSION_INT 240
52
53static void resetglobals(void);
54static void initglobals(void);
55static void setopt(int argc, char **argv,
56 char *iname, char *oname,
57 char *pname, char *rname);
58static void setconfig(char *root);
59static void about(void);
60static void setconstants(void);
61static void parse(void);
62static void dumplits(void);
63static void dumpzero(int count);
64static void declfuncvar(int tok, char *symname,
65 int tag, int fpublic,
66 int fstatic, int fstock, int fconst);
67static void declglb(char *firstname, int firsttag,
68 int fpublic, int fstatic, int stock, int fconst);
69static int declloc(int fstatic);
70static void decl_const(int table);
71static void decl_enum(int table);
72static cell needsub(int *tag);
73static void initials(int ident, int tag,
74 cell * size, int dim[], int numdim);
75static cell initvector(int ident, int tag, cell size, int fillzero);
76static cell init(int ident, int *tag);
77static void funcstub(int native);
78static int newfunc(char *firstname, int firsttag,
79 int fpublic, int fstatic, int stock);
80static int declargs(symbol * sym);
81static void doarg(char *name, int ident, int offset,
82 int tags[], int numtags,
83 int fpublic, int fconst, arginfo * arg);
84static void reduce_referrers(symbol * root);
85static int testsymbols(symbol * root, int level,
86 int testlabs, int testconst);
87static void destructsymbols(symbol * root, int level);
88static constvalue *find_constval_byval(constvalue * table, cell val);
89static void statement(int *lastindent, int allow_decl);
90static void compound(void);
91static void doexpr(int comma, int chkeffect,
92 int allowarray, int mark_endexpr,
93 int *tag, int chkfuncresult);
94static void doassert(void);
95static void doexit(void);
96static void test(int label, int parens, int invert);
97static void doif(void);
98static void dowhile(void);
99static void dodo(void);
100static void dofor(void);
101static void doswitch(void);
102static void dogoto(void);
103static void dolabel(void);
104static symbol *fetchlab(char *name);
105static void doreturn(void);
106static void dobreak(void);
107static void docont(void);
108static void dosleep(void);
109static void addwhile(int *ptr);
110static void delwhile(void);
111static int *readwhile(void);
112
113static int lastst = 0; /* last executed statement type */
114static int nestlevel = 0; /* number of active (open) compound statements */
115static int rettype = 0; /* the type that a "return" expression should have */
116static int skipinput = 0; /* number of lines to skip from the first input file */
117static int wq[wqTABSZ]; /* "while queue", internal stack for nested loops */
118static int *wqptr; /* pointer to next entry */
119static char binfname[PATH_MAX]; /* binary file name */
120
121int
122main(int argc, char *argv[], char *env[] EINA_UNUSED)
123{
124 e_prefix_determine(argv[0]);
125 return sc_compile(argc, argv);
126}
127
128int
129sc_error(int number, char *message, char *filename, int firstline,
130 int lastline, va_list argptr)
131{
132 static char *prefix[3] = { "error", "fatal error", "warning" };
133
134 if (number != 0)
135 {
136 char *pre;
137
138 pre = prefix[number / 100];
139 if (firstline >= 0)
140 fprintf(stderr, "%s(%d -- %d) : %s %03d: ", filename, firstline,
141 lastline, pre, number);
142 else
143 fprintf(stderr, "%s(%d) : %s %03d: ", filename, lastline, pre,
144 number);
145 } /* if */
146 vfprintf(stderr, message, argptr);
147 fflush(stderr);
148 return 0;
149}
150
151void *
152sc_opensrc(char *filename)
153{
154 return fopen(filename, "rb");
155}
156
157void
158sc_closesrc(void *handle)
159{
160 assert(handle != NULL);
161 fclose((FILE *) handle);
162}
163
164void
165sc_resetsrc(void *handle, void *position)
166{
167 assert(handle != NULL);
168 fsetpos((FILE *) handle, (fpos_t *) position);
169}
170
171char *
172sc_readsrc(void *handle, char *target, int maxchars)
173{
174 return fgets(target, maxchars, (FILE *) handle);
175}
176
177void *
178sc_getpossrc(void *handle)
179{
180 static fpos_t lastpos; /* may need to have a LIFO stack of
181 * such positions */
182
183 fgetpos((FILE *) handle, &lastpos);
184 return &lastpos;
185}
186
187int
188sc_eofsrc(void *handle)
189{
190 return feof((FILE *) handle);
191}
192
193void *
194sc_openasm(int fd)
195{
196 return fdopen(fd, "w+");
197}
198
199void
200sc_closeasm(void *handle)
201{
202 if (handle)
203 fclose((FILE *) handle);
204}
205
206void
207sc_resetasm(void *handle)
208{
209 fflush((FILE *) handle);
210 fseek((FILE *) handle, 0, SEEK_SET);
211}
212
213int
214sc_writeasm(void *handle, char *st)
215{
216 return fputs(st, (FILE *) handle) >= 0;
217}
218
219char *
220sc_readasm(void *handle, char *target, int maxchars)
221{
222 return fgets(target, maxchars, (FILE *) handle);
223}
224
225void *
226sc_openbin(char *filename)
227{
228 return fopen(filename, "wb");
229}
230
231void
232sc_closebin(void *handle, int deletefile)
233{
234 fclose((FILE *) handle);
235 if (deletefile)
236 unlink(binfname);
237}
238
239void
240sc_resetbin(void *handle)
241{
242 fflush((FILE *) handle);
243 fseek((FILE *) handle, 0, SEEK_SET);
244}
245
246int
247sc_writebin(void *handle, void *buffer, int size)
248{
249 return (int)fwrite(buffer, 1, size, (FILE *) handle) == size;
250}
251
252long
253sc_lengthbin(void *handle)
254{
255 return ftell((FILE *) handle);
256}
257
258/* "main" of the compiler
259 */
260int
261sc_compile(int argc, char *argv[])
262{
263 int entry, i, jmpcode, fd_out;
264 int retcode;
265 char incfname[PATH_MAX];
266 char reportname[PATH_MAX];
267 FILE *binf;
268 void *inpfmark;
269 char lcl_ctrlchar;
270 int lcl_packstr, lcl_needsemicolon, lcl_tabsize;
271 char *tmpdir;
272
273 /* set global variables to their initial value */
274 binf = NULL;
275 initglobals();
276 errorset(sRESET);
277 errorset(sEXPRRELEASE);
278 lexinit();
279
280 /* make sure that we clean up on a fatal error; do this before the
281 * first call to error(). */
282 if ((jmpcode = setjmp(errbuf)) != 0)
283 goto cleanup;
284
285 /* allocate memory for fixed tables */
286 inpfname = (char *)malloc(PATH_MAX);
287 litq = (cell *) malloc(litmax * sizeof(cell));
288 if (!litq)
289 error(103); /* insufficient memory */
290 if (!phopt_init())
291 error(103); /* insufficient memory */
292
293 setopt(argc, argv, inpfname, binfname, incfname, reportname);
294
295 /* open the output file */
296
297#ifndef HAVE_EVIL
298 tmpdir = getenv("TMPDIR");
299 if (!tmpdir) tmpdir = "/tmp";
300#else
301 tmpdir = (char *)evil_tmpdir_get();
302#endif /* ! HAVE_EVIL */
303
304 snprintf(outfname, PATH_MAX, "%s/embryo_cc.asm-tmp-XXXXXX", tmpdir);
305 fd_out = mkstemp(outfname);
306 if (fd_out < 0)
307 error(101, outfname);
308
309 setconfig(argv[0]); /* the path to the include files */
310 lcl_ctrlchar = sc_ctrlchar;
311 lcl_packstr = sc_packstr;
312 lcl_needsemicolon = sc_needsemicolon;
313 lcl_tabsize = sc_tabsize;
314 inpf = inpf_org = (FILE *) sc_opensrc(inpfname);
315 if (!inpf)
316 error(100, inpfname);
317 freading = TRUE;
318 outf = (FILE *) sc_openasm(fd_out); /* first write to assembler
319 * file (may be temporary) */
320 if (!outf)
321 error(101, outfname);
322 /* immediately open the binary file, for other programs to check */
323 binf = (FILE *) sc_openbin(binfname);
324 if (!binf)
325 error(101, binfname);
326 setconstants(); /* set predefined constants and tagnames */
327 for (i = 0; i < skipinput; i++) /* skip lines in the input file */
328 if (sc_readsrc(inpf, pline, sLINEMAX))
329 fline++; /* keep line number up to date */
330 skipinput = fline;
331 sc_status = statFIRST;
332 /* do the first pass through the file */
333 inpfmark = sc_getpossrc(inpf);
334 if (incfname[0] != '\0')
335 {
336 if (strcmp(incfname, sDEF_PREFIX) == 0)
337 {
338 plungefile(incfname, FALSE, TRUE); /* parse "default.inc" */
339 }
340 else
341 {
342 if (!plungequalifiedfile(incfname)) /* parse "prefix" include
343 * file */
344 error(100, incfname); /* cannot read from ... (fatal error) */
345 } /* if */
346 } /* if */
347 preprocess(); /* fetch first line */
348 parse(); /* process all input */
349
350 /* second pass */
351 sc_status = statWRITE; /* set, to enable warnings */
352
353 /* ??? for re-parsing the listing file instead of the original source
354 * file (and doing preprocessing twice):
355 * - close input file, close listing file
356 * - re-open listing file for reading (inpf)
357 * - open assembler file (outf)
358 */
359
360 /* reset "defined" flag of all functions and global variables */
361 reduce_referrers(&glbtab);
362 delete_symbols(&glbtab, 0, TRUE, FALSE);
363#if !defined NO_DEFINE
364 delete_substtable();
365#endif
366 resetglobals();
367 sc_ctrlchar = lcl_ctrlchar;
368 sc_packstr = lcl_packstr;
369 sc_needsemicolon = lcl_needsemicolon;
370 sc_tabsize = lcl_tabsize;
371 errorset(sRESET);
372 /* reset the source file */
373 inpf = inpf_org;
374 freading = TRUE;
375 sc_resetsrc(inpf, inpfmark); /* reset file position */
376 fline = skipinput; /* reset line number */
377 lexinit(); /* clear internal flags of lex() */
378 sc_status = statWRITE; /* allow to write --this variable was reset
379 * by resetglobals() */
380 writeleader();
381 setfile(inpfname, fnumber);
382 if (incfname[0] != '\0')
383 {
384 if (strcmp(incfname, sDEF_PREFIX) == 0)
385 plungefile(incfname, FALSE, TRUE); /* parse "default.inc" (again) */
386 else
387 plungequalifiedfile(incfname); /* parse implicit include
388 * file (again) */
389 } /* if */
390 preprocess(); /* fetch first line */
391 parse(); /* process all input */
392 /* inpf is already closed when readline() attempts to pop of a file */
393 writetrailer(); /* write remaining stuff */
394
395 entry = testsymbols(&glbtab, 0, TRUE, FALSE); /* test for unused
396 * or undefined functions and variables */
397 if (!entry)
398 error(13); /* no entry point (no public functions) */
399
400 cleanup:
401 if (inpf) /* main source file is not closed, do it now */
402 sc_closesrc(inpf);
403 /* write the binary file (the file is already open) */
404 if (errnum == 0 && jmpcode == 0)
405 {
406 assert(binf != NULL);
407 sc_resetasm(outf); /* flush and loop back, for reading */
408 assemble(binf, outf); /* assembler file is now input */
409 } /* if */
410 if (outf)
411 sc_closeasm(outf);
412 unlink (outfname);
413 if (binf)
414 sc_closebin(binf, errnum != 0);
415
416 if (inpfname)
417 free(inpfname);
418 if (litq)
419 free(litq);
420 phopt_cleanup();
421 stgbuffer_cleanup();
422 assert(jmpcode != 0 || loctab.next == NULL); /* on normal flow,
423 * local symbols
424 * should already have been deleted */
425 delete_symbols(&loctab, 0, TRUE, TRUE); /* delete local variables
426 * if not yet done (i.e.
427 * on a fatal error) */
428 delete_symbols(&glbtab, 0, TRUE, TRUE);
429 delete_consttable(&tagname_tab);
430 delete_consttable(&libname_tab);
431 delete_aliastable();
432 delete_pathtable();
433#if !defined NO_DEFINE
434 delete_substtable();
435#endif
436 if (errnum != 0)
437 {
438 printf("\n%d Error%s.\n", errnum, (errnum > 1) ? "s" : "");
439 retcode = 2;
440 }
441 else if (warnnum != 0)
442 {
443 printf("\n%d Warning%s.\n", warnnum, (warnnum > 1) ? "s" : "");
444 retcode = 1;
445 }
446 else
447 {
448 retcode = jmpcode;
449 } /* if */
450 return retcode;
451}
452
453int
454sc_addconstant(char *name, cell value, int tag)
455{
456 errorset(sFORCESET); /* make sure error engine is silenced */
457 sc_status = statIDLE;
458 add_constant(name, value, sGLOBAL, tag);
459 return 1;
460}
461
462int
463sc_addtag(char *name)
464{
465 cell val;
466 constvalue *ptr;
467 int last, tag;
468
469 if (!name)
470 {
471 /* no tagname was given, check for one */
472 if (lex(&val, &name) != tLABEL)
473 {
474 lexpush();
475 return 0; /* untagged */
476 } /* if */
477 } /* if */
478
479 last = 0;
480 ptr = tagname_tab.next;
481 while (ptr)
482 {
483 tag = (int)(ptr->value & TAGMASK);
484 if (strcmp(name, ptr->name) == 0)
485 return tag; /* tagname is known, return its sequence number */
486 tag &= (int)~FIXEDTAG;
487 if (tag > last)
488 last = tag;
489 ptr = ptr->next;
490 } /* while */
491
492 /* tagname currently unknown, add it */
493 tag = last + 1; /* guaranteed not to exist already */
494 if (sc_isupper(*name))
495 tag |= (int)FIXEDTAG;
496 append_constval(&tagname_tab, name, (cell) tag, 0);
497 return tag;
498}
499
500static void
501resetglobals(void)
502{
503 /* reset the subset of global variables that is modified by the
504 * first pass */
505 curfunc = NULL; /* pointer to current function */
506 lastst = 0; /* last executed statement type */
507 nestlevel = 0; /* number of active (open) compound statements */
508 rettype = 0; /* the type that a "return" expression should have */
509 litidx = 0; /* index to literal table */
510 stgidx = 0; /* index to the staging buffer */
511 labnum = 0; /* number of (internal) labels */
512 staging = 0; /* true if staging output */
513 declared = 0; /* number of local cells declared */
514 glb_declared = 0; /* number of global cells declared */
515 code_idx = 0; /* number of bytes with generated code */
516 ntv_funcid = 0; /* incremental number of native function */
517 curseg = 0; /* 1 if currently parsing CODE, 2 if parsing DATA */
518 freading = FALSE; /* no input file ready yet */
519 fline = 0; /* the line number in the current file */
520 fnumber = 0; /* the file number in the file table (debugging) */
521 fcurrent = 0; /* current file being processed (debugging) */
522 intest = 0; /* true if inside a test */
523 sideeffect = 0; /* true if an expression causes a side-effect */
524 stmtindent = 0; /* current indent of the statement */
525 indent_nowarn = TRUE; /* do not skip warning "217 loose indentation" */
526 sc_allowtags = TRUE; /* allow/detect tagnames */
527 sc_status = statIDLE;
528}
529
530static void
531initglobals(void)
532{
533 resetglobals();
534
535 skipinput = 0; /* number of lines to skip from the first
536 * input file */
537 sc_ctrlchar = CTRL_CHAR; /* the escape character */
538 litmax = sDEF_LITMAX; /* current size of the literal table */
539 errnum = 0; /* number of errors */
540 warnnum = 0; /* number of warnings */
541/* sc_debug=sCHKBOUNDS; by default: bounds checking+assertions */
542 sc_debug = 0; /* by default: no debug */
543 charbits = 8; /* a "char" is 8 bits */
544 sc_packstr = FALSE; /* strings are unpacked by default */
545/* sc_compress=TRUE; compress output bytecodes */
546 sc_compress = FALSE; /* compress output bytecodes */
547 sc_needsemicolon = FALSE; /* semicolon required to terminate
548 * expressions? */
549 sc_dataalign = 4;
550 sc_stksize = sDEF_AMXSTACK; /* default stack size */
551 sc_tabsize = 8; /* assume a TAB is 8 spaces */
552 sc_rationaltag = 0; /* assume no support for rational numbers */
553 rational_digits = 0; /* number of fractional digits */
554
555 outfname[0] = '\0'; /* output file name */
556 inpf = NULL; /* file read from */
557 inpfname = NULL; /* pointer to name of the file currently
558 * read from */
559 outf = NULL; /* file written to */
560 litq = NULL; /* the literal queue */
561 glbtab.next = NULL; /* clear global variables/constants table */
562 loctab.next = NULL; /* " local " / " " */
563 tagname_tab.next = NULL; /* tagname table */
564 libname_tab.next = NULL; /* library table (#pragma library "..."
565 * syntax) */
566
567 pline[0] = '\0'; /* the line read from the input file */
568 lptr = NULL; /* points to the current position in "pline" */
569 curlibrary = NULL; /* current library */
570 inpf_org = NULL; /* main source file */
571
572 wqptr = wq; /* initialize while queue pointer */
573
574}
575
576static void
577parseoptions(int argc, char **argv, char *iname, char *oname,
578 char *pname EINA_UNUSED, char *rname EINA_UNUSED)
579{
580 char str[PATH_MAX];
581 int i, stack_size;
582 size_t len;
583
584 /* use embryo include dir always */
585 snprintf(str, sizeof(str), "%s/include/", e_prefix_data_get());
586 insert_path(str);
587 insert_path("./");
588
589 for (i = 1; i < argc; i++)
590 {
591 if (!strcmp (argv[i], "-i") && (i + 1 < argc) && *argv[i + 1])
592 {
593 /* include directory */
594 i++;
595 strncpy(str, argv[i], sizeof(str));
596
597 len = strlen(str);
598 if (str[len - 1] != DIRSEP_CHAR)
599 {
600 str[len] = DIRSEP_CHAR;
601 str[len + 1] = '\0';
602 }
603
604 insert_path(str);
605 }
606 else if (!strcmp (argv[i], "-o") && (i + 1 < argc) && *argv[i + 1])
607 {
608 /* output file */
609 i++;
610 strcpy(oname, argv[i]); /* FIXME */
611 }
612 else if (!strcmp (argv[i], "-S") && (i + 1 < argc) && *argv[i + 1])
613 {
614 /* stack size */
615 i++;
616 stack_size = atoi(argv[i]);
617
618 if (stack_size > 64)
619 sc_stksize = (cell) stack_size;
620 else
621 about();
622 }
623 else if (!*iname)
624 {
625 /* input file */
626 strcpy(iname, argv[i]); /* FIXME */
627 }
628 else
629 {
630 /* only allow one input filename */
631 about();
632 }
633 }
634}
635
636static void
637setopt(int argc, char **argv, char *iname, char *oname,
638 char *pname, char *rname)
639{
640 *iname = '\0';
641 *oname = '\0';
642 *pname = '\0';
643 *rname = '\0';
644 strcpy(pname, sDEF_PREFIX);
645
646 parseoptions(argc, argv, iname, oname, pname, rname);
647 if (iname[0] == '\0')
648 about();
649}
650
651static void
652setconfig(char *root)
653{
654 char path[PATH_MAX];
655 char *ptr;
656 int len;
657
658 path[sizeof(path) - 1] = 0;
659
660 /* add the default "include" directory */
661 if (root)
662 {
663 /* path + filename (hopefully) */
664 strncpy(path, root, sizeof(path) - 1);
665 path[sizeof(path) - 1] = 0;
666 }
667/* terminate just behind last \ or : */
668 if ((ptr = strrchr(path, DIRSEP_CHAR))
669 || (ptr = strchr(path, ':')))
670 {
671 /* If there was no terminating "\" or ":",
672 * the filename probably does not
673 * contain the path; so we just don't add it
674 * to the list in that case
675 */
676 *(ptr + 1) = '\0';
677 if (strlen(path) < (sizeof(path) - 1 - 7))
678 {
679 strcat(path, "include");
680 }
681 len = strlen(path);
682 path[len] = DIRSEP_CHAR;
683 path[len + 1] = '\0';
684 insert_path(path);
685 } /* if */
686}
687
688static void
689about(void)
690{
691 printf("Usage: embryo_cc <filename> [options]\n\n");
692 printf("Options:\n");
693#if 0
694 printf
695 (" -A<num> alignment in bytes of the data segment and the\
696 stack\n");
697
698 printf
699 (" -a output assembler code (skip code generation\
700 pass)\n");
701
702 printf
703 (" -C[+/-] compact encoding for output file (default=%c)\n",
704 sc_compress ? '+' : '-');
705 printf(" -c8 [default] a character is 8-bits\
706 (ASCII/ISO Latin-1)\n");
707
708 printf(" -c16 a character is 16-bits (Unicode)\n");
709#if defined dos_setdrive
710 printf(" -Dpath active directory path\n");
711#endif
712 printf
713 (" -d0 no symbolic information, no run-time checks\n");
714 printf(" -d1 [default] run-time checks, no symbolic\
715 information\n");
716 printf
717 (" -d2 full debug information and dynamic checking\n");
718 printf(" -d3 full debug information, dynamic checking,\
719 no optimization\n");
720#endif
721 printf(" -i <name> path for include files\n");
722#if 0
723 printf(" -l create list file (preprocess only)\n");
724#endif
725 printf(" -o <name> set base name of output file\n");
726#if 0
727 printf
728 (" -P[+/-] strings are \"packed\" by default (default=%c)\n",
729 sc_packstr ? '+' : '-');
730 printf(" -p<name> set name of \"prefix\" file\n");
731 if (!waitkey())
732 longjmp(errbuf, 3);
733#endif
734 printf
735 (" -S <num> stack/heap size in cells (default=%d, min=65)\n",
736 (int)sc_stksize);
737#if 0
738 printf(" -s<num> skip lines from the input file\n");
739 printf
740 (" -t<num> TAB indent size (in character positions)\n");
741 printf(" -\\ use '\\' for escape characters\n");
742 printf(" -^ use '^' for escape characters\n");
743 printf(" -;[+/-] require a semicolon to end each statement\
744 (default=%c)\n", sc_needsemicolon ? '+' : '-');
745
746 printf
747 (" sym=val define constant \"sym\" with value \"val\"\n");
748 printf(" sym= define constant \"sym\" with value 0\n");
749#endif
750 longjmp(errbuf, 3); /* user abort */
751}
752
753static void
754setconstants(void)
755{
756 int debug;
757
758 assert(sc_status == statIDLE);
759 append_constval(&tagname_tab, "_", 0, 0); /* "untagged" */
760 append_constval(&tagname_tab, "bool", 1, 0);
761
762 add_constant("true", 1, sGLOBAL, 1); /* boolean flags */
763 add_constant("false", 0, sGLOBAL, 1);
764 add_constant("EOS", 0, sGLOBAL, 0); /* End Of String, or '\0' */
765 add_constant("cellbits", 32, sGLOBAL, 0);
766 add_constant("cellmax", INT_MAX, sGLOBAL, 0);
767 add_constant("cellmin", INT_MIN, sGLOBAL, 0);
768 add_constant("charbits", charbits, sGLOBAL, 0);
769 add_constant("charmin", 0, sGLOBAL, 0);
770 add_constant("charmax", (charbits == 16) ? 0xffff : 0xff, sGLOBAL, 0);
771
772 add_constant("__Small", VERSION_INT, sGLOBAL, 0);
773
774 debug = 0;
775 if ((sc_debug & (sCHKBOUNDS | sSYMBOLIC)) == (sCHKBOUNDS | sSYMBOLIC))
776 debug = 2;
777 else if ((sc_debug & sCHKBOUNDS) == sCHKBOUNDS)
778 debug = 1;
779 add_constant("debug", debug, sGLOBAL, 0);
780}
781
782/* parse - process all input text
783 *
784 * At this level, only static declarations and function definitions
785 * are legal.
786 */
787static void
788parse(void)
789{
790 int tok, tag, fconst, fstock, fstatic;
791 cell val;
792 char *str;
793
794 while (freading)
795 {
796 /* first try whether a declaration possibly is native or public */
797 tok = lex(&val, &str); /* read in (new) token */
798 switch (tok)
799 {
800 case 0:
801 /* ignore zero's */
802 break;
803 case tNEW:
804 fconst = matchtoken(tCONST);
805 declglb(NULL, 0, FALSE, FALSE, FALSE, fconst);
806 break;
807 case tSTATIC:
808 /* This can be a static function or a static global variable;
809 * we know which of the two as soon as we have parsed up to the
810 * point where an opening parenthesis of a function would be
811 * expected. To back out after deciding it was a declaration of
812 * a static variable after all, we have to store the symbol name
813 * and tag.
814 */
815 fstock = matchtoken(tSTOCK);
816 fconst = matchtoken(tCONST);
817 tag = sc_addtag(NULL);
818 tok = lex(&val, &str);
819 if (tok == tNATIVE || tok == tPUBLIC)
820 {
821 error(42); /* invalid combination of class specifiers */
822 break;
823 } /* if */
824 declfuncvar(tok, str, tag, FALSE, TRUE, fstock, fconst);
825 break;
826 case tCONST:
827 decl_const(sGLOBAL);
828 break;
829 case tENUM:
830 decl_enum(sGLOBAL);
831 break;
832 case tPUBLIC:
833 /* This can be a public function or a public variable;
834 * see the comment above (for static functions/variables)
835 * for details.
836 */
837 fconst = matchtoken(tCONST);
838 tag = sc_addtag(NULL);
839 tok = lex(&val, &str);
840 if (tok == tNATIVE || tok == tSTOCK || tok == tSTATIC)
841 {
842 error(42); /* invalid combination of class specifiers */
843 break;
844 } /* if */
845 declfuncvar(tok, str, tag, TRUE, FALSE, FALSE, fconst);
846 break;
847 case tSTOCK:
848 /* This can be a stock function or a stock *global) variable;
849 * see the comment above (for static functions/variables) for
850 * details.
851 */
852 fstatic = matchtoken(tSTATIC);
853 fconst = matchtoken(tCONST);
854 tag = sc_addtag(NULL);
855 tok = lex(&val, &str);
856 if (tok == tNATIVE || tok == tPUBLIC)
857 {
858 error(42); /* invalid combination of class specifiers */
859 break;
860 } /* if */
861 declfuncvar(tok, str, tag, FALSE, fstatic, TRUE, fconst);
862 break;
863 case tLABEL:
864 case tSYMBOL:
865 case tOPERATOR:
866 lexpush();
867 if (!newfunc(NULL, -1, FALSE, FALSE, FALSE))
868 {
869 error(10); /* illegal function or declaration */
870 lexclr(TRUE); /* drop the rest of the line */
871 } /* if */
872 break;
873 case tNATIVE:
874 funcstub(TRUE); /* create a dummy function */
875 break;
876 case tFORWARD:
877 funcstub(FALSE);
878 break;
879 case '}':
880 error(54); /* unmatched closing brace */
881 break;
882 case '{':
883 error(55); /* start of function body without function header */
884 break;
885 default:
886 if (freading)
887 {
888 error(10); /* illegal function or declaration */
889 lexclr(TRUE); /* drop the rest of the line */
890 } /* if */
891 } /* switch */
892 } /* while */
893}
894
895/* dumplits
896 *
897 * Dump the literal pool (strings etc.)
898 *
899 * Global references: litidx (referred to only)
900 */
901static void
902dumplits(void)
903{
904 int j, k;
905
906 k = 0;
907 while (k < litidx)
908 {
909 /* should be in the data segment */
910 assert(curseg == 2);
911 defstorage();
912 j = 16; /* 16 values per line */
913 while (j && k < litidx)
914 {
915 outval(litq[k], FALSE);
916 stgwrite(" ");
917 k++;
918 j--;
919 if (j == 0 || k >= litidx)
920 stgwrite("\n"); /* force a newline after 10 dumps */
921 /* Note: stgwrite() buffers a line until it is complete. It recognizes
922 * the end of line as a sequence of "\n\0", so something like "\n\t"
923 * so should not be passed to stgwrite().
924 */
925 } /* while */
926 } /* while */
927}
928
929/* dumpzero
930 *
931 * Dump zero's for default initial values
932 */
933static void
934dumpzero(int count)
935{
936 int i;
937
938 if (count <= 0)
939 return;
940 assert(curseg == 2);
941 defstorage();
942 i = 0;
943 while (count-- > 0)
944 {
945 outval(0, FALSE);
946 i = (i + 1) % 16;
947 stgwrite((i == 0 || count == 0) ? "\n" : " ");
948 if (i == 0 && count > 0)
949 defstorage();
950 } /* while */
951}
952
953static void
954aligndata(int numbytes)
955{
956 if ((((glb_declared + litidx) * sizeof(cell)) % numbytes) != 0)
957 {
958 while ((((glb_declared + litidx) * sizeof(cell)) % numbytes) != 0)
959 stowlit(0);
960 } /* if */
961
962}
963
964static void
965declfuncvar(int tok, char *symname, int tag, int fpublic, int fstatic,
966 int fstock, int fconst)
967{
968 char name[sNAMEMAX + 1];
969
970 if (tok != tSYMBOL && tok != tOPERATOR)
971 {
972 if (freading)
973 error(20, symname); /* invalid symbol name */
974 return;
975 } /* if */
976 if (tok == tOPERATOR)
977 {
978 lexpush();
979 if (!newfunc(NULL, tag, fpublic, fstatic, fstock))
980 error(10); /* illegal function or declaration */
981 }
982 else
983 {
984 assert(strlen(symname) <= sNAMEMAX);
985 strcpy(name, symname);
986 if (fconst || !newfunc(name, tag, fpublic, fstatic, fstock))
987 declglb(name, tag, fpublic, fstatic, fstock, fconst);
988 /* if not a static function, try a static variable */
989 } /* if */
990}
991
992/* declglb - declare global symbols
993 *
994 * Declare a static (global) variable. Global variables are stored in
995 * the DATA segment.
996 *
997 * global references: glb_declared (altered)
998 */
999static void
1000declglb(char *firstname, int firsttag, int fpublic, int fstatic,
1001 int stock, int fconst)
1002{
1003 int ident, tag, ispublic;
1004 int idxtag[sDIMEN_MAX];
1005 char name[sNAMEMAX + 1];
1006 cell val, size, cidx;
1007 char *str;
1008 int dim[sDIMEN_MAX];
1009 int numdim, level;
1010 int filenum;
1011 symbol *sym;
1012
1013#if !defined NDEBUG
1014 cell glbdecl = 0;
1015#endif
1016
1017 filenum = fcurrent; /* save file number at the start of the
1018 * declaration */
1019 do
1020 {
1021 size = 1; /* single size (no array) */
1022 numdim = 0; /* no dimensions */
1023 ident = iVARIABLE;
1024 if (firstname)
1025 {
1026 assert(strlen(firstname) <= sNAMEMAX);
1027 strcpy(name, firstname); /* save symbol name */
1028 tag = firsttag;
1029 firstname = NULL;
1030 }
1031 else
1032 {
1033 tag = sc_addtag(NULL);
1034 if (lex(&val, &str) != tSYMBOL) /* read in (new) token */
1035 error(20, str); /* invalid symbol name */
1036 assert(strlen(str) <= sNAMEMAX);
1037 strcpy(name, str); /* save symbol name */
1038 } /* if */
1039 sym = findglb(name);
1040 if (!sym)
1041 sym = findconst(name);
1042 if (sym && (sym->usage & uDEFINE) != 0)
1043 error(21, name); /* symbol already defined */
1044 ispublic = fpublic;
1045 if (name[0] == PUBLIC_CHAR)
1046 {
1047 ispublic = TRUE; /* implicitly public variable */
1048 if (stock || fstatic)
1049 error(42); /* invalid combination of class specifiers */
1050 } /* if */
1051 while (matchtoken('['))
1052 {
1053 ident = iARRAY;
1054 if (numdim == sDIMEN_MAX)
1055 {
1056 error(53); /* exceeding maximum number of dimensions */
1057 return;
1058 } /* if */
1059 if (numdim > 0 && dim[numdim - 1] == 0)
1060 error(52); /* only last dimension may be variable length */
1061 size = needsub(&idxtag[numdim]); /* get size; size==0 for
1062 * "var[]" */
1063#if INT_MAX < LONG_MAX
1064 if (size > INT_MAX)
1065 error(105); /* overflow, exceeding capacity */
1066#endif
1067 if (ispublic)
1068 error(56, name); /* arrays cannot be public */
1069 dim[numdim++] = (int)size;
1070 } /* while */
1071 /* if this variable is never used (which can be detected only in
1072 * the second stage), shut off code generation; make an exception
1073 * for public variables
1074 */
1075 cidx = 0; /* only to avoid a compiler warning */
1076 if (sc_status == statWRITE && sym
1077 && (sym->usage & (uREAD | uWRITTEN | uPUBLIC)) == 0)
1078 {
1079 sc_status = statSKIP;
1080 cidx = code_idx;
1081#if !defined NDEBUG
1082 glbdecl = glb_declared;
1083#endif
1084 } /* if */
1085 defsymbol(name, ident, sGLOBAL, sizeof(cell) * glb_declared, tag);
1086 begdseg(); /* real (initialized) data in data segment */
1087 assert(litidx == 0); /* literal queue should be empty */
1088 if (sc_alignnext)
1089 {
1090 litidx = 0;
1091 aligndata(sc_dataalign);
1092 dumplits(); /* dump the literal queue */
1093 sc_alignnext = FALSE;
1094 litidx = 0; /* global initial data is dumped, so restart at zero */
1095 } /* if */
1096 initials(ident, tag, &size, dim, numdim); /* stores values in
1097 * the literal queue */
1098 if (numdim == 1)
1099 dim[0] = (int)size;
1100 dumplits(); /* dump the literal queue */
1101 dumpzero((int)size - litidx);
1102 litidx = 0;
1103 if (!sym)
1104 { /* define only if not yet defined */
1105 sym =
1106 addvariable(name, sizeof(cell) * glb_declared, ident, sGLOBAL,
1107 tag, dim, numdim, idxtag);
1108 }
1109 else
1110 { /* if declared but not yet defined, adjust the
1111 * variable's address */
1112 sym->addr = sizeof(cell) * glb_declared;
1113 sym->usage |= uDEFINE;
1114 } /* if */
1115 if (ispublic)
1116 sym->usage |= uPUBLIC;
1117 if (fconst)
1118 sym->usage |= uCONST;
1119 if (stock)
1120 sym->usage |= uSTOCK;
1121 if (fstatic)
1122 sym->fnumber = filenum;
1123 if (ident == iARRAY)
1124 for (level = 0; level < numdim; level++)
1125 symbolrange(level, dim[level]);
1126 if (sc_status == statSKIP)
1127 {
1128 sc_status = statWRITE;
1129 code_idx = cidx;
1130 assert(glb_declared == glbdecl);
1131 }
1132 else
1133 {
1134 glb_declared += (int)size; /* add total number of cells */
1135 } /* if */
1136 }
1137 while (matchtoken(',')); /* enddo *//* more? */
1138 needtoken(tTERM); /* if not comma, must be semicolumn */
1139}
1140
1141/* declloc - declare local symbols
1142 *
1143 * Declare local (automatic) variables. Since these variables are
1144 * relative to the STACK, there is no switch to the DATA segment.
1145 * These variables cannot be initialized either.
1146 *
1147 * global references: declared (altered)
1148 * funcstatus (referred to only)
1149 */
1150static int
1151declloc(int fstatic)
1152{
1153 int ident, tag;
1154 int idxtag[sDIMEN_MAX];
1155 char name[sNAMEMAX + 1];
1156 symbol *sym;
1157 cell val, size;
1158 char *str;
1159 value lval = { NULL, 0, 0, 0, 0, NULL };
1160 int cur_lit = 0;
1161 int dim[sDIMEN_MAX];
1162 int numdim, level;
1163 int fconst;
1164
1165 fconst = matchtoken(tCONST);
1166 do
1167 {
1168 ident = iVARIABLE;
1169 size = 1;
1170 numdim = 0; /* no dimensions */
1171 tag = sc_addtag(NULL);
1172 if (lex(&val, &str) != tSYMBOL) /* read in (new) token */
1173 error(20, str); /* invalid symbol name */
1174 assert(strlen(str) <= sNAMEMAX);
1175 strcpy(name, str); /* save symbol name */
1176 if (name[0] == PUBLIC_CHAR)
1177 error(56, name); /* local variables cannot be public */
1178 /* Note: block locals may be named identical to locals at higher
1179 * compound blocks (as with standard C); so we must check (and add)
1180 * the "nesting level" of local variables to verify the
1181 * multi-definition of symbols.
1182 */
1183 if ((sym = findloc(name)) && sym->compound == nestlevel)
1184 error(21, name); /* symbol already defined */
1185 /* Although valid, a local variable whose name is equal to that
1186 * of a global variable or to that of a local variable at a lower
1187 * level might indicate a bug.
1188 */
1189 if (((sym = findloc(name)) && sym->compound != nestlevel)
1190 || findglb(name))
1191 error(219, name); /* variable shadows another symbol */
1192 while (matchtoken('['))
1193 {
1194 ident = iARRAY;
1195 if (numdim == sDIMEN_MAX)
1196 {
1197 error(53); /* exceeding maximum number of dimensions */
1198 return ident;
1199 } /* if */
1200 if (numdim > 0 && dim[numdim - 1] == 0)
1201 error(52); /* only last dimension may be variable length */
1202 size = needsub(&idxtag[numdim]); /* get size; size==0 for "var[]" */
1203#if INT_MAX < LONG_MAX
1204 if (size > INT_MAX)
1205 error(105); /* overflow, exceeding capacity */
1206#endif
1207 dim[numdim++] = (int)size;
1208 } /* while */
1209 if (ident == iARRAY || fstatic)
1210 {
1211 if (sc_alignnext)
1212 {
1213 aligndata(sc_dataalign);
1214 sc_alignnext = FALSE;
1215 } /* if */
1216 cur_lit = litidx; /* save current index in the literal table */
1217 initials(ident, tag, &size, dim, numdim);
1218 if (size == 0)
1219 return ident; /* error message already given */
1220 if (numdim == 1)
1221 dim[0] = (int)size;
1222 } /* if */
1223 /* reserve memory (on the stack) for the variable */
1224 if (fstatic)
1225 {
1226 /* write zeros for uninitialized fields */
1227 while (litidx < cur_lit + size)
1228 stowlit(0);
1229 sym =
1230 addvariable(name, (cur_lit + glb_declared) * sizeof(cell),
1231 ident, sSTATIC, tag, dim, numdim, idxtag);
1232 defsymbol(name, ident, sSTATIC,
1233 (cur_lit + glb_declared) * sizeof(cell), tag);
1234 }
1235 else
1236 {
1237 declared += (int)size; /* variables are put on stack,
1238 * adjust "declared" */
1239 sym =
1240 addvariable(name, -declared * sizeof(cell), ident, sLOCAL, tag,
1241 dim, numdim, idxtag);
1242 defsymbol(name, ident, sLOCAL, -declared * sizeof(cell), tag);
1243 modstk(-(int)size * sizeof(cell));
1244 } /* if */
1245 /* now that we have reserved memory for the variable, we can
1246 * proceed to initialize it */
1247 sym->compound = nestlevel; /* for multiple declaration/shadowing */
1248 if (fconst)
1249 sym->usage |= uCONST;
1250 if (ident == iARRAY)
1251 for (level = 0; level < numdim; level++)
1252 symbolrange(level, dim[level]);
1253 if (!fstatic)
1254 { /* static variables already initialized */
1255 if (ident == iVARIABLE)
1256 {
1257 /* simple variable, also supports initialization */
1258 int ctag = tag; /* set to "tag" by default */
1259 int explicit_init = FALSE; /* is the variable explicitly
1260 * initialized? */
1261 if (matchtoken('='))
1262 {
1263 doexpr(FALSE, FALSE, FALSE, FALSE, &ctag, TRUE);
1264 explicit_init = TRUE;
1265 }
1266 else
1267 {
1268 const1(0); /* uninitialized variable, set to zero */
1269 } /* if */
1270 /* now try to save the value (still in PRI) in the variable */
1271 lval.sym = sym;
1272 lval.ident = iVARIABLE;
1273 lval.constval = 0;
1274 lval.tag = tag;
1275 check_userop(NULL, ctag, lval.tag, 2, NULL, &ctag);
1276 store(&lval);
1277 endexpr(TRUE); /* full expression ends after the store */
1278 if (!matchtag(tag, ctag, TRUE))
1279 error(213); /* tag mismatch */
1280 /* if the variable was not explicitly initialized, reset the
1281 * "uWRITTEN" flag that store() set */
1282 if (!explicit_init)
1283 sym->usage &= ~uWRITTEN;
1284 }
1285 else
1286 {
1287 /* an array */
1288 if (litidx - cur_lit < size)
1289 fillarray(sym, size * sizeof(cell), 0);
1290 if (cur_lit < litidx)
1291 {
1292 /* check whether the complete array is set to a single value;
1293 * if it is, more compact code can be generated */
1294 cell first = litq[cur_lit];
1295 int i;
1296
1297 for (i = cur_lit; i < litidx && litq[i] == first; i++)
1298 /* nothing */ ;
1299 if (i == litidx)
1300 {
1301 /* all values are the same */
1302 fillarray(sym, (litidx - cur_lit) * sizeof(cell),
1303 first);
1304 litidx = cur_lit; /* reset literal table */
1305 }
1306 else
1307 {
1308 /* copy the literals to the array */
1309 const1((cur_lit + glb_declared) * sizeof(cell));
1310 copyarray(sym, (litidx - cur_lit) * sizeof(cell));
1311 } /* if */
1312 } /* if */
1313 } /* if */
1314 } /* if */
1315 }
1316 while (matchtoken(',')); /* enddo *//* more? */
1317 needtoken(tTERM); /* if not comma, must be semicolumn */
1318 return ident;
1319}
1320
1321static cell
1322calc_arraysize(int dim[], int numdim, int cur)
1323{
1324 if (cur == numdim)
1325 return 0;
1326 return dim[cur] + (dim[cur] * calc_arraysize(dim, numdim, cur + 1));
1327}
1328
1329/* initials
1330 *
1331 * Initialize global objects and local arrays.
1332 * size==array cells (count), if 0 on input, the routine counts
1333 * the number of elements
1334 * tag==required tagname id (not the returned tag)
1335 *
1336 * Global references: litidx (altered)
1337 */
1338static void
1339initials(int ident, int tag, cell * size, int dim[], int numdim)
1340{
1341 int ctag;
1342 int curlit = litidx;
1343 int d;
1344
1345 if (!matchtoken('='))
1346 {
1347 if (ident == iARRAY && dim[numdim - 1] == 0)
1348 {
1349 /* declared as "myvar[];" which is senseless (note: this *does* make
1350 * sense in the case of a iREFARRAY, which is a function parameter)
1351 */
1352 error(9); /* array has zero length -> invalid size */
1353 } /* if */
1354 if (numdim > 1)
1355 {
1356 /* initialize the indirection tables */
1357#if sDIMEN_MAX>2
1358#error Array algorithms for more than 2 dimensions are not implemented
1359#endif
1360 assert(numdim == 2);
1361 *size = calc_arraysize(dim, numdim, 0);
1362 for (d = 0; d < dim[0]; d++)
1363 stowlit((dim[0] + d * (dim[1] - 1)) * sizeof(cell));
1364 } /* if */
1365 return;
1366 } /* if */
1367
1368 if (ident == iVARIABLE)
1369 {
1370 assert(*size == 1);
1371 init(ident, &ctag);
1372 if (!matchtag(tag, ctag, TRUE))
1373 error(213); /* tag mismatch */
1374 }
1375 else
1376 {
1377 assert(numdim > 0);
1378 if (numdim == 1)
1379 {
1380 *size = initvector(ident, tag, dim[0], FALSE);
1381 }
1382 else
1383 {
1384 cell offs, dsize;
1385
1386 /* The simple algorithm below only works for arrays with one or
1387 * two dimensions. This should be some recursive algorithm.
1388 */
1389 if (dim[numdim - 1] != 0)
1390 /* set size to (known) full size */
1391 *size = calc_arraysize(dim, numdim, 0);
1392 /* dump indirection tables */
1393 for (d = 0; d < dim[0]; d++)
1394 stowlit(0);
1395 /* now dump individual vectors */
1396 needtoken('{');
1397 offs = dim[0];
1398 for (d = 0; d < dim[0]; d++)
1399 {
1400 litq[curlit + d] = offs * sizeof(cell);
1401 dsize = initvector(ident, tag, dim[1], TRUE);
1402 offs += dsize - 1;
1403 if (d + 1 < dim[0])
1404 needtoken(',');
1405 if (matchtoken('{') || matchtoken(tSTRING))
1406 /* expect a '{' or a string */
1407 lexpush();
1408 else
1409 break;
1410 } /* for */
1411 matchtoken(',');
1412 needtoken('}');
1413 } /* if */
1414 } /* if */
1415
1416 if (*size == 0)
1417 *size = litidx - curlit; /* number of elements defined */
1418}
1419
1420/* initvector
1421 * Initialize a single dimensional array
1422 */
1423static cell
1424initvector(int ident, int tag, cell size, int fillzero)
1425{
1426 cell prev1 = 0, prev2 = 0;
1427 int ctag;
1428 int ellips = FALSE;
1429 int curlit = litidx;
1430
1431 assert(ident == iARRAY || ident == iREFARRAY);
1432 if (matchtoken('{'))
1433 {
1434 do
1435 {
1436 if (matchtoken('}'))
1437 { /* to allow for trailing ',' after the initialization */
1438 lexpush();
1439 break;
1440 } /* if */
1441 if ((ellips = matchtoken(tELLIPS)) != 0)
1442 break;
1443 prev2 = prev1;
1444 prev1 = init(ident, &ctag);
1445 if (!matchtag(tag, ctag, TRUE))
1446 error(213); /* tag mismatch */
1447 }
1448 while (matchtoken(',')); /* do */
1449 needtoken('}');
1450 }
1451 else
1452 {
1453 init(ident, &ctag);
1454 if (!matchtag(tag, ctag, TRUE))
1455 error(213); /* tagname mismatch */
1456 } /* if */
1457 /* fill up the literal queue with a series */
1458 if (ellips)
1459 {
1460 cell step =
1461 ((litidx - curlit) == 1) ? (cell) 0 : prev1 - prev2;
1462 if (size == 0 || (litidx - curlit) == 0)
1463 error(41); /* invalid ellipsis, array size unknown */
1464 else if ((litidx - curlit) == (int)size)
1465 error(18); /* initialisation data exceeds declared size */
1466 while ((litidx - curlit) < (int)size)
1467 {
1468 prev1 += step;
1469 stowlit(prev1);
1470 } /* while */
1471 } /* if */
1472 if (fillzero && size > 0)
1473 {
1474 while ((litidx - curlit) < (int)size)
1475 stowlit(0);
1476 } /* if */
1477 if (size == 0)
1478 {
1479 size = litidx - curlit; /* number of elements defined */
1480 }
1481 else if (litidx - curlit > (int)size)
1482 { /* e.g. "myvar[3]={1,2,3,4};" */
1483 error(18); /* initialisation data exceeds declared size */
1484 litidx = (int)size + curlit; /* avoid overflow in memory moves */
1485 } /* if */
1486 return size;
1487}
1488
1489/* init
1490 *
1491 * Evaluate one initializer.
1492 */
1493static cell
1494init(int ident, int *tag)
1495{
1496 cell i = 0;
1497
1498 if (matchtoken(tSTRING))
1499 {
1500 /* lex() automatically stores strings in the literal table (and
1501 * increases "litidx") */
1502 if (ident == iVARIABLE)
1503 {
1504 error(6); /* must be assigned to an array */
1505 litidx = 1; /* reset literal queue */
1506 } /* if */
1507 *tag = 0;
1508 }
1509 else if (constexpr(&i, tag))
1510 {
1511 stowlit(i); /* store expression result in literal table */
1512 } /* if */
1513 return i;
1514}
1515
1516/* needsub
1517 *
1518 * Get required array size
1519 */
1520static cell
1521needsub(int *tag)
1522{
1523 cell val;
1524
1525 *tag = 0;
1526 if (matchtoken(']')) /* we've already seen "[" */
1527 return 0; /* null size (like "char msg[]") */
1528 constexpr(&val, tag); /* get value (must be constant expression) */
1529 if (val < 0)
1530 {
1531 error(9); /* negative array size is invalid; assumed zero */
1532 val = 0;
1533 } /* if */
1534 needtoken(']');
1535 return val; /* return array size */
1536}
1537
1538/* decl_const - declare a single constant
1539 *
1540 */
1541static void
1542decl_const(int vclass)
1543{
1544 char constname[sNAMEMAX + 1];
1545 cell val;
1546 char *str;
1547 int tag, exprtag;
1548 int symbolline;
1549
1550 tag = sc_addtag(NULL);
1551 if (lex(&val, &str) != tSYMBOL) /* read in (new) token */
1552 error(20, str); /* invalid symbol name */
1553 symbolline = fline; /* save line where symbol was found */
1554 strcpy(constname, str); /* save symbol name */
1555 needtoken('=');
1556 constexpr(&val, &exprtag); /* get value */
1557 needtoken(tTERM);
1558 /* add_constant() checks for duplicate definitions */
1559 if (!matchtag(tag, exprtag, FALSE))
1560 {
1561 /* temporarily reset the line number to where the symbol was
1562 * defined */
1563 int orgfline = fline;
1564
1565 fline = symbolline;
1566 error(213); /* tagname mismatch */
1567 fline = orgfline;
1568 } /* if */
1569 add_constant(constname, val, vclass, tag);
1570}
1571
1572/* decl_enum - declare enumerated constants
1573 *
1574 */
1575static void
1576decl_enum(int vclass)
1577{
1578 char enumname[sNAMEMAX + 1], constname[sNAMEMAX + 1];
1579 cell val, value, size;
1580 char *str;
1581 int tok, tag, explicittag;
1582 cell increment, multiplier;
1583
1584 /* get an explicit tag, if any (we need to remember whether an
1585 * explicit tag was passed, even if that explicit tag was "_:", so we
1586 * cannot call sc_addtag() here
1587 */
1588 if (lex(&val, &str) == tLABEL)
1589 {
1590 tag = sc_addtag(str);
1591 explicittag = TRUE;
1592 }
1593 else
1594 {
1595 lexpush();
1596 tag = 0;
1597 explicittag = FALSE;
1598 } /* if */
1599
1600 /* get optional enum name (also serves as a tag if no explicit
1601 * tag was set) */
1602 if (lex(&val, &str) == tSYMBOL)
1603 { /* read in (new) token */
1604 strcpy(enumname, str); /* save enum name (last constant) */
1605 if (!explicittag)
1606 tag = sc_addtag(enumname);
1607 }
1608 else
1609 {
1610 lexpush(); /* analyze again */
1611 enumname[0] = '\0';
1612 } /* if */
1613
1614 /* get increment and multiplier */
1615 increment = 1;
1616 multiplier = 1;
1617 if (matchtoken('('))
1618 {
1619 if (matchtoken(taADD))
1620 {
1621 constexpr(&increment, NULL);
1622 }
1623 else if (matchtoken(taMULT))
1624 {
1625 constexpr(&multiplier, NULL);
1626 }
1627 else if (matchtoken(taSHL))
1628 {
1629 constexpr(&val, NULL);
1630 while (val-- > 0)
1631 multiplier *= 2;
1632 } /* if */
1633 needtoken(')');
1634 } /* if */
1635
1636 needtoken('{');
1637 /* go through all constants */
1638 value = 0; /* default starting value */
1639 do
1640 {
1641 if (matchtoken('}'))
1642 { /* quick exit if '}' follows ',' */
1643 lexpush();
1644 break;
1645 } /* if */
1646 tok = lex(&val, &str); /* read in (new) token */
1647 if (tok != tSYMBOL && tok != tLABEL)
1648 error(20, str); /* invalid symbol name */
1649 strcpy(constname, str); /* save symbol name */
1650 size = increment; /* default increment of 'val' */
1651 if (tok == tLABEL || matchtoken(':'))
1652 constexpr(&size, NULL); /* get size */
1653 if (matchtoken('='))
1654 constexpr(&value, NULL); /* get value */
1655 /* add_constant() checks whether a variable (global or local) or
1656 * a constant with the same name already exists */
1657 add_constant(constname, value, vclass, tag);
1658 if (multiplier == 1)
1659 value += size;
1660 else
1661 value *= size * multiplier;
1662 }
1663 while (matchtoken(','));
1664 needtoken('}'); /* terminates the constant list */
1665 matchtoken(';'); /* eat an optional ; */
1666
1667 /* set the enum name to the last value plus one */
1668 if (enumname[0] != '\0')
1669 add_constant(enumname, value, vclass, tag);
1670}
1671
1672/*
1673 * Finds a function in the global symbol table or creates a new entry.
1674 * It does some basic processing and error checking.
1675 */
1676symbol *
1677fetchfunc(char *name, int tag)
1678{
1679 symbol *sym;
1680 cell offset;
1681
1682 offset = code_idx;
1683 if ((sc_debug & sSYMBOLIC) != 0)
1684 {
1685 offset += opcodes(1) + opargs(3) + nameincells(name);
1686 /* ^^^ The address for the symbol is the code address. But the
1687 * "symbol" instruction itself generates code. Therefore the
1688 * offset is pre-adjusted to the value it will have after the
1689 * symbol instruction.
1690 */
1691 } /* if */
1692 if ((sym = findglb(name)))
1693 { /* already in symbol table? */
1694 if (sym->ident != iFUNCTN)
1695 {
1696 error(21, name); /* yes, but not as a function */
1697 return NULL; /* make sure the old symbol is not damaged */
1698 }
1699 else if ((sym->usage & uDEFINE) != 0)
1700 {
1701 error(21, name); /* yes, and it's already defined */
1702 }
1703 else if ((sym->usage & uNATIVE) != 0)
1704 {
1705 error(21, name); /* yes, and it is an native */
1706 } /* if */
1707 assert(sym->vclass == sGLOBAL);
1708 if ((sym->usage & uDEFINE) == 0)
1709 {
1710 /* as long as the function stays undefined, update the address
1711 * and the tag */
1712 sym->addr = offset;
1713 sym->tag = tag;
1714 } /* if */
1715 }
1716 else
1717 {
1718 /* don't set the "uDEFINE" flag; it may be a prototype */
1719 sym = addsym(name, offset, iFUNCTN, sGLOBAL, tag, 0);
1720 /* assume no arguments */
1721 sym->dim.arglist = (arginfo *) malloc(1 * sizeof(arginfo));
1722 sym->dim.arglist[0].ident = 0;
1723 /* set library ID to NULL (only for native functions) */
1724 sym->x.lib = NULL;
1725 } /* if */
1726 return sym;
1727}
1728
1729/* This routine adds symbolic information for each argument.
1730 */
1731static void
1732define_args(void)
1733{
1734 symbol *sym;
1735
1736 /* At this point, no local variables have been declared. All
1737 * local symbols are function arguments.
1738 */
1739 sym = loctab.next;
1740 while (sym)
1741 {
1742 assert(sym->ident != iLABEL);
1743 assert(sym->vclass == sLOCAL);
1744 defsymbol(sym->name, sym->ident, sLOCAL, sym->addr, sym->tag);
1745 if (sym->ident == iREFARRAY)
1746 {
1747 symbol *sub = sym;
1748
1749 while (sub)
1750 {
1751 symbolrange(sub->dim.array.level, sub->dim.array.length);
1752 sub = finddepend(sub);
1753 } /* while */
1754 } /* if */
1755 sym = sym->next;
1756 } /* while */
1757}
1758
1759static int
1760operatorname(char *name)
1761{
1762 int opertok;
1763 char *str;
1764 cell val;
1765
1766 assert(name != NULL);
1767
1768 /* check the operator */
1769 opertok = lex(&val, &str);
1770 switch (opertok)
1771 {
1772 case '+':
1773 case '-':
1774 case '*':
1775 case '/':
1776 case '%':
1777 case '>':
1778 case '<':
1779 case '!':
1780 case '~':
1781 case '=':
1782 name[0] = (char)opertok;
1783 name[1] = '\0';
1784 break;
1785 case tINC:
1786 strcpy(name, "++");
1787 break;
1788 case tDEC:
1789 strcpy(name, "--");
1790 break;
1791 case tlEQ:
1792 strcpy(name, "==");
1793 break;
1794 case tlNE:
1795 strcpy(name, "!=");
1796 break;
1797 case tlLE:
1798 strcpy(name, "<=");
1799 break;
1800 case tlGE:
1801 strcpy(name, ">=");
1802 break;
1803 default:
1804 name[0] = '\0';
1805 error(61); /* operator cannot be redefined
1806 * (or bad operator name) */
1807 return 0;
1808 } /* switch */
1809
1810 return opertok;
1811}
1812
1813static int
1814operatoradjust(int opertok, symbol * sym, char *opername, int resulttag)
1815{
1816 int tags[2] = { 0, 0 };
1817 int count = 0;
1818 arginfo *arg;
1819 char tmpname[sNAMEMAX + 1];
1820 symbol *oldsym;
1821
1822 if (opertok == 0)
1823 return TRUE;
1824
1825 /* count arguments and save (first two) tags */
1826 while (arg = &sym->dim.arglist[count], arg->ident != 0)
1827 {
1828 if (count < 2)
1829 {
1830 if (arg->numtags > 1)
1831 error(65, count + 1); /* function argument may only have
1832 * a single tag */
1833 else if (arg->numtags == 1)
1834 tags[count] = arg->tags[0];
1835 } /* if */
1836 if (opertok == '~' && count == 0)
1837 {
1838 if (arg->ident != iREFARRAY)
1839 error(73, arg->name); /* must be an array argument */
1840 }
1841 else
1842 {
1843 if (arg->ident != iVARIABLE)
1844 error(66, arg->name); /* must be non-reference argument */
1845 } /* if */
1846 if (arg->hasdefault)
1847 error(59, arg->name); /* arguments of an operator may not
1848 * have a default value */
1849 count++;
1850 } /* while */
1851
1852 /* for '!', '++' and '--', count must be 1
1853 * for '-', count may be 1 or 2
1854 * for '=', count must be 1, and the resulttag is also important
1855 * for all other (binary) operators and the special '~'
1856 * operator, count must be 2
1857 */
1858 switch (opertok)
1859 {
1860 case '!':
1861 case '=':
1862 case tINC:
1863 case tDEC:
1864 if (count != 1)
1865 error(62); /* number or placement of the operands does
1866 * not fit the operator */
1867 break;
1868 case '-':
1869 if (count != 1 && count != 2)
1870 error(62); /* number or placement of the operands does
1871 * not fit the operator */
1872 break;
1873 default:
1874 if (count != 2)
1875 error(62); /* number or placement of the operands does
1876 * not fit the operator */
1877 } /* switch */
1878
1879 if (tags[0] == 0
1880 && ((opertok != '=' && tags[1] == 0) || (opertok == '=' && resulttag == 0)))
1881 error(64); /* cannot change predefined operators */
1882
1883 /* change the operator name */
1884 assert(opername[0] != '\0');
1885 operator_symname(tmpname, opername, tags[0], tags[1], count, resulttag);
1886 if ((oldsym = findglb(tmpname)))
1887 {
1888 int i;
1889
1890 if ((oldsym->usage & uDEFINE) != 0)
1891 {
1892 char errname[2 * sNAMEMAX + 16];
1893
1894 funcdisplayname(errname, tmpname);
1895 error(21, errname); /* symbol already defined */
1896 } /* if */
1897 sym->usage |= oldsym->usage; /* copy flags from the previous
1898 * definition */
1899 for (i = 0; i < oldsym->numrefers; i++)
1900 if (oldsym->refer[i])
1901 refer_symbol(sym, oldsym->refer[i]);
1902 delete_symbol(&glbtab, oldsym);
1903 } /* if */
1904 if ((sc_debug & sSYMBOLIC) != 0)
1905 sym->addr += nameincells(tmpname) - nameincells(sym->name);
1906 strcpy(sym->name, tmpname);
1907 sym->hash = namehash(sym->name); /* calculate new hash */
1908
1909 /* operators should return a value, except the '~' operator */
1910 if (opertok != '~')
1911 sym->usage |= uRETVALUE;
1912
1913 return TRUE;
1914}
1915
1916static int
1917check_operatortag(int opertok, int resulttag, char *opername)
1918{
1919 assert(opername != NULL && opername[0] != '\0');
1920 switch (opertok)
1921 {
1922 case '!':
1923 case '<':
1924 case '>':
1925 case tlEQ:
1926 case tlNE:
1927 case tlLE:
1928 case tlGE:
1929 if (resulttag != sc_addtag("bool"))
1930 {
1931 error(63, opername, "bool:"); /* operator X requires
1932 * a "bool:" result tag */
1933 return FALSE;
1934 } /* if */
1935 break;
1936 case '~':
1937 if (resulttag != 0)
1938 {
1939 error(63, opername, "_:"); /* operator "~" requires
1940 * a "_:" result tag */
1941 return FALSE;
1942 } /* if */
1943 break;
1944 } /* switch */
1945 return TRUE;
1946}
1947
1948static char *
1949tag2str(char *dest, int tag)
1950{
1951 tag &= TAGMASK;
1952 assert(tag >= 0);
1953 sprintf(dest, "0%x", tag);
1954 return sc_isdigit(dest[1]) ? &dest[1] : dest;
1955}
1956
1957char *
1958operator_symname(char *symname, char *opername, int tag1, int tag2,
1959 int numtags, int resulttag)
1960{
1961 char tagstr1[10], tagstr2[10];
1962 int opertok;
1963
1964 assert(numtags >= 1 && numtags <= 2);
1965 opertok = (opername[1] == '\0') ? opername[0] : 0;
1966 if (opertok == '=')
1967 sprintf(symname, "%s%s%s", tag2str(tagstr1, resulttag), opername,
1968 tag2str(tagstr2, tag1));
1969 else if (numtags == 1 || opertok == '~')
1970 sprintf(symname, "%s%s", opername, tag2str(tagstr1, tag1));
1971 else
1972 sprintf(symname, "%s%s%s", tag2str(tagstr1, tag1), opername,
1973 tag2str(tagstr2, tag2));
1974 return symname;
1975}
1976
1977static int
1978parse_funcname(char *fname, int *tag1, int *tag2, char *opname)
1979{
1980 char *ptr, *name;
1981 int unary;
1982
1983 /* tags are only positive, so if the function name starts with a '-',
1984 * the operator is an unary '-' or '--' operator.
1985 */
1986 if (*fname == '-')
1987 {
1988 *tag1 = 0;
1989 unary = TRUE;
1990 ptr = fname;
1991 }
1992 else
1993 {
1994 *tag1 = (int)strtol(fname, &ptr, 16);
1995 unary = ptr == fname; /* unary operator if it doesn't start
1996 * with a tag name */
1997 } /* if */
1998 assert(!unary || *tag1 == 0);
1999 assert(*ptr != '\0');
2000 for (name = opname; !sc_isdigit(*ptr);)
2001 *name++ = *ptr++;
2002 *name = '\0';
2003 *tag2 = (int)strtol(ptr, NULL, 16);
2004 return unary;
2005}
2006
2007char *
2008funcdisplayname(char *dest, char *funcname)
2009{
2010 int tags[2];
2011 char opname[10];
2012 constvalue *tagsym[2];
2013 int unary;
2014
2015 if (sc_isalpha(*funcname) || *funcname == '_' || *funcname == PUBLIC_CHAR
2016 || *funcname == '\0')
2017 {
2018 if (dest != funcname)
2019 strcpy(dest, funcname);
2020 return dest;
2021 } /* if */
2022
2023 unary = parse_funcname(funcname, &tags[0], &tags[1], opname);
2024 tagsym[1] = find_constval_byval(&tagname_tab, tags[1]);
2025 assert(tagsym[1] != NULL);
2026 if (unary)
2027 {
2028 sprintf(dest, "operator%s(%s:)", opname, tagsym[1]->name);
2029 }
2030 else
2031 {
2032 tagsym[0] = find_constval_byval(&tagname_tab, tags[0]);
2033 /* special case: the assignment operator has the return value
2034 * as the 2nd tag */
2035 if (opname[0] == '=' && opname[1] == '\0')
2036 sprintf(dest, "%s:operator%s(%s:)", tagsym[0]->name, opname,
2037 tagsym[1]->name);
2038 else
2039 sprintf(dest, "operator%s(%s:,%s:)", opname, tagsym[0]->name,
2040 tagsym[1]->name);
2041 } /* if */
2042 return dest;
2043}
2044
2045static void
2046funcstub(int native)
2047{
2048 int tok, tag;
2049 char *str;
2050 cell val;
2051 char symbolname[sNAMEMAX + 1];
2052 symbol *sym;
2053 int opertok;
2054
2055 opertok = 0;
2056 lastst = 0;
2057 litidx = 0; /* clear the literal pool */
2058
2059 tag = sc_addtag(NULL);
2060 tok = lex(&val, &str);
2061 if (native)
2062 {
2063 if (tok == tPUBLIC || tok == tSTOCK || tok == tSTATIC ||
2064 (tok == tSYMBOL && *str == PUBLIC_CHAR))
2065 error(42); /* invalid combination of class specifiers */
2066 }
2067 else
2068 {
2069 if (tok == tPUBLIC || tok == tSTATIC)
2070 tok = lex(&val, &str);
2071 } /* if */
2072 if (tok == tOPERATOR)
2073 {
2074 opertok = operatorname(symbolname);
2075 if (opertok == 0)
2076 return; /* error message already given */
2077 check_operatortag(opertok, tag, symbolname);
2078 }
2079 else
2080 {
2081 if (tok != tSYMBOL && freading)
2082 {
2083 error(10); /* illegal function or declaration */
2084 return;
2085 } /* if */
2086 strcpy(symbolname, str);
2087 } /* if */
2088 needtoken('('); /* only functions may be native/forward */
2089
2090 sym = fetchfunc(symbolname, tag); /* get a pointer to the
2091 * function entry */
2092 if (!sym)
2093 return;
2094 if (native)
2095 {
2096 sym->usage = uNATIVE | uRETVALUE | uDEFINE;
2097 sym->x.lib = curlibrary;
2098 } /* if */
2099
2100 declargs(sym);
2101 /* "declargs()" found the ")" */
2102 if (!operatoradjust(opertok, sym, symbolname, tag))
2103 sym->usage &= ~uDEFINE;
2104 /* for a native operator, also need to specify an "exported"
2105 * function name; for a native function, this is optional
2106 */
2107 if (native)
2108 {
2109 if (opertok != 0)
2110 {
2111 needtoken('=');
2112 lexpush(); /* push back, for matchtoken() to retrieve again */
2113 } /* if */
2114 if (matchtoken('='))
2115 {
2116 /* allow number or symbol */
2117 if (matchtoken(tSYMBOL))
2118 {
2119 tokeninfo(&val, &str);
2120 if (strlen(str) > sEXPMAX)
2121 {
2122 error(220, str, sEXPMAX);
2123 str[sEXPMAX] = '\0';
2124 } /* if */
2125 insert_alias(sym->name, str);
2126 }
2127 else
2128 {
2129 constexpr(&val, NULL);
2130 sym->addr = val;
2131 /*
2132 * ?? Must mark this address, so that it won't be generated again
2133 * and it won't be written to the output file. At the moment,
2134 * I have assumed that this syntax is only valid if val < 0.
2135 * To properly mix "normal" native functions and indexed native
2136 * functions, one should use negative indices anyway.
2137 * Special code for a negative index in sym->addr exists in
2138 * SC4.C (ffcall()) and in SC6.C (the loops for counting the
2139 * number of native variables and for writing them).
2140 */
2141 } /* if */
2142 } /* if */
2143 } /* if */
2144 needtoken(tTERM);
2145
2146 litidx = 0; /* clear the literal pool */
2147 /* clear local variables queue */
2148 delete_symbols(&loctab, 0, TRUE, TRUE);
2149}
2150
2151/* newfunc - begin a function
2152 *
2153 * This routine is called from "parse" and tries to make a function
2154 * out of the following text
2155 *
2156 * Global references: funcstatus,lastst,litidx
2157 * rettype (altered)
2158 * curfunc (altered)
2159 * declared (altered)
2160 * glb_declared (altered)
2161 * sc_alignnext (altered)
2162 */
2163static int
2164newfunc(char *firstname, int firsttag, int fpublic, int fstatic, int stock)
2165{
2166 symbol *sym;
2167 int argcnt, tok, tag, funcline;
2168 int opertok, opererror;
2169 char symbolname[sNAMEMAX + 1];
2170 char *str;
2171 cell val, cidx, glbdecl;
2172 int filenum;
2173
2174 litidx = 0; /* clear the literal pool ??? */
2175 opertok = 0;
2176 lastst = 0; /* no statement yet */
2177 cidx = 0; /* just to avoid compiler warnings */
2178 glbdecl = 0;
2179 filenum = fcurrent; /* save file number at start of declaration */
2180
2181 if (firstname)
2182 {
2183 assert(strlen(firstname) <= sNAMEMAX);
2184 strcpy(symbolname, firstname); /* save symbol name */
2185 tag = firsttag;
2186 }
2187 else
2188 {
2189 tag = (firsttag >= 0) ? firsttag : sc_addtag(NULL);
2190 tok = lex(&val, &str);
2191 assert(!fpublic);
2192 if (tok == tNATIVE || (tok == tPUBLIC && stock))
2193 error(42); /* invalid combination of class specifiers */
2194 if (tok == tOPERATOR)
2195 {
2196 opertok = operatorname(symbolname);
2197 if (opertok == 0)
2198 return TRUE; /* error message already given */
2199 check_operatortag(opertok, tag, symbolname);
2200 }
2201 else
2202 {
2203 if (tok != tSYMBOL && freading)
2204 {
2205 error(20, str); /* invalid symbol name */
2206 return FALSE;
2207 } /* if */
2208 assert(strlen(str) <= sNAMEMAX);
2209 strcpy(symbolname, str);
2210 } /* if */
2211 } /* if */
2212 /* check whether this is a function or a variable declaration */
2213 if (!matchtoken('('))
2214 return FALSE;
2215 /* so it is a function, proceed */
2216 funcline = fline; /* save line at which the function is defined */
2217 if (symbolname[0] == PUBLIC_CHAR)
2218 {
2219 fpublic = TRUE; /* implicitly public function */
2220 if (stock)
2221 error(42); /* invalid combination of class specifiers */
2222 } /* if */
2223 sym = fetchfunc(symbolname, tag); /* get a pointer to the
2224 * function entry */
2225 if (!sym)
2226 return TRUE;
2227 if (fpublic)
2228 sym->usage |= uPUBLIC;
2229 if (fstatic)
2230 sym->fnumber = filenum;
2231 /* declare all arguments */
2232 argcnt = declargs(sym);
2233 opererror = !operatoradjust(opertok, sym, symbolname, tag);
2234 if (strcmp(symbolname, uMAINFUNC) == 0)
2235 {
2236 if (argcnt > 0)
2237 error(5); /* "main()" function may not have any arguments */
2238 sym->usage |= uREAD; /* "main()" is the program's entry point:
2239 * always used */
2240 } /* if */
2241 /* "declargs()" found the ")"; if a ";" appears after this, it was a
2242 * prototype */
2243 if (matchtoken(';'))
2244 {
2245 if (!sc_needsemicolon)
2246 error(218); /* old style prototypes used with optional
2247 * semicolumns */
2248 delete_symbols(&loctab, 0, TRUE, TRUE); /* prototype is done;
2249 * forget everything */
2250 return TRUE;
2251 } /* if */
2252 /* so it is not a prototype, proceed */
2253 /* if this is a function that is not referred to (this can only be
2254 * detected in the second stage), shut code generation off */
2255 if (sc_status == statWRITE && (sym->usage & uREAD) == 0)
2256 {
2257 sc_status = statSKIP;
2258 cidx = code_idx;
2259 glbdecl = glb_declared;
2260 } /* if */
2261 begcseg();
2262 sym->usage |= uDEFINE; /* set the definition flag */
2263 if (fpublic)
2264 sym->usage |= uREAD; /* public functions are always "used" */
2265 if (stock)
2266 sym->usage |= uSTOCK;
2267 if (opertok != 0 && opererror)
2268 sym->usage &= ~uDEFINE;
2269 defsymbol(sym->name, iFUNCTN, sGLOBAL,
2270 code_idx + opcodes(1) + opargs(3) + nameincells(sym->name), tag);
2271 /* ^^^ The address for the symbol is the code address. But the
2272 * "symbol" instruction itself generates code. Therefore the
2273 * offset is pre-adjusted to the value it will have after the
2274 * symbol instruction.
2275 */
2276 startfunc(sym->name); /* creates stack frame */
2277 if ((sc_debug & sSYMBOLIC) != 0)
2278 setline(funcline, fcurrent);
2279 if (sc_alignnext)
2280 {
2281 alignframe(sc_dataalign);
2282 sc_alignnext = FALSE;
2283 } /* if */
2284 declared = 0; /* number of local cells */
2285 rettype = (sym->usage & uRETVALUE); /* set "return type" variable */
2286 curfunc = sym;
2287 define_args(); /* add the symbolic info for the function arguments */
2288 statement(NULL, FALSE);
2289 if ((rettype & uRETVALUE) != 0)
2290 sym->usage |= uRETVALUE;
2291 if (declared != 0)
2292 {
2293 /* This happens only in a very special (and useless) case, where a
2294 * function has only a single statement in its body (no compound
2295 * block) and that statement declares a new variable
2296 */
2297 modstk((int)declared * sizeof(cell)); /* remove all local
2298 * variables */
2299 declared = 0;
2300 } /* if */
2301 if ((lastst != tRETURN) && (lastst != tGOTO))
2302 {
2303 const1(0);
2304 ffret();
2305 if ((sym->usage & uRETVALUE) != 0)
2306 {
2307 char symname[2 * sNAMEMAX + 16]; /* allow space for user
2308 * defined operators */
2309 funcdisplayname(symname, sym->name);
2310 error(209, symname); /* function should return a value */
2311 } /* if */
2312 } /* if */
2313 endfunc();
2314 if (litidx)
2315 { /* if there are literals defined */
2316 glb_declared += litidx;
2317 begdseg(); /* flip to DATA segment */
2318 dumplits(); /* dump literal strings */
2319 litidx = 0;
2320 } /* if */
2321 testsymbols(&loctab, 0, TRUE, TRUE); /* test for unused arguments
2322 * and labels */
2323 delete_symbols(&loctab, 0, TRUE, TRUE); /* clear local variables
2324 * queue */
2325 assert(loctab.next == NULL);
2326 curfunc = NULL;
2327 if (sc_status == statSKIP)
2328 {
2329 sc_status = statWRITE;
2330 code_idx = cidx;
2331 glb_declared = glbdecl;
2332 } /* if */
2333 return TRUE;
2334}
2335
2336static int
2337argcompare(arginfo * a1, arginfo * a2)
2338{
2339 int result, level;
2340
2341 result = strcmp(a1->name, a2->name) == 0;
2342 if (result)
2343 result = a1->ident == a2->ident;
2344 if (result)
2345 result = a1->usage == a2->usage;
2346 if (result)
2347 result = a1->numtags == a2->numtags;
2348 if (result)
2349 {
2350 int i;
2351
2352 for (i = 0; i < a1->numtags && result; i++)
2353 result = a1->tags[i] == a2->tags[i];
2354 } /* if */
2355 if (result)
2356 result = a1->hasdefault == a2->hasdefault;
2357 if (a1->hasdefault)
2358 {
2359 if (a1->ident == iREFARRAY)
2360 {
2361 if (result)
2362 result = a1->defvalue.array.size == a2->defvalue.array.size;
2363 if (result)
2364 result =
2365 a1->defvalue.array.arraysize == a2->defvalue.array.arraysize;
2366 /* also check the dimensions of both arrays */
2367 if (result)
2368 result = a1->numdim == a2->numdim;
2369 for (level = 0; result && level < a1->numdim; level++)
2370 result = a1->dim[level] == a2->dim[level];
2371 /* ??? should also check contents of the default array
2372 * (these troubles go away in a 2-pass compiler that forbids
2373 * double declarations, but Small currently does not forbid them)
2374 */
2375 }
2376 else
2377 {
2378 if (result)
2379 {
2380 if ((a1->hasdefault & uSIZEOF) != 0
2381 || (a1->hasdefault & uTAGOF) != 0)
2382 result = a1->hasdefault == a2->hasdefault
2383 && strcmp(a1->defvalue.size.symname,
2384 a2->defvalue.size.symname) == 0
2385 && a1->defvalue.size.level == a2->defvalue.size.level;
2386 else
2387 result = a1->defvalue.val == a2->defvalue.val;
2388 } /* if */
2389 } /* if */
2390 if (result)
2391 result = a1->defvalue_tag == a2->defvalue_tag;
2392 } /* if */
2393 return result;
2394}
2395
2396/* declargs()
2397 *
2398 * This routine adds an entry in the local symbol table for each
2399 * argument found in the argument list.
2400 * It returns the number of arguments.
2401 */
2402static int
2403declargs(symbol * sym)
2404{
2405#define MAXTAGS 16
2406 char *ptr;
2407 int argcnt, oldargcnt, tok, tags[MAXTAGS], numtags;
2408 cell val;
2409 arginfo arg, *arglist;
2410 char name[sNAMEMAX + 1];
2411 int ident, fpublic, fconst;
2412 int idx;
2413
2414 /* if the function is already defined earlier, get the number of
2415 * arguments of the existing definition
2416 */
2417 oldargcnt = 0;
2418 if ((sym->usage & uPROTOTYPED) != 0)
2419 while (sym->dim.arglist[oldargcnt].ident != 0)
2420 oldargcnt++;
2421 argcnt = 0; /* zero aruments up to now */
2422 ident = iVARIABLE;
2423 numtags = 0;
2424 fconst = FALSE;
2425 fpublic = (sym->usage & uPUBLIC) != 0;
2426 /* the '(' parantheses has already been parsed */
2427 if (!matchtoken(')'))
2428 {
2429 do
2430 { /* there are arguments; process them */
2431 /* any legal name increases argument count (and stack offset) */
2432 tok = lex(&val, &ptr);
2433 switch (tok)
2434 {
2435 case 0:
2436 /* nothing */
2437 break;
2438 case '&':
2439 if (ident != iVARIABLE || numtags > 0)
2440 error(1, "-identifier-", "&");
2441 ident = iREFERENCE;
2442 break;
2443 case tCONST:
2444 if (ident != iVARIABLE || numtags > 0)
2445 error(1, "-identifier-", "const");
2446 fconst = TRUE;
2447 break;
2448 case tLABEL:
2449 if (numtags > 0)
2450 error(1, "-identifier-", "-tagname-");
2451 tags[0] = sc_addtag(ptr);
2452 numtags = 1;
2453 break;
2454 case '{':
2455 if (numtags > 0)
2456 error(1, "-identifier-", "-tagname-");
2457 numtags = 0;
2458 while (numtags < MAXTAGS)
2459 {
2460 if (!matchtoken('_') && !needtoken(tSYMBOL))
2461 break;
2462 tokeninfo(&val, &ptr);
2463 tags[numtags++] = sc_addtag(ptr);
2464 if (matchtoken('}'))
2465 break;
2466 needtoken(',');
2467 } /* for */
2468 needtoken(':');
2469 tok = tLABEL; /* for outer loop:
2470 * flag that we have seen a tagname */
2471 break;
2472 case tSYMBOL:
2473 if (argcnt >= sMAXARGS)
2474 error(45); /* too many function arguments */
2475 strcpy(name, ptr); /* save symbol name */
2476 if (name[0] == PUBLIC_CHAR)
2477 error(56, name); /* function arguments cannot be public */
2478 if (numtags == 0)
2479 tags[numtags++] = 0; /* default tag */
2480 /* Stack layout:
2481 * base + 0*sizeof(cell) == previous "base"
2482 * base + 1*sizeof(cell) == function return address
2483 * base + 2*sizeof(cell) == number of arguments
2484 * base + 3*sizeof(cell) == first argument of the function
2485 * So the offset of each argument is:
2486 * "(argcnt+3) * sizeof(cell)".
2487 */
2488 doarg(name, ident, (argcnt + 3) * sizeof(cell), tags, numtags,
2489 fpublic, fconst, &arg);
2490 if (fpublic && arg.hasdefault)
2491 error(59, name); /* arguments of a public function may not
2492 * have a default value */
2493 if ((sym->usage & uPROTOTYPED) == 0)
2494 {
2495 /* redimension the argument list, add the entry */
2496 sym->dim.arglist =
2497 (arginfo *) realloc(sym->dim.arglist,
2498 (argcnt + 2) * sizeof(arginfo));
2499 if (!sym->dim.arglist)
2500 error(103); /* insufficient memory */
2501 sym->dim.arglist[argcnt] = arg;
2502 sym->dim.arglist[argcnt + 1].ident = 0; /* keep the list
2503 * terminated */
2504 }
2505 else
2506 {
2507 /* check the argument with the earlier definition */
2508 if (argcnt > oldargcnt
2509 || !argcompare(&sym->dim.arglist[argcnt], &arg))
2510 error(25); /* function definition does not match prototype */
2511 /* may need to free default array argument and the tag list */
2512 if (arg.ident == iREFARRAY && arg.hasdefault)
2513 free(arg.defvalue.array.data);
2514 else if (arg.ident == iVARIABLE
2515 && ((arg.hasdefault & uSIZEOF) != 0
2516 || (arg.hasdefault & uTAGOF) != 0))
2517 free(arg.defvalue.size.symname);
2518 free(arg.tags);
2519 } /* if */
2520 argcnt++;
2521 ident = iVARIABLE;
2522 numtags = 0;
2523 fconst = FALSE;
2524 break;
2525 case tELLIPS:
2526 if (ident != iVARIABLE)
2527 error(10); /* illegal function or declaration */
2528 if (numtags == 0)
2529 tags[numtags++] = 0; /* default tag */
2530 if ((sym->usage & uPROTOTYPED) == 0)
2531 {
2532 /* redimension the argument list, add the entry iVARARGS */
2533 sym->dim.arglist =
2534 (arginfo *) realloc(sym->dim.arglist,
2535 (argcnt + 2) * sizeof(arginfo));
2536 if (!sym->dim.arglist)
2537 error(103); /* insufficient memory */
2538 sym->dim.arglist[argcnt + 1].ident = 0; /* keep the list
2539 * terminated */
2540 sym->dim.arglist[argcnt].ident = iVARARGS;
2541 sym->dim.arglist[argcnt].hasdefault = FALSE;
2542 sym->dim.arglist[argcnt].defvalue.val = 0;
2543 sym->dim.arglist[argcnt].defvalue_tag = 0;
2544 sym->dim.arglist[argcnt].numtags = numtags;
2545 sym->dim.arglist[argcnt].tags =
2546 (int *)malloc(numtags * sizeof tags[0]);
2547 if (!sym->dim.arglist[argcnt].tags)
2548 error(103); /* insufficient memory */
2549 memcpy(sym->dim.arglist[argcnt].tags, tags,
2550 numtags * sizeof tags[0]);
2551 }
2552 else
2553 {
2554 if (argcnt > oldargcnt
2555 || sym->dim.arglist[argcnt].ident != iVARARGS)
2556 error(25); /* function definition does not match prototype */
2557 } /* if */
2558 argcnt++;
2559 break;
2560 default:
2561 error(10); /* illegal function or declaration */
2562 } /* switch */
2563 }
2564 while (tok == '&' || tok == tLABEL || tok == tCONST || (tok != tELLIPS && matchtoken(','))); /* more? */
2565 /* if the next token is not ",", it should be ")" */
2566 needtoken(')');
2567 } /* if */
2568 /* resolve any "sizeof" arguments (now that all arguments are known) */
2569 assert(sym->dim.arglist != NULL);
2570 arglist = sym->dim.arglist;
2571 for (idx = 0; idx < argcnt && arglist[idx].ident != 0; idx++)
2572 {
2573 if ((arglist[idx].hasdefault & uSIZEOF) != 0
2574 || (arglist[idx].hasdefault & uTAGOF) != 0)
2575 {
2576 int altidx;
2577
2578 /* Find the argument with the name mentioned after the "sizeof".
2579 * Note that we cannot use findloc here because we need the
2580 * arginfo struct, not the symbol.
2581 */
2582 ptr = arglist[idx].defvalue.size.symname;
2583 for (altidx = 0;
2584 altidx < argcnt && strcmp(ptr, arglist[altidx].name) != 0;
2585 altidx++)
2586 /* nothing */ ;
2587 if (altidx >= argcnt)
2588 {
2589 error(17, ptr); /* undefined symbol */
2590 }
2591 else
2592 {
2593 /* check the level against the number of dimensions */
2594 /* the level must be zero for "tagof" values */
2595 assert(arglist[idx].defvalue.size.level == 0
2596 || (arglist[idx].hasdefault & uSIZEOF) != 0);
2597 if (arglist[idx].defvalue.size.level > 0
2598 && arglist[idx].defvalue.size.level >=
2599 arglist[altidx].numdim)
2600 error(28); /* invalid subscript */
2601 if (arglist[altidx].ident != iREFARRAY)
2602 {
2603 assert(arglist[altidx].ident == iVARIABLE
2604 || arglist[altidx].ident == iREFERENCE);
2605 error(223, ptr); /* redundant sizeof */
2606 } /* if */
2607 } /* if */
2608 } /* if */
2609 } /* for */
2610
2611 sym->usage |= uPROTOTYPED;
2612 errorset(sRESET); /* reset error flag (clear the "panic mode") */
2613 return argcnt;
2614}
2615
2616/* doarg - declare one argument type
2617 *
2618 * this routine is called from "declargs()" and adds an entry in the
2619 * local symbol table for one argument. "fpublic" indicates whether
2620 * the function for this argument list is public.
2621 * The arguments themselves are never public.
2622 */
2623static void
2624doarg(char *name, int ident, int offset, int tags[], int numtags,
2625 int fpublic, int fconst, arginfo * arg)
2626{
2627 symbol *argsym;
2628 cell size;
2629 int idxtag[sDIMEN_MAX];
2630
2631 strcpy(arg->name, name);
2632 arg->hasdefault = FALSE; /* preset (most common case) */
2633 arg->defvalue.val = 0; /* clear */
2634 arg->defvalue_tag = 0;
2635 arg->numdim = 0;
2636 if (matchtoken('['))
2637 {
2638 if (ident == iREFERENCE)
2639 error(67, name); /*illegal declaration ("&name[]" is unsupported) */
2640 do
2641 {
2642 if (arg->numdim == sDIMEN_MAX)
2643 {
2644 error(53); /* exceeding maximum number of dimensions */
2645 return;
2646 } /* if */
2647 /* there is no check for non-zero major dimensions here, only if
2648 * the array parameter has a default value, we enforce that all
2649 * array dimensions, except the last, are non-zero
2650 */
2651 size = needsub(&idxtag[arg->numdim]); /* may be zero here,
2652 *it is a pointer anyway */
2653#if INT_MAX < LONG_MAX
2654 if (size > INT_MAX)
2655 error(105); /* overflow, exceeding capacity */
2656#endif
2657 arg->dim[arg->numdim] = (int)size;
2658 arg->numdim += 1;
2659 }
2660 while (matchtoken('['));
2661 ident = iREFARRAY; /* "reference to array" (is a pointer) */
2662 if (matchtoken('='))
2663 {
2664 int level;
2665
2666 lexpush(); /* initials() needs the "=" token again */
2667 assert(numtags > 0);
2668 /* for the moment, when a default value is given for the array,
2669 * all dimension sizes, except the last, must be non-zero
2670 * (function initials() requires to know the major dimensions)
2671 */
2672 for (level = 0; level < arg->numdim - 1; level++)
2673 if (arg->dim[level] == 0)
2674 error(52); /* only last dimension may be variable length */
2675 initials(ident, tags[0], &size, arg->dim, arg->numdim);
2676 assert(size >= litidx);
2677 /* allocate memory to hold the initial values */
2678 arg->defvalue.array.data = (cell *) malloc(litidx * sizeof(cell));
2679 if (arg->defvalue.array.data)
2680 {
2681 int i;
2682
2683 memcpy(arg->defvalue.array.data, litq, litidx * sizeof(cell));