/* * Copyright (c) 2026 Nakidai Perumenei * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #ifndef __THAC_H__ #define __THAC_H__ #define _POSIX_SOURCE #include enum { GENVARLEN = 16, }; typedef unsigned long ulong; typedef long long vlong; #define lengthof(X) (sizeof(X)/sizeof(*(X))) #define max(X, Y) ((X) > (Y) ? (X) : (Y)) #define min(X, Y) ((X) < (Y) ? (X) : (Y)) #define ENUMGEN(X) X, #define TOKTYPES(X) \ X(TEOF) \ X(TAMPER) /* & */ \ X(TAND) /* && */ \ X(TARRLEFT) /* <- */ \ X(TASSAMPER) /* &= */ \ X(TASSASTER) /* *= */ \ X(TASSCARET) /* ^= */ \ X(TASSIGN) /* = */ \ X(TASSLSHIFT) /* <<= */ \ X(TASSMINUS) /* -= */ \ X(TASSPERC) /* %= */ \ X(TASSPIPE) /* |= */ \ X(TASSPLUS) /* += */ \ X(TASSRSHIFT) /* >>= */ \ X(TASSSLASH) /* /= */ \ X(TASTER) /* * */ \ X(TCARET) /* ^ */ \ X(TCLBRACE) /* } */ \ X(TCLBRACK) /* ] */ \ X(TCLPAREN) /* ) */ \ X(TCOL) /* : */ \ X(TCOMMA) /* , */ \ X(TCONCAT) /* >< */ \ X(TDECR) /* -- */ \ X(TEQ) /* == */ \ X(TEXCLAM) /* ! */ \ X(TID) /* */ \ X(TINCR) /* ++ */ \ X(TKEYASSERT) /* assert */ \ X(TKEYBREAK) /* break */ \ X(TKEYCONT) /* continue */ \ X(TKEYELSE) /* else */ \ X(TKEYFOR) /* for */ \ X(TKEYFOREACH) /* foreach */ \ X(TKEYIF) /* if */ \ X(TKEYLEN) /* len */ \ X(TKEYMOD) /* mod */ \ X(TKEYNODE) /* node */ \ X(TKEYWITH) /* with */ \ X(TLESS) /* < */ \ X(TLESSEQ) /* <= */ \ X(TLSHIFT) /* << */ \ X(TMINUS) /* - */ \ X(TGREAT) /* > */ \ X(TGREATEQ) /* >= */ \ X(TNEQ) /* != */ \ X(TNUM) /* */ \ X(TOPBRACE) /* { */ \ X(TOPBRACK) /* [ */ \ X(TOPPAREN) /* ( */ \ X(TOR) /* || */ \ X(TPERC) /* % */ \ X(TPIPE) /* | */ \ X(TPLUS) /* + */ \ X(TPOW) /* ** */ \ X(TQUEST) /* ? */ \ X(TRSHIFT) /* >> */ \ X(TSEMICOL) /* ; */ \ X(TSLASH) /* / */ \ X(TTILDE) /* ~ */ \ /* TOKTYPES */ #define NODETYPES(X) \ X(NCOMP) /* compound statement */ \ X(NCOND) /* if statement */ \ X(NFOR) /* for statement */ \ X(NFOREACH) /* for statement */ \ X(NMOD) /* module expression */ \ X(NNUM) /* number */ \ X(NNODE) /* node expression */ \ X(NOPER) /* (unary (m) / binary (l r) / ternary (l m r)) operator */ \ X(NWITH) /* module invocation */ \ X(NVAR) /* variable reference */ \ X(NBREAK) /* break statement to exit the loop */ \ X(NCONT) /* continue statement to go to next loop iteration */ \ /* NODETYPES */ #define NOPERTYPES(X) \ X(OLEN) \ X(OASSERT) \ X(OCONNECT) \ X(OINDEX) \ X(OSLICE) \ X(OARRAY) \ X(OCONCAT) \ /* binary logic */ \ X(OBAND) \ X(OBOR) \ X(OBXOR) \ X(OLSHIFT) \ X(ORSHIFT) \ X(OINV) \ /* logic */ \ X(OAND) \ X(ONOT) \ X(OOR) \ X(OCOND) \ /* relations */ \ X(OEQ) \ X(ONEQ) \ X(OLESS) \ X(OLESSEQ) \ X(OGREAT) \ X(OGREATEQ) \ /* algebraic */ \ X(OPOSTDECR) \ X(OPOSTINCR) \ X(OPREDECR) \ X(OPREINCR) \ X(OSUM) \ X(OSUB) \ X(OMUL) \ X(ODIV) \ X(OMOD) \ X(OPOW) \ /* assignment */ \ X(OASSBAND) \ X(OASSMUL) \ X(OASSBXOR) \ X(OASSIGN) \ X(OASSLSHIFT) \ X(OASSSUB) \ X(OASSMOD) \ X(OASSBOR) \ X(OASSSUM) \ X(OASSRSHIFT) \ X(OASSDIV) \ /* NOPERTYPES */ #define VALTYPES(X) \ X(VNIL) \ X(VBREAK) \ X(VCONT) \ X(VNUM) \ X(VVAR) \ X(VARR) \ /* VALTYPES */ struct tok { enum tok_t {TOKTYPES(ENUMGEN)} type; struct tinfo { char *p; ulong len, cap; } info; }; struct node { enum node_t {NODETYPES(ENUMGEN)} type; union { struct ncomp { struct node **stmts; ulong len; } ncomp; struct ncond { struct node *cond, *t, *f; } ncond; struct nfor { struct node *before, *cond, *between, *code; } nfor; struct nforeach { struct node *obj, *code; } nforeach; struct nmod { struct node *code; char **params; ulong len; } nmod; vlong nnum; struct nnode { struct node **params; ulong len; } nnode; struct noper { enum noper_t {NOPERTYPES(ENUMGEN)} type; struct node *l, *m, *r; } noper; struct nwith { struct node *mod, **args, *code; ulong len; } nwith; char *nvar; }; }; struct val { enum val_t {VALTYPES(ENUMGEN)} type; union { char *name; /* VVAR */ vlong num; /* VNUM */ struct /* VARR; */ { struct val *arr; ulong len; }; }; }; struct scope { struct scope *parent; struct var { char *name; struct val val; } *vars; ulong len; }; struct vertex { struct { vlong *arr; ulong len; } props; struct { ulong *arr; ulong len; } nbrs; }; extern FILE *curfile; extern char *curname, *progname; extern ulong curline; extern struct scope basescope; extern struct tok curtok; extern struct val nil; void complain(int code, char *, ...); void say(char *, ...); void die(int code, char *, ...); void dieno(int code, char *, ...); enum tok_t gettok(void); void ungettok(void); #define exptok(...) _exptok(__VA_ARGS__, TEOF) int _exptok(enum tok_t, ...); struct node *getstmt(void); struct val eval(struct node *, struct scope *); /* * TODO: Probably current struct scope implementation is bad, * as because of it functions below require double pointer * and consequently overwrite it. Maybe a pure linked list? */ long findvar(char *, struct scope **); ulong assignvar(char *, struct val, struct scope **); int varnextchar(struct scope *); ulong varnextnum(struct scope *); void delvarscope(struct scope *, ulong); struct val deref(struct val, struct scope *); struct val getval(enum val_t, struct val, struct scope *, int); struct val copyval(struct val old); void freeval(struct val); struct val connectval(struct val, struct val, struct scope *); ulong mkvert(void); void addprop(ulong, vlong); void addedge(ulong, ulong); void showverts(void); void walkval(struct val *, ulong); void walknode(struct node *, ulong); void walkscope(struct scope *, ulong); char *tokname(enum tok_t); char *nodename(enum node_t); char *valname(enum val_t); char *nopername(enum noper_t); #endif /* __THAC_H__ */