asm: added "def<b|w|r>"; implemented "high()", "low()", "word()" functions
[urasm.git] / src / urasm-new.c
blobe44d815fbc355f4e44ed4224bd8355bb2522e6bc
1 // UrForth/C standalone
2 // coded by Ketmar // Invisible Vector
3 // GPLv3 ONLY
4 //
5 #ifndef _GNU_SOURCE
6 # define _GNU_SOURCE
7 #endif
9 #include <getopt.h>
10 #include <setjmp.h>
11 #include <stdarg.h>
12 #include <stddef.h>
13 #include <stdint.h>
14 #include <stdlib.h>
15 #include <stdio.h>
16 #include <string.h>
17 #include <unistd.h>
19 #include <sys/types.h>
20 #include <sys/stat.h>
21 #include <unistd.h>
23 #ifdef WIN32
24 # include <windows.h>
25 #else
26 # include <signal.h>
27 #endif
29 #include "liburforth/urforth.h"
32 #define UR_FORCE_INLINE static inline __attribute__((always_inline))
33 #define UR_INLINE static inline
36 #define VERSION_HI 2
37 #define VERSION_MID 0
38 #define VERSION_LO 1
41 #define MAYBE_UNUSED __attribute__((unused))
44 // ////////////////////////////////////////////////////////////////////////// //
45 __attribute((unused))
46 static const char *ur_assert_failure (const char *cond, const char *fname, int fline,
47 const char *func)
49 for (const char *t = fname; *t; ++t) {
50 #ifdef WIN32
51 if (*t == '/' || *t == '\\') fname = t+1;
52 #else
53 if (*t == '/') fname = t+1;
54 #endif
56 fflush(stdout);
57 fprintf(stderr, "\n%s:%d: Assertion in `%s` failed: %s\n", fname, fline, func, cond);
58 fflush(stderr);
59 abort();
62 #define ur_assert(cond_) do { if (__builtin_expect((!(cond_)), 0)) { ur_assert_failure(#cond_, __FILE__, __LINE__, __PRETTY_FUNCTION__); } } while (0)
65 // ////////////////////////////////////////////////////////////////////////// //
66 static char *ufoIncludeDir = NULL;
69 //==========================================================================
71 // initUFEInclideDir
73 //==========================================================================
74 static void initUFEInclideDir (void) {
75 const char *id = getenv("URASM_URFORTH_INCLUDE_DIR");
76 if (id && id[0]) {
77 ufoIncludeDir = strdup(id);
78 } else {
79 char myDir[4096];
80 memset(myDir, 0, sizeof(myDir));
81 #ifndef WIN32
82 if (readlink("/proc/self/exe", myDir, sizeof(myDir)-1) < 0) {
83 strcpy(myDir, ".");
84 } else {
85 char *p = (char *)strrchr(myDir, '/');
86 if (!p) strcpy(myDir, "."); else *p = '\0';
88 #else
89 GetModuleFileName(GetModuleHandle(NULL), myDir, sizeof(myDir)-1);
90 char *p = strrchr(myDir, '\\');
91 if (!p) strcpy(myDir, "."); else *p = '\0';
92 #endif
93 strcat(myDir, "/urflibs");
94 ur_assert(ufoIncludeDir == NULL);
95 ufoIncludeDir = strdup(myDir);
97 while (ufoIncludeDir[0] && ufoIncludeDir[strlen(ufoIncludeDir)-1] == '/') ufoIncludeDir[strlen(ufoIncludeDir)-1] = '\0';
98 if (!ufoIncludeDir[0]) strcpy(ufoIncludeDir, ".");
102 static jmp_buf errJP;
103 static int testparser = 0;
104 static int g_argc;
105 static char **g_argv;
108 //==========================================================================
110 // ufoFatalError
112 //==========================================================================
113 __attribute__((noreturn))
114 void ufoFatalError (void) {
115 longjmp(errJP, 666);
119 //==========================================================================
121 // strprintfVA
123 //==========================================================================
124 static char *strprintfVA (const char *fmt, va_list vaorig) {
125 char *buf = NULL;
126 int olen, len = 128;
128 buf = malloc(len);
129 if (buf == NULL) { fprintf(stderr, "\nFATAL: out of memory!\n"); abort(); }
130 for (;;) {
131 char *nb;
132 va_list va;
134 va_copy(va, vaorig);
135 olen = vsnprintf(buf, len, fmt, va);
136 va_end(va);
137 if (olen >= 0 && olen < len) return buf;
138 if (olen < 0) olen = len*2-1;
139 nb = realloc(buf, olen+1);
140 if (nb == NULL) { fprintf(stderr, "\nFATAL: out of memory!\n"); abort(); }
141 buf = nb;
142 len = olen+1;
147 //==========================================================================
149 // strprintf
151 //==========================================================================
152 static __attribute__((format(printf,1,2))) char *strprintf (const char *fmt, ...) {
153 char *buf = NULL;
154 va_list va;
155 va_start(va, fmt);
156 buf = strprintfVA(fmt, va);
157 va_end(va);
158 return buf;
162 //==========================================================================
164 // createIncludeName
166 // returns malloced string
168 //==========================================================================
169 static char *createIncludeName (const char *fname, int assystem, const char *lastIncPathUFO) {
170 struct stat st;
171 char *res;
173 if (!fname || !fname[0]) return NULL;
175 if (fname[0] != '/') {
176 const char *incdir = lastIncPathUFO;
177 if (assystem && (!incdir || !incdir[0])) incdir = ufoIncludeDir;
178 if (incdir == NULL || incdir[0] == 0) incdir = ".";
179 res = strprintf("%s/%s", incdir, fname);
180 } else {
181 res = strprintf("%s", fname);
184 if (stat(res, &st) == 0) {
185 if (S_ISDIR(st.st_mode)) {
186 char *rs = strprintf("%s/%s", res, (assystem ? "00-main-loader.f" : "zzmain.f"));
187 free(res);
188 res = rs;
192 //fprintf(stderr, "inc: fname=<%s>; sys=%d; def=<%s>; res=<%s>\n", fname, assystem, defaultmain, res);
193 return res;
197 //==========================================================================
199 // ufoCreateIncludeName
201 //==========================================================================
202 char *ufoCreateIncludeName (const char *fname, int assystem, const char *lastIncPath) {
203 #if 0
204 fprintf(stderr, "ICIN: fname=<%s>; lastinc=<%s>; assystem=%d\n",
205 fname, lastIncPath, assystem);
206 #endif
207 if (lastIncPath == NULL && assystem) lastIncPath = ufoIncludeDir;
208 return createIncludeName(fname, assystem, lastIncPath);
212 #ifndef WIN32
213 //==========================================================================
215 // sigCtrlC
217 //==========================================================================
218 static void sigCtrlC (int sig) {
219 ufoSetUserAbort();
221 #endif
224 //==========================================================================
226 // ufcWord_N_BYE
228 //==========================================================================
229 static void ufcWord_N_BYE (uint32_t pfa) {
230 uint32_t ec = ufoPopData();
231 exit((int)ec);
235 //==========================================================================
237 // ufcWord_BYE
239 //==========================================================================
240 static void ufcWord_BYE (uint32_t pfa) {
241 exit(0);
245 //==========================================================================
247 // ufcWord_ARGC
249 //==========================================================================
250 static void ufcWord_ARGC (uint32_t pfa) {
251 int rest = g_argc - optind;
252 if (rest <= 0) ufoPushData(0); else ufoPushData((uint32_t)rest);
256 //==========================================================================
258 // ufcWord_ARGV
260 // ARGV ( idx -- addr count )
261 // copy CLI arg to PAD+4, and set counter to PAD.
262 // 0 is first arg, not program name!
264 //==========================================================================
265 static void ufcWord_ARGV (uint32_t pfa) {
266 uint32_t idx = ufoPopData();
267 int rest = g_argc - optind;
268 const uint32_t addr = ufoGetPAD() + 4u;
269 uint32_t count = 0;
270 if (rest > 0 || idx < rest) {
271 const unsigned char *arg = (const unsigned char *)(g_argv[optind + (int)idx]);
272 while (*arg) {
273 ufoPokeByte(addr + count, *arg);
274 count += 1u; arg += 1u;
277 ufoPokeCell(addr - 4u, count);
278 ufoPushData(addr);
279 ufoPushData(count);
283 //==========================================================================
285 // initUrForth
287 //==========================================================================
288 static void initUrForth (void) {
289 #ifdef WIN32
290 ufoCondDefine("SHITDOZE");
291 #else
292 ufoCondDefine("NIX");
293 #endif
294 ufoCondDefine("URASM-NEW");
295 if (testparser) ufoCondDefine("TEST-PARSER");
296 ufoRegisterWord("N-BYE", &ufcWord_N_BYE, UFW_FLAG_PROTECTED);
297 ufoRegisterWord("BYE", &ufcWord_BYE, UFW_FLAG_PROTECTED);
298 ufoRegisterWord("ARGC", &ufcWord_ARGC, UFW_FLAG_PROTECTED);
299 ufoRegisterWord("ARGV", &ufcWord_ARGV, UFW_FLAG_PROTECTED);
303 //==========================================================================
305 // urcShutdown
307 //==========================================================================
308 static void urcShutdown (void) {
309 ufoDeinit();
310 if (ufoIncludeDir) free(ufoIncludeDir);
314 ///////////////////////////////////////////////////////////////////////////////
315 // options
317 static struct option longOpts[] = {
318 {"help", 0, NULL, 'h'},
319 {"repl", 0, NULL, 'R'},
320 {"test", 0, NULL, 'T'},
321 {NULL, 0, NULL, 0}
325 //==========================================================================
327 // usage
329 //==========================================================================
330 static void usage (const char *pname) {
331 printf(
332 "usage: %s [options] infile\n"
333 "\n"
334 "options:\n"
335 " -h --help this help\n"
336 , pname);
340 //==========================================================================
342 // main
344 //==========================================================================
345 int main (int argc, char *argv[]) {
346 int res = 0, c;
347 const char *pname = argv[0];
348 int dorepl = 0;
350 ufoSetUserPostInit(&initUrForth);
352 initUFEInclideDir();
354 printf("UrForth/C & UrAsm v%d.%d.%d, compile date: %s %s\n",
355 VERSION_HI, VERSION_MID, VERSION_LO, __DATE__, __TIME__);
356 while ((c = getopt_long(argc, argv, "h", longOpts, NULL)) >= 0) {
357 switch (c) {
358 case '?': return 1;
359 case 'h': usage(pname); res = 0; if (ufoIncludeDir) free(ufoIncludeDir); exit(0);
360 case 'R': dorepl = 1; break;
361 case 'T': testparser = 1; break;
365 g_argc = argc;
366 g_argv = argv;
368 #ifndef WIN32
369 signal(SIGINT, &sigCtrlC);
370 #endif
372 atexit(&urcShutdown);
374 if (setjmp(errJP) == 0) {
375 ufoInit();
376 } else {
377 fprintf(stderr, "FATAL: INITILIZATION FAILED!\n");
378 exit(1);
381 if (dorepl) {
382 for (;;) {
383 if (setjmp(errJP) == 0) {
384 uint32_t cfa;
385 cfa = ufoFindWordInVocabulary("UFO-RUN-REPL", ufoGetForthVocId());
386 if (cfa == 0) {
387 fprintf(stderr, "FATAL: REPL is not available.\n");
388 exit(1);
389 } else {
390 ufoRunWord(cfa);
394 } else {
395 uint32_t cfa = ufoFindWordInVocabulary("RUN-URASM", ufoGetForthVocId());
396 if (cfa == 0) {
397 fprintf(stderr, "FATAL: cannot find main URASM loop word.\n");
398 exit(1);
400 if (setjmp(errJP) == 0) {
401 ufoRunWord(cfa);
402 } else {
403 res = 1;
407 return (res ? 1 : 0);