1 // UrForth/C standalone
2 // coded by Ketmar // Invisible Vector
19 #include <sys/types.h>
29 #include "liburforth/urforth.h"
32 #define UR_FORCE_INLINE static inline __attribute__((always_inline))
33 #define UR_INLINE static inline
41 #define MAYBE_UNUSED __attribute__((unused))
44 // ////////////////////////////////////////////////////////////////////////// //
46 static const char *ur_assert_failure (const char *cond
, const char *fname
, int fline
,
49 for (const char *t
= fname
; *t
; ++t
) {
51 if (*t
== '/' || *t
== '\\') fname
= t
+1;
53 if (*t
== '/') fname
= t
+1;
57 fprintf(stderr
, "\n%s:%d: Assertion in `%s` failed: %s\n", fname
, fline
, func
, cond
);
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 //==========================================================================
73 //==========================================================================
74 static void initUFEInclideDir (void) {
75 const char *id
= getenv("URASM_URFORTH_INCLUDE_DIR");
77 ufoIncludeDir
= strdup(id
);
80 memset(myDir
, 0, sizeof(myDir
));
82 if (readlink("/proc/self/exe", myDir
, sizeof(myDir
)-1) < 0) {
85 char *p
= (char *)strrchr(myDir
, '/');
86 if (!p
) strcpy(myDir
, "."); else *p
= '\0';
89 GetModuleFileName(GetModuleHandle(NULL
), myDir
, sizeof(myDir
)-1);
90 char *p
= strrchr(myDir
, '\\');
91 if (!p
) strcpy(myDir
, "."); else *p
= '\0';
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;
105 static char **g_argv
;
108 //==========================================================================
112 //==========================================================================
113 __attribute__((noreturn
))
114 void ufoFatalError (void) {
119 //==========================================================================
123 //==========================================================================
124 static char *strprintfVA (const char *fmt
, va_list vaorig
) {
129 if (buf
== NULL
) { fprintf(stderr
, "\nFATAL: out of memory!\n"); abort(); }
135 olen
= vsnprintf(buf
, len
, fmt
, 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(); }
147 //==========================================================================
151 //==========================================================================
152 static __attribute__((format(printf
,1,2))) char *strprintf (const char *fmt
, ...) {
156 buf
= strprintfVA(fmt
, va
);
162 //==========================================================================
166 // returns malloced string
168 //==========================================================================
169 static char *createIncludeName (const char *fname
, int assystem
, const char *lastIncPathUFO
) {
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
);
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"));
192 //fprintf(stderr, "inc: fname=<%s>; sys=%d; def=<%s>; res=<%s>\n", fname, assystem, defaultmain, res);
197 //==========================================================================
199 // ufoCreateIncludeName
201 //==========================================================================
202 char *ufoCreateIncludeName (const char *fname
, int assystem
, const char *lastIncPath
) {
204 fprintf(stderr
, "ICIN: fname=<%s>; lastinc=<%s>; assystem=%d\n",
205 fname
, lastIncPath
, assystem
);
207 if (lastIncPath
== NULL
&& assystem
) lastIncPath
= ufoIncludeDir
;
208 return createIncludeName(fname
, assystem
, lastIncPath
);
213 //==========================================================================
217 //==========================================================================
218 static void sigCtrlC (int sig
) {
224 //==========================================================================
228 //==========================================================================
229 static void ufcWord_N_BYE (uint32_t pfa
) {
230 uint32_t ec
= ufoPopData();
235 //==========================================================================
239 //==========================================================================
240 static void ufcWord_BYE (uint32_t pfa
) {
245 //==========================================================================
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 //==========================================================================
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;
270 if (rest
> 0 || idx
< rest
) {
271 const unsigned char *arg
= (const unsigned char *)(g_argv
[optind
+ (int)idx
]);
273 ufoPokeByte(addr
+ count
, *arg
);
274 count
+= 1u; arg
+= 1u;
277 ufoPokeCell(addr
- 4u, count
);
283 //==========================================================================
287 //==========================================================================
288 static void initUrForth (void) {
290 ufoCondDefine("SHITDOZE");
292 ufoCondDefine("NIX");
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 //==========================================================================
307 //==========================================================================
308 static void urcShutdown (void) {
310 if (ufoIncludeDir
) free(ufoIncludeDir
);
314 ///////////////////////////////////////////////////////////////////////////////
317 static struct option longOpts
[] = {
318 {"help", 0, NULL
, 'h'},
319 {"repl", 0, NULL
, 'R'},
320 {"test", 0, NULL
, 'T'},
325 //==========================================================================
329 //==========================================================================
330 static void usage (const char *pname
) {
332 "usage: %s [options] infile\n"
335 " -h --help this help\n"
340 //==========================================================================
344 //==========================================================================
345 int main (int argc
, char *argv
[]) {
347 const char *pname
= argv
[0];
350 ufoSetUserPostInit(&initUrForth
);
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) {
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;
369 signal(SIGINT
, &sigCtrlC
);
372 atexit(&urcShutdown
);
374 if (setjmp(errJP
) == 0) {
377 fprintf(stderr
, "FATAL: INITILIZATION FAILED!\n");
383 if (setjmp(errJP
) == 0) {
385 cfa
= ufoFindWordInVocabulary("UFO-RUN-REPL", ufoGetForthVocId());
387 fprintf(stderr
, "FATAL: REPL is not available.\n");
395 uint32_t cfa
= ufoFindWordInVocabulary("RUN-URASM", ufoGetForthVocId());
397 fprintf(stderr
, "FATAL: cannot find main URASM loop word.\n");
400 if (setjmp(errJP
) == 0) {
407 return (res
? 1 : 0);