DVX_GUI/src/apps/kpunch/dvxbasic/compiler/front.h
2026-10-12 14:19:24 -05:00

505 lines
26 KiB
C

// The MIT License (MIT)
//
// Copyright (C) 2026 Scott Duensing
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
// front.h -- DVX BASIC compiler internals shared by the front-end passes
//
// parse*.c tokens -> syntax tree of one unit (and the declaration pass)
// resolve*.c names -> symbols, built-ins, controls; semantic checks
// typecheck.c static types and implicit conversions
// fold.c constant folding (CONST values, literal subexpressions)
// gen*.c tree -> p-code
// compiler.c the driver: declaration pass, unit loop, module tables
//
// Embeddable: no DVX dependencies, pure C.
#ifndef DVXBASIC_FRONT_H
#define DVXBASIC_FRONT_H
#include "compiler.h"
#include "ast.h"
#include "scope.h"
#include "lexer.h"
#include "codegen.h"
#include "opcodes.h"
#include "../runtime/vm.h"
#include <stdbool.h>
#include <stdint.h>
// Error message sizes: the stored message ("Line N, Col M: text") and
// the text before the prefix is added.
#define BAS_COMPILE_ERROR_LEN 1024
#define BAS_ERROR_TEXT_LEN 512
// Letters DEFINT .. DEFSTR cover (A-Z), and a letter with no DEFxxx.
#define BAS_DEFTYPE_LETTERS ('Z' - 'A' + 1)
#define BAS_DEFTYPE_NONE 0xFF
// Recursion guards: nested expressions and blocks each cost a dozen C
// stack frames, and the DOS stack is small.
#define BAS_MAX_EXPR_DEPTH 64
#define BAS_MAX_BLOCK_DEPTH 32
// blockDepth while a top-level unit's own statement is parsed (a
// procedure must be one: its scope lives in the unit arena).
#define BAS_UNIT_BLOCK_DEPTH 1
// Longest TYPE field chain in a store target (a.b.c ...).
#define BAS_MAX_FIELD_CHAIN BAS_LAYOUT_MAX_DEPTH
// The member class of an object the source names directly (a control or
// a form, not an object variable): its methods take their arguments by
// value.
#define BAS_CLASS_HOST (-3)
// BASIC's TRUE as an integer.
#define BAS_TRUE_INT (-1)
// DEF FN function names start with FN.
#define BAS_DEFFN_PREFIX "FN"
// Form / PictureBox drawing methods with QBasic statement syntax, and
// the form methods a two-part name.Show / name.Hide statement means.
#define BAS_METHOD_CIRCLE "Circle"
#define BAS_METHOD_LINE "Line"
#define BAS_METHOD_PRINT "Print"
#define BAS_METHOD_PSET "PSet"
#define BAS_METHOD_SCALE "Scale"
#define BAS_METHOD_SHOW "Show"
#define BAS_METHOD_HIDE "Hide"
// A file-private name (Private CONST / ENUM outside class modules) is the
// name, this separator (no identifier holds it) and the file's number.
#define BAS_FILE_PRIVATE_SEP "|"
// basDeclareEnumName's file for a name every file sees.
#define BAS_FILE_PUBLIC (-1)
// Words the parser reads by their text (identifiers, not reserved).
#define BAS_KW_COMPARE "COMPARE"
#define BAS_KW_FRIEND "FRIEND"
#define BAS_KW_IMPLEMENTS "IMPLEMENTS"
#define BAS_KW_TEXT "TEXT"
// Built-ins the parser calls by these names (BasBuiltinT.name), which no
// identifier can spell: LIKE and ERROR are reserved words, a name holds
// no '.'.
#define BAS_BUILTIN_LIKE "LIKE"
#define BAS_BUILTIN_ERROR "ERROR"
#define BAS_BUILTIN_ERR_DESCRIPTION "ERR.DESCRIPTION"
#define BAS_BUILTIN_ERR_SOURCE "ERR.SOURCE"
// ARRAY(...), which the resolver builds itself (a program's own Array
// procedure or variable comes first).
#define BAS_ARRAY_FUNC "ARRAY"
// Err's members the parser reads by their text.
#define BAS_ERR_MEMBER_CLEAR "CLEAR"
#define BAS_ERR_MEMBER_DESCRIPTION "DESCRIPTION"
#define BAS_ERR_MEMBER_NUMBER "NUMBER"
#define BAS_ERR_MEMBER_RAISE "RAISE"
#define BAS_ERR_MEMBER_SOURCE "SOURCE"
// Arguments of the two-argument statements and built-ins (FILECOPY,
// NAME, SETATTR, SEEK, LIKE ...).
#define BAS_PAIR_ARGS 2
// ST_ONERROR's ival: ON ERROR RESUME NEXT (0: ON ERROR GOTO).
#define BAS_ON_ERROR_RESUME_NEXT 1
// ST_LABEL ival: a QBasic line number (its value in ival2), which ERL reports
#define BAS_LABEL_LINE_NUMBER 1
// MsgBox: the OK button only (vbOKOnly, the default flags).
#define BAS_MSGBOX_OK_ONLY 0x0000
// The error for a name after AS that is no type.
#define BAS_TYPE_EXPECTED "Expected type name (Integer, Long, Single, Double, String, Boolean, Date, Variant, Control, Form, Object, Collection, TYPE, ENUM or class name)"
// Types named by identifiers rather than reserved words.
#define BAS_DATE_TYPE_NAME "DATE"
#define BAS_BYTE_TYPE_NAME "BYTE"
#define BAS_CURRENCY_TYPE_NAME "CURRENCY"
#define BAS_VARIANT_TYPE_NAME "VARIANT"
#define BAS_COLLECTION_TYPE_NAME "COLLECTION"
// The Collection class as messages name it.
#define BAS_COLLECTION_DISPLAY_NAME "Collection"
// Built-in function flags.
#define BI_PURE 0x01 // result depends on the arguments alone: allowed in constant expressions
#define BI_FOLD 0x02 // folded in ordinary code when its arguments are literals
#define BI_OBJECT_ARG 0x04 // the first argument is an object (a bare control or form name is the object)
// The built-in function a statement may call too (CallByName obj, ...).
#define BAS_CALLBYNAME_NAME "CallByName"
// A built-in function (BasBuiltinT table in resolveExpr.c). An
// OP_BUILTIN entry names its BasBuiltinFnE in func and takes its argument
// counts from basBuiltinArity.
typedef struct {
const char *name;
uint8_t opcode;
uint8_t func;
uint8_t minArgs;
uint8_t maxArgs;
uint8_t resultType; // BAS_TYPE_* the result always has (BAS_NODE_TYPE_UNKNOWN: depends)
uint8_t flags; // BI_*
uint8_t nullMask; // arguments (BAS_NULL_ARG_*) whose Null makes the result Null: VB's Variant forms (Left, Mid ...); 0: none
const char *const *argNames; // VB's names of its arguments (Name:=value), NULL-terminated; NULL: none given by name
} BasBuiltinT;
// How an early-bound member is used (basBindMember).
typedef enum {
BAS_ACCESS_READ, // obj.name: its value (no argument list)
BAS_ACCESS_VALUE, // obj.name(args) in an expression
BAS_ACCESS_STATEMENT, // obj.name args / obj.name(args) as a statement
BAS_ACCESS_LET, // obj.name(args) = value
BAS_ACCESS_SET // Set obj.name(args) = value
} BasAccessE;
// How an unresolved name is being used (resolver).
typedef enum {
BAS_USE_VALUE, // its value
BAS_USE_OBJECT, // an object is expected (SET value, IS / TypeOf operand, object parameter)
BAS_USE_MEMBERBASE // name.member
} BasUseE;
// Deferred argument forms of the drawing methods (obj.Line ...), read
// once the resolver knows whether obj is a class instance.
typedef enum {
BAS_DEFER_ARGS, // comma-separated method arguments
BAS_DEFER_DRAWING // the method's QBasic statement syntax (Print items, Line / Circle / PSet blocks, Scale rectangle)
} BasDeferModeE;
// How an assignment stores (BasStmtT.ival2 of ST_ASSIGN).
typedef enum {
BAS_STORE_PLAIN, // the value replaces what the target holds
BAS_STORE_APPEND, // s = s + x / s = s & x on a STRING variable: x appended in place (OP_STR_APPEND); ival = the operator
BAS_STORE_RECORD // a TYPE value copied into the record the target holds (BAS_FN_RECORD_ASSIGN)
} BasStoreE;
// A change the resolver made to a symbol in the middle of a unit (see
// basSymChange): what it was before and after statement at.
typedef struct {
const BasNodeT *at;
BasSymT *sym;
uint32_t beforeFlags;
uint32_t afterFlags;
int32_t beforeUdtTypeId;
int32_t afterUdtTypeId;
uint8_t beforeType;
uint8_t afterType;
} BasSymChangeT;
// A loop or SELECT the generator is inside.
typedef struct {
int32_t *exitPatches; // stb_ds: EXIT jumps to land after the loop
int32_t selectBase; // SELECT depth at the loop's start (EXIT pops the ones opened since)
bool isFor; // FOR / FOR EACH (else DO / WHILE)
bool isForEach; // no VM FOR frame to drop on EXIT FOR
} BasGenLoopT;
struct BasCompilerS {
// Source and tokens
const char *source;
int32_t sourceLen;
BasLexerT lex;
int32_t prevLine; // line of the previous token (errors at the end of a line)
// First error
char error[BAS_COMPILE_ERROR_LEN];
bool hasError;
int32_t errorLine;
int32_t errorCol;
// Memory: module-lifetime data and the unit being compiled
BasArenaT modArena;
BasArenaT unitArena;
// Parser context (syntax only)
int32_t exprDepth;
int32_t blockDepth;
bool parseInClass; // between BEGINCLASS and ENDCLASS
bool parseInProc; // inside a SUB / FUNCTION / Property body
bool parseProcIsFunction; // ... a FUNCTION or Property Get (its name sets its result)
bool parseProcIsStatic; // ... declared STATIC (its DIMs declare STATIC variables)
bool parseInDeclareLib; // inside a DECLARE LIBRARY block (BINARY STRING allowed)
const char *parseProcName; // the procedure being parsed (its own name sets its result)
const char *parseClassName; // the class module being parsed (module arena; parseInClass)
BasWithT *parseWith; // the innermost WITH block being parsed (its '.name's)
// Symbols
BasScopeTabT moduleTab; // globals, procedures, constants, TYPE / ENUM / class names
BasScopeTabT moduleLabels;
BasScopeTabT formTab; // the current form's variables (inForm)
BasScopeTabT localTab; // the current procedure's parameters and locals (inProc)
BasScopeTabT localLabels;
BasTypeDefT **typeDefs; // stb_ds, indexed by TYPE id
BasClassDefT *classes; // stb_ds, indexed by class number
BasWithEventsDefT *withEvents; // stb_ds, binding number order
const char **formNames; // stb_ds, every BEGINFORM name (declaration pass)
BasSymT **moduleVars; // stb_ds, module / form / member variables in creation order (debug info)
BasMemberVarDeclT *memberVarDecls; // stb_ds, class member variables the declaration pass read (registered at its end)
BasMemberPatchT *memberPatches; // stb_ds, early-bound member operands to fill in at the end
// Scope state (resolver, in source order)
bool inForm;
bool inClass;
bool inProc;
bool inDefFn; // a DEF FN body: undeclared names are module variables
bool inConstExpr; // a constant expression: only constants may be named
const char *formName; // current form ("" outside)
int32_t fileIdx; // the project file being compiled (BEGINMODULE / BEGINFORM / BEGINCLASS block; 0 outside them): where a Private CONST / ENUM is seen
int32_t outerFileIdx; // fileIdx around the BEGINFORM / BEGINCLASS block being compiled (a class inside a project's module goes back to the module's)
int32_t fileCount; // file numbers given out so far
int32_t filePrivates; // file-private names declared (lookups try the file's own first while there are any)
int32_t classIdx; // current class (inClass)
BasSymT *curProc; // procedure being compiled (inProc)
const char *curProcName; // its name as written (its result is set by it)
uint8_t curProcKind; // its BasMemberKindE
bool curProcStatic; // it was declared STATIC: its implicit variables are STATIC
int32_t nextGlobalSlot;
int32_t nextFormSlot;
int32_t nextMemberSlot;
int32_t nextLocalSlot;
int32_t hiddenCount; // names of compiler variables
uint8_t defType[BAS_DEFTYPE_LETTERS];
int32_t optionBase;
bool optionExplicit;
bool compareText; // OPTION COMPARE TEXT (constant expressions)
// Resolver bookkeeping inside a procedure (or the module body)
int32_t forDepth;
int32_t doDepth;
int32_t selectDepth;
int32_t lastLabelDepth; // SELECT depth at the label defined last (RETURN pops the ones opened since)
int32_t savedForDepth; // the module body's bookkeeping while a procedure is compiled
int32_t savedDoDepth;
int32_t savedSelectDepth;
int32_t savedLabelDepth;
BasSymChangeT *symChanges; // stb_ds: the current unit's symbol changes, in source order
// Code generation
BasCodeGenT cg;
int32_t initJmpAddr; // JMP over a form / class set-up block (-1: none)
int32_t initCodeStart; // first byte of that block
int32_t procSkipJump; // JMP over the procedures defined since the last module code (-1: none)
int32_t *tempSlots; // stb_ds: compiler temporaries of the module code (global / form slots)
int32_t *procTempSlots; // stb_ds: compiler temporaries of the procedure being generated (local slots)
int32_t tempUsed; // temporaries the current statement holds
BasGenLoopT *loops; // stb_ds: open loops, innermost last
int32_t genSelectDepth; // SELECT test values on the eval stack
int32_t *exitProcPatches; // stb_ds: EXIT SUB / FUNCTION / PROPERTY jumps
int32_t debugProcCount; // procedures emitted (debugger procIndex)
BasVmT *constVm; // evaluates constant expressions (made on first use)
const BasCtrlValidatorT *validator;
};
// ============================================================
// Errors (compiler.c)
// ============================================================
// Records the first error at line / col (col 0: not known).
void basErrorAt(BasCompilerT *c, int32_t line, int32_t col, const char *fmt, ...);
// Records the first error at a node.
void basErrorNode(BasCompilerT *c, const BasNodeT *n, const char *fmt, ...);
// ============================================================
// Parser (parse.c, parseExpr.c, parseStmt.c, parseDecl.c)
// ============================================================
void basParseAdvance(BasCompilerT *c);
BasTokenTypeE basParseAfterParens(BasLexerT *lex);
BasNodeT *basParseArgList(BasCompilerT *c, int32_t *outArgc);
bool basParseAtEnd(BasCompilerT *c);
BasNodeT *basParseAttribute(BasCompilerT *c);
BasNodeT *basParseBareArgs(BasCompilerT *c, int32_t *outArgc);
BasNodeT *basParseBuiltinCall(BasCompilerT *c, const char *name, BasNodeT *args, int32_t argc, int32_t line, int32_t col);
BasNodeT *basParseChain(BasCompilerT *c, BasNodeT *base, bool statement);
bool basParseCheck(const BasCompilerT *c, BasTokenTypeE type);
bool basParseCheckWord(const BasCompilerT *c, const char *word);
BasNodeT *basParseCurLit(BasCompilerT *c, int64_t scaled);
void basParseDeclarations(BasCompilerT *c);
BasNodeT *basParseDeclStatement(BasCompilerT *c);
BasNodeT *basParseDeferredArgs(BasCompilerT *c, BasStmtT *call, BasDeferModeE mode, int32_t *outArgc);
void basParseError(BasCompilerT *c, const char *fmt, ...);
void basParseErrorExpected(BasCompilerT *c, const char *what);
BasNodeT *basParseEvent(BasCompilerT *c);
void basParseExpect(BasCompilerT *c, BasTokenTypeE type);
void basParseExpectEnd(BasCompilerT *c);
BasNodeT *basParseExpr(BasCompilerT *c);
bool basParseFriendAhead(const BasCompilerT *c);
BasNodeT *basParseFriendProc(BasCompilerT *c);
BasNodeT *basParseInputBoxArgs(BasCompilerT *c, int32_t *outArgc);
BasNodeT *basParseIntLit(BasCompilerT *c, int32_t value);
BasNodeT *basParseIntrinsic(BasCompilerT *c, uint8_t opcode, BasNodeT *args, int32_t argc, int32_t operand);
BasNodeT *basParseLValue(BasCompilerT *c, bool allowFields);
bool basParseMatch(BasCompilerT *c, BasTokenTypeE type);
bool basParseMatchEnd(BasCompilerT *c, BasTokenTypeE kw);
BasNodeT *basParseMsgBoxArgs(BasCompilerT *c, int32_t *outArgc);
bool basParseNameFollows(BasCompilerT *c, bool anyWord);
BasNodeT *basParseNode(BasCompilerT *c, int32_t size, uint8_t kind);
BasNodeT *basParseObjectOperand(BasCompilerT *c, BasNodeT *operand);
BasTokenTypeE basParsePeekAfterParens(const BasCompilerT *c);
BasProcT *basParseProcHeader(BasCompilerT *c, uint8_t memberKind, bool memberName);
void basParseSkipNewlines(BasCompilerT *c);
BasNodeT *basParseStatement(BasCompilerT *c);
BasNodeT *basParseStrLit(BasCompilerT *c, const char *text, int32_t len);
char *basParseTokenName(BasCompilerT *c);
BasNodeT *basParseUnit(BasCompilerT *c);
BasNodeT *basParseWithRef(BasCompilerT *c);
// ============================================================
// Resolver (resolve.c, resolveExpr.c)
// ============================================================
BasSymT *basAddGlobalVar(BasCompilerT *c, const char *name, uint8_t dataType);
BasSymT *basAddLocal(BasCompilerT *c, const char *name, uint8_t kind, uint8_t dataType);
BasSymT *basAddLocalVar(BasCompilerT *c, const char *name, uint8_t dataType);
BasSymT *basAddModuleVar(BasCompilerT *c, const char *name, uint8_t dataType);
BasNodeT *basBindMember(BasCompilerT *c, BasNodeT *obj, int32_t cls, const char *name, BasNodeT *args, int32_t argc, uint8_t access, const BasNodeT *at);
const BasBuiltinT *basBuiltinFind(const char *name);
int32_t basClassFind(BasCompilerT *c, const char *name);
bool basClassKnown(int32_t cls);
void basCloseProcScope(BasCompilerT *c);
BasNodeT *basControlNode(BasCompilerT *c, const char *name, const BasNodeT *at);
bool basConvertsArg(uint8_t dataType, uint8_t paramFlags);
void basDeclareClass(BasCompilerT *c, const char *name);
uint8_t basDeclaredStoreType(const BasSymT *sym);
void basDeclareEnumName(BasCompilerT *c, const char *name, int32_t privateFile);
void basDeclareForm(BasCompilerT *c, const char *name);
void basDeclareLibrary(BasCompilerT *c, const BasStmtT *s);
void basDeclareMemberVars(BasCompilerT *c, const BasStmtT *dim, int32_t classIdx);
void basDeclareMemberVarsEnd(BasCompilerT *c);
void basDeclareProc(BasCompilerT *c, BasProcT *proc, int32_t classIdx);
void basDeclareTypeName(BasCompilerT *c, const char *name);
void basDeclareUserControlVar(BasCompilerT *c, int32_t classIdx);
BasSymT *basEnsureVariable(BasCompilerT *c, const char *name, const BasNodeT *at);
int32_t basExprClass(const BasCompilerT *c, const BasNodeT *n);
int32_t basExprUdtType(const BasCompilerT *c, const BasNodeT *n);
int32_t basFieldIndex(const BasTypeDefT *td, const char *name);
bool basFilePrivateName(const BasCompilerT *c, const char *name, int32_t fileIdx, char *out, int32_t outSize);
uint8_t basImplicitType(const BasCompilerT *c, const char *name, bool *outTyped);
bool basIsDefFnName(const char *name);
bool basIsFormName(const BasCompilerT *c, const char *name);
bool basLateArgs(BasCompilerT *c, BasCallT *call, BasNodeT *args, int32_t argc, bool byRef);
BasNodeT *basLoadFormNode(BasCompilerT *c, const char *name, const BasNodeT *at);
BasSymT *basLookup(BasCompilerT *c, const char *name);
BasSymT *basLookupModuleVar(BasCompilerT *c, const char *name);
BasSymT *basLookupProc(BasCompilerT *c, const char *name);
BasSymT *basModuleFind(const BasCompilerT *c, const char *name);
BasNodeT *basNamedArgs(BasCompilerT *c, const char *const *names, int32_t count, BasNodeT *args, const BasNodeT *at);
BasNodeT *basNodeConst(BasCompilerT *c, const BasConstValT *v, const BasNodeT *at);
BasNodeT *basNodeConv(BasCompilerT *c, BasNodeT *a, uint8_t op, int32_t aux);
BasNodeT *basNodeCur(BasCompilerT *c, int64_t scaled, const BasNodeT *at);
BasNodeT *basNodeInt(BasCompilerT *c, int32_t value, uint8_t type, const BasNodeT *at);
BasNodeT *basNodeIntrinsic(BasCompilerT *c, uint8_t opcode, BasNodeT *args, int32_t argc, int32_t operand, int32_t line, int32_t col);
BasNodeT *basNodeSpecial(BasCompilerT *c, int32_t kind, const BasNodeT *at);
BasNodeT *basNodeStr(BasCompilerT *c, const char *text, int32_t len, const BasNodeT *at);
BasNodeT *basNodeVar(BasCompilerT *c, BasSymT *sym, const BasNodeT *at);
BasNodeT *basNodeZero(BasCompilerT *c, uint8_t dataType, const BasNodeT *at);
BasSymT *basPropertyProc(BasCompilerT *c, const char *name, bool isSet);
bool basQualify(const BasCompilerT *c, int32_t classIdx, const char *name, char *out, int32_t outSize);
bool basRejectHiddenModuleVar(BasCompilerT *c, const char *name, const BasNodeT *at);
BasNodeT *basResolveArg(BasCompilerT *c, BasNodeT *arg, bool byRef, uint8_t *outRefType);
void basResolveBody(BasCompilerT *c, BasNodeT *list);
BasNodeT *basResolveCallee(BasCompilerT *c, BasCallT *call, bool statement);
void basResolveDefType(BasCompilerT *c, const BasStmtT *s);
BasNodeT *basResolveExpr(BasCompilerT *c, BasNodeT *n, uint8_t use);
BasNodeT *basResolveLValue(BasCompilerT *c, BasNodeT *n, bool allowFields);
BasNodeT *basResolveMemberParts(BasCompilerT *c, BasMemberT *m, bool isProp, BasNodeT **outObj, int32_t *outClass);
BasNodeT *basResolveMethodArgs(BasCompilerT *c, BasNodeT *args, int32_t argc, bool byRef);
void basResolveModuleEnd(BasCompilerT *c);
BasNodeT *basResolveObjectMember(BasCompilerT *c, BasNodeT *obj, const char *name, int32_t memberClass, uint16_t flags, const BasNodeT *at);
BasNodeT *basResolveProcArgs(BasCompilerT *c, const BasSymT *sym, BasNodeT *args, int32_t valueParams, const BasNodeT *at, int32_t *outArgc);
void basResolveStatement(BasCompilerT *c, BasNodeT *s);
bool basResolveTypeSpec(BasCompilerT *c, const BasTypeSpecT *t, bool prescan, uint8_t *outType, int32_t *outUdt, int32_t *outClass);
void basResolveUnit(BasCompilerT *c, BasNodeT *unit);
void basResolveUnitEnd(BasCompilerT *c, BasNodeT *unit);
BasSymT *basStaticVariable(BasCompilerT *c, const char *name, uint8_t dataType, bool isTyped, int32_t objClass, int32_t fixedLen, const BasNodeT *at, BasSymT **outSlot);
BasScopeE basStorageScope(const BasSymT *sym);
void basSymChange(BasCompilerT *c, BasSymT *sym, const BasNodeT *at, uint8_t dataType, int32_t udtTypeId, uint32_t flags);
void basSymChangesUndo(BasCompilerT *c);
BasNodeT *basTypedArg(BasCompilerT *c, const char *procName, int32_t idx, uint8_t dataType, bool byVal, BasNodeT *arg);
BasSymT *basUserControlProc(const BasCompilerT *c, int32_t classIdx, int32_t evt);
bool basValidateCtrlMember(BasCompilerT *c, const char *ctrlName, const char *member, bool isProp, const BasNodeT *at);
BasNodeT *basWithObject(BasCompilerT *c, const BasNodeT *ref);
// ============================================================
// Types and folding (typecheck.c, fold.c)
// ============================================================
bool basConstConvert(BasCompilerT *c, BasConstValT *v, uint8_t asType, const char *what, const BasNodeT *at);
bool basFoldConstExpr(BasCompilerT *c, BasNodeT *expr, BasConstValT *out);
BasNodeT *basFoldConv(BasCompilerT *c, BasNodeT *value, uint8_t op);
BasNodeT *basFoldExpr(BasCompilerT *c, BasNodeT *n);
bool basStartsTyped(uint8_t dataType);
uint8_t basStaticType(const BasNodeT *n);
void basTypeUnit(BasCompilerT *c, BasNodeT *unit);
// ============================================================
// Generator (gen.c, genExpr.c, genStmt.c)
// ============================================================
uint8_t basBinaryOpcode(uint8_t tok);
void basGenAddrOf(BasCompilerT *c, const BasSymT *sym);
void basGenArgs(BasCompilerT *c, const BasNodeT *list);
void basGenBody(BasCompilerT *c, const BasNodeT *list);
void basGenCall(BasCompilerT *c, BasSymT *sym, int32_t argc);
void basGenDeclaration(BasCompilerT *c, const BasNodeT *s);
void basGenExpr(BasCompilerT *c, const BasNodeT *n);
void basGenFlushProcSkip(BasCompilerT *c);
int32_t basGenJump(BasCompilerT *c, uint8_t op);
void basGenJumpTo(BasCompilerT *c, uint8_t op, int32_t target);
void basGenLine(BasCompilerT *c, const BasNodeT *s);
void basGenLoadTemp(BasCompilerT *c, int32_t slot);
void basGenLoadVar(BasCompilerT *c, const BasSymT *sym);
void basGenNew(BasCompilerT *c, const char *name, int32_t objClass);
void basGenObjMember(BasCompilerT *c, uint8_t op, const BasCallT *call);
void basGenPatchHere(BasCompilerT *c, int32_t operandPos);
void basGenPushCStr(BasCompilerT *c, const char *text);
void basGenPushInt16(BasCompilerT *c, int16_t v);
void basGenPushSpecial(BasCompilerT *c, uint8_t kind);
void basGenPushStr(BasCompilerT *c, const char *text, int32_t len);
void basGenRef(BasCompilerT *c, const BasNodeT *n);
void basGenSlotRef(BasCompilerT *c, int32_t scope, int32_t slot, uint8_t storeType);
void basGenStatement(BasCompilerT *c, const BasNodeT *s);
void basGenStore(BasCompilerT *c, const BasSymT *sym);
void basGenStoreConv(BasCompilerT *c, uint8_t dataType);
void basGenStoreFrom(BasCompilerT *c, const BasSymT *sym, uint8_t valueType);
void basGenStoreRaw(BasCompilerT *c, const BasSymT *sym);
void basGenStoreSlot(BasCompilerT *c, int32_t scope, int32_t slot, uint8_t conv);
void basGenStoreTemp(BasCompilerT *c, int32_t slot);
uint8_t basGenStoreValue(BasCompilerT *c, const BasNodeT *value, uint8_t convType, int32_t fixedLen, int32_t objClass, bool isSet, bool deferConv);
void basGenSymChanges(BasCompilerT *c, const BasNodeT *at);
int32_t basGenTemp(BasCompilerT *c);
void basGenTempRef(BasCompilerT *c);
void basGenTempReset(BasCompilerT *c);
bool basGenUdtLayout(BasCompilerT *c, int32_t typeId);
bool basGenUdtSpec(BasCompilerT *c, int32_t typeId);
#endif // DVXBASIC_FRONT_H