Compare commits

...

36 Commits

Author SHA1 Message Date
6e1129cb6b Debug information improvements 2023-12-08 03:56:09 +00:00
dc4d4aba24 Fix parser goof 2023-12-08 03:44:42 +00:00
c11e0792f4 Minor fixes for the linux assembler 2023-12-08 03:13:22 +00:00
84c5c9f4f2 Dump Everything. 2023-12-08 03:12:09 +00:00
5f014fed8b Fixes for windows again. 2023-12-08 03:01:56 +00:00
cdd8e017e2 Fix assigning local definitions. 2023-12-07 22:42:25 +00:00
29b797d7dc Refactor codegen, allow compiling for linux 2023-12-06 19:01:20 +00:00
bfebf647eb Optionally search relative to the current source file to find headers. 2023-12-06 18:26:10 +00:00
bc787c3adb Wire in enhanced error handling to all crash situations 2023-04-25 00:06:35 +01:00
0f77480d5b Refactor to allow inline initialization of arrays. 2023-04-24 22:26:54 +01:00
e42a2cfd8d Refactor to allow inline initialization of variables. 2023-04-24 20:41:49 +01:00
96f6773904 Allow omission of braces on multiple-statement switch cases. 2023-04-24 03:57:58 +01:00
4e47cdcaf6 Add switch statement, case and default handling, wire in the error handler for a sample program 2023-04-24 03:03:31 +01:00
70ae06af44 Add useful error handler 2023-04-24 02:17:11 +01:00
09af190aa9 Fix rsp not being escaped properly in the Win32 GAS ASM generator 2023-04-23 19:20:09 +01:00
4d5fd36390 Fix not consuming semicolon on most operations 2023-04-23 18:56:35 +01:00
216d6c6b5e Refactor to generalise assembler output 2023-04-23 17:32:02 +01:00
39756f4e89 Small fixes to assembly output 2022-03-06 02:28:42 +00:00
734bc049e7 Allow single statements in bodies of if, else, while and for 2022-03-06 01:52:37 +00:00
334b02cd76 Fix break & continue implementation 2022-03-06 01:15:07 +00:00
0454c38a7e Add extra output files to gitignore. 2022-03-05 23:42:15 +00:00
b7f8d8666e Implement break/continue statements. 2022-03-05 23:42:01 +00:00
4e62bbdc51 Finish the Import mechanism, plus some bug fixes 2022-03-05 02:05:18 +00:00
2c27f2eb40 Assign source files their actual locations 2022-03-05 01:22:54 +00:00
37cdaacc71 Begin refactor for multiplexed compilation 2022-03-05 01:13:45 +00:00
f2d2d07709 Create import test files 2022-03-04 15:55:08 +00:00
2c87817904 Implement alias - a faster typedef 2022-03-04 02:31:16 +00:00
628c7a3a13 Implement enums and the foundation of a type alias system 2022-03-04 01:11:04 +00:00
3717b310be Implement unions and largest-element allocation 2022-03-03 02:44:07 +00:00
537246daae CLion reformatting pass, finish struct implementation 2022-03-03 00:05:10 +00:00
ac8c0ed9c7 Add struct tests. 2021-07-05 00:07:55 +01:00
8e45ea5eef Implement (broken) struct member access 2021-07-05 00:07:04 +01:00
2bdbe6e6c0
Fixes to parsing and function pointers. It's a hack but it... works? kinda? 2021-03-15 15:59:15 +00:00
d848425701
Working on functions, symbols, and toward a GL hello world. 2021-03-15 01:22:47 +00:00
f766d02467
Move to the BS toolcahin 2021-03-12 23:48:06 +00:00
8263fb853b
Fixes to struct parsing 2021-02-22 17:43:06 +00:00
69 changed files with 6257 additions and 1414 deletions

8
.gitignore vendored
View File

@ -1,6 +1,14 @@
.idea
.vscode
.cache
out
bin
build
Erythro
test
cmake-build-debug
*.s
*.o

26
CMakeLists.txt Normal file
View File

@ -0,0 +1,26 @@
cmake_minimum_required(VERSION 3.21)
project(Erythro C)
set(CMAKE_C_STANDARD 11)
include_directories(include)
add_executable(Erythro
include/Data.h
include/Defs.h
src/assemble/AssemblerDispatcher.c
src/assemble/Win32GASAssembler.c
src/assemble/LinuxGASAssembler.c
src/assemble/JVMAssembler.c
src/assemble/QBEAssembler.c
src/Delegate.c
src/Dump.c
src/Lexer.c
src/Main.c
src/Parser.c
src/Pointers.c
src/Statements.c
src/Symbols.c
src/Types.c
src/Importer.c
src/Errors.c)

20
build.json Normal file
View File

@ -0,0 +1,20 @@
{
"name": "Erythro",
"author": "Curle",
"source": {
"src": [
"$root/src/*.c"
],
"inc": [
"$root/include/"
]
},
"build": {
"compile": [
"-g -I$inc",
"$src"
]
}
}

View File

@ -4,6 +4,7 @@
/*************/
#pragma once
#include <stdio.h>
#include <Defs.h>
#include <stdbool.h>
@ -13,40 +14,53 @@
#endif
#define TEXTLEN 512
#define SYMBOLS 1024
extern_ struct SymbolTableEntry* Globals, *GlobalsEnd;
extern_ struct SymbolTableEntry* Locals, *LocalsEnd;
extern_ struct SymbolTableEntry* Params, *ParamsEnd;
extern_ struct SymbolTableEntry* Structs, *StructsEnd;
extern_ struct SymbolTableEntry* StructMembers, *StructMembersEnd;
extern_ struct SymbolTableEntry* Unions, *UnionsEnd;
extern_ struct SymbolTableEntry* Enums, *EnumsEnd;
extern_ bool OptDumpTree;
extern_ bool OptKeepAssembly;
extern_ bool OptAssembleFiles;
extern_ bool OptLinkFiles;
extern_ bool OptVerboseOutput;
extern_ char* OutputFileName;
extern_ char* CurrentASMFile, *CurrentObjectFile;
extern_ int TypeSizes[5];
extern_ char* TokenNames[];
extern_ int CurrentFunction;
extern_ struct SymbolTableEntry* FunctionEntry;
extern_ int Line;
extern_ int Overread;
extern_ FILE* SourceFile;
// All currently open source files.
extern_ struct FileData** Files;
// The source file currently being operated on.
extern_ struct FileData* CurrentFile;
// The file we are writing into; CurrentFile -> OutputFile
extern_ FILE* OutputFile;
extern_ struct Token CurrentToken;
// Symbol tables.
extern_ struct SymbolTableEntry* Globals, * GlobalsEnd;
extern_ struct SymbolTableEntry* Locals, * LocalsEnd;
extern_ struct SymbolTableEntry* Params, * ParamsEnd;
extern_ struct SymbolTableEntry* Structs, * StructsEnd;
extern_ struct SymbolTableEntry* CompositeMembers, * CompositeMembersEnd;
extern_ struct SymbolTableEntry* EnumMembers, * EnumMembersEnd;
extern_ struct SymbolTableEntry* Unions, * UnionsEnd;
extern_ struct SymbolTableEntry* Enums, * EnumsEnd;
extern_ struct SymbolTableEntry* Types, * TypesEnd;
// Whether we should dump the syntax tree before starting to assemble the file.
extern_ bool OptDumpTree;
// Whether we should keep the assembly files after successfully linking.
extern_ bool OptKeepAssembly;
// Whether to stop at compilation and dumping - skip assembly and binary creation altogether.
extern_ bool OptAssembleFiles;
// Whether to stop at assembly - skip linking into a binary.
extern_ bool OptLinkFiles;
// Whether to output extended debugging information.
extern_ bool OptVerboseOutput;
// The name of the binary we want to create.
extern_ char* OutputFileName;
// The sizes of each of the core types, in bytes.
extern_ int TypeSizes[5];
// The name of the Assembler Module that we should use.
extern_ char* OptAssemblerName;
// The Assembler Module to call to when performing generation operations.
extern_ struct AssemblerModule* Assembler;
// The names of each token in the language, synchronized to the TokenTypes enum.
extern_ char* TokenNames[];
extern_ char* OperationNames[];
// The names of the storage scopes.
extern_ char* ScopeNames[];
extern_ int Overread;
extern_ char CurrentIdentifier[TEXTLEN + 1];
extern_ int CurrentGlobal;
extern_ int CurrentLocal;

View File

@ -4,12 +4,14 @@
/*************/
#pragma once
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <string.h>
#include <stdbool.h>
/*
* ARithmetic tokens are prefixed AR.
* LIteral tokens are prefixed LI.
@ -66,6 +68,7 @@ enum TokenTypes {
LI_INT, // Integer literal
LI_STR, // String literal
LI_SEMIC, // ;
LI_COLON, // :
LI_LBRAC, // {
LI_RBRAC, // }
@ -77,6 +80,8 @@ enum TokenTypes {
LI_RPARE, // )
LI_COM, // ,
LI_DOT, // .
LI_ARROW, // ->
TY_IDENTIFIER, // Identifier name. Variable, function, etc.
TY_NONE, // No return type. Literal void.
@ -86,14 +91,25 @@ enum TokenTypes {
TY_VOID, // "void" type keyword
KW_FUNC, // :: function name incoming
KW_BREAK, // "break" keyword
KW_CONTINUE, // "continue" keyword
KW_SWITCH, // "switch" keyword
KW_DEFAULT, // "default" keyword
KW_CASE, // "case" keyword
KW_PRINT,
KW_IF,
KW_ELSE,
KW_WHILE,
KW_FOR,
KW_RETURN,
KW_STRUCT
KW_STRUCT,
KW_UNION,
KW_ENUM,
KW_ALIAS,
KW_IMPORT
};
/*
@ -107,6 +123,9 @@ enum TokenTypes {
*
* It is important that Tokens and Operations are logically separated,
* but that the Operation's index is the same as the Token that invokes it.
*
* Every five elements, an index is assigned. These are the natural indices.
* They are marked to make navigation of the Syntax Tree easier.
*/
enum SyntaxOps {
@ -115,40 +134,40 @@ enum SyntaxOps {
OP_BOOLOR, // Boolean OR two statements
OP_BOOLAND, // Boolean AND two statements
OP_BITOR, // Bitwise OR a number
OP_BITXOR, // Bitwise XOR a number
OP_BITXOR = 5, // Bitwise XOR a number
OP_BITAND, // Bitwise AND a number
OP_EQUAL, // Compare equality
OP_INEQ, // Compare inequality
OP_LESS, // Less than?
OP_GREAT, // Greater than?
OP_GREAT = 10, // Greater than?
OP_LESSE, // Less than or Equal to?
OP_GREATE, // Greater than or Equal to?
OP_SHIFTL, // Arithmetic Shift Left (Multiply by 2)
OP_SHIFTR, // Arithmetic Shift Right (Divide by 2)
OP_ADD, // Add two numbers.
OP_ADD = 15, // Add two numbers.
OP_SUBTRACT, // Subtract two numbers.
OP_MULTIPLY, // Multiply two numbers.
OP_DIVIDE, // Divide two numbers.
OP_PREINC, // Increment var before reference.
OP_PREDEC, // Decrement var before reference.
OP_PREDEC = 20, // Decrement var before reference.
OP_POSTINC, // Increment var after reference.
OP_POSTDEC, // Decrement var after reference.
OP_BITNOT, // Invert a number bitwise
OP_BOOLNOT, // Invert a statement logically
OP_NEGATE, // Negate a number (turn a positive number negative)
OP_NEGATE = 25, // Negate a number (turn a positive number negative)
OP_BOOLCONV, // Convert an expression to a boolean.s
OP_ADDRESS, // Fetch the address of a var
OP_DEREF, // Get the value of the address in a pointer
TERM_INTLITERAL, // Integer Literal. This is a virtual operation, so it's a terminal.
TERM_STRLITERAL, // String Literal. Also terminal.
TERM_STRLITERAL = 30, // String Literal. Also terminal.
REF_IDENT, // Reference (read) an identifier (variable).
@ -156,18 +175,34 @@ enum SyntaxOps {
OP_SCALE, // We have a pointer that needs to be scaled!
OP_CALL, // Call a function
OP_RET, // Return from a function
OP_RET = 35, // Return from a function
OP_COMP, // Compound statements need a way to be "glued" together. This is one of those mechanisms
OP_IF, // If statement
OP_LOOP, // FOR, WHILE
OP_PRINT, // Print statement
OP_FUNC, // Define a function
OP_FUNC = 40, // Define a function
OP_BREAK, // Break out of the loop
OP_CONTINUE, // Continue the loop
OP_SWITCH, // Switch statement
OP_DEFAULT, // Default case
OP_CASE = 45 // Case
};
// A node in a Binary Tree that forms the syntax of Erythro
/**
* The way syntax is stored by the parser and assembled into a usable file.
* An ASTNode forms an item in a linked list.
*
* Thus, you can traverse up and down a tree of ASTNodes easily.
*
* Walking the tree is as simple as reading the Operation and recursively reading the Left, Middle and Right nodes as called for.
* For example, an if-else statement uses all three subnodes.
*
* This means that AST Nodes aren't exactly a binary tree, but a syntax tree nonetheless.
*/
struct ASTNode {
int Operation; // SyntaxOps Index
int ExprType; // Value->IntValue's DataType
@ -182,6 +217,12 @@ struct ASTNode {
};
};
/**
* Describes the basic unit of syntax in the language.
* A token has a type (an index into the TokenTypes enum) and a value.
*
* The value represents the numerical value of an integer literal, etc.
*/
struct Token {
int type;
int value;
@ -198,31 +239,81 @@ struct SymbolTableEntry {
struct SymbolTableEntry* CompositeType; // A pointer to the start of a Symbol Table list that represents a certain Composite type
int Structure; // An entry in StructureType - metadata on how to process the data
int Storage; // The scope of this symbol - decides when it is discarded.
union {
int EndLabel; // For a function - The number of the label to jump to, in order to exit this function (if applicable)
int Length; // For an array - The length of the symbol in units of 1 element -- the size of an array, for example.
int IntValue; // For an enum - The value of an Enum entry
};
int Length; // Size of an array, or the number of parameters in a function
int Size; // Total size in bytes.
int* InitialValues;
int IntValue; // For an enum - The value of an Enum entry
union {
int EndLabel; // For a function - The number of the label to jump to, in order to exit this function (if applicable)
int SinkOffset; // For a variable - How many times must we sink the rbp to get to this symbol in the stack?
int Elements; // For a function - How many parameters?
};
struct SymbolTableEntry* NextSymbol; // The next symbol in a list
struct SymbolTableEntry* Start; // The first member in a list
};
/**
* Information about a given source file.
*
* A file that starts the parsing of another file will never confuse the parser.
*
* It is the end goal that the parser will be multithreaded, operating on a single file at a time.
*
* Note that files do not contain their own symbol tables - these are global.
*/
struct FileData {
// Whether or not this file will accept definitions of functions.
bool AllowDefinitions;
// A FILE stream that we can read the file from.
FILE* Stream;
// The filename of the source code
char* SourceName;
// The filename of the assembly output
char* AssemblyName;
// The filename of the assembled object code
char* ObjectName;
// The line of the file we are currently working on, -1 if it is finished
long CurrentLine;
// The column of the file we are currently working on, -1 if it is finished
long CurrentColumn;
// The depth of the loop currently being parsed.
long CurrentLoopDepth;
// The column that was last marked as "valid", the start of the error block if something goes wrong.
long CurrentSafeColumn;
// Whether or not we are currently parsing a switch statement - changes the behavior of compound statements!
bool SwitchStatement;
// The symbol currently being lexed - TokenTypes index and integer value.
struct Token CurrentSymbol;
// The function currently being parsed - null if in global scope or if finished.
struct SymbolTableEntry* FunctionEntry;
// Once ready, the full AST trees of this file.
struct ASTNode* Tree;
};
enum StorageScope {
SC_GLOBAL = 1, // Global Scope
SC_STRUCT, // Struct Definitions
SC_UNION, // Union Definitions
SC_ENUM, // Enum Definitions
SC_MEMBER, // The members of Structs or Enums
//SC_CLASS, // Class-local definitions
//SC_STATIC, // Static storage definitions
SC_ENUMENTRY, // Enum Entry Names
SC_ALIAS, // Typedef aliases
SC_MEMBER, // The members of Structs or Unions
//SC_CLASS, // Class-local definitions
//SC_STATIC, // Static storage definitions
SC_PARAM, // Function parameters
SC_LOCAL // Function-local scope.
// There is no deeper scope than function.
// There is no deeper scope than function.
};
@ -241,9 +332,12 @@ enum DataTypes {
RET_INT = 32, // "int" type keyword
RET_LONG = 48, // "long" type keyword
RET_VOID = 64, // "void" type keyword
DAT_STRUCT = 80, // Struct Data
DAT_UNION, // Union Data
DAT_ENUM, // Enum Data
DAT_ALIAS, // Alias Definition
DAT_NONE, // No type, no work needed.
};
/*
@ -254,10 +348,10 @@ enum DataTypes {
enum StructureType {
ST_VAR, // This is variable
ST_FUNC, // This is a function
ST_ARR // This is an array
// This is an enum
// This is a struct
// This is a typedef
ST_ARR, // This is an array
ST_RUCT, // This is a struct
ST_ENUM, // This is an enum
// This is a typedef
};
@ -266,9 +360,13 @@ enum StructureType {
* * * * * * * * * * * * * * * * * * * * * * * * * * * */
char* Suffixate(char* String, char Suffix);
char* Compile(char* InputFile);
char* Assemble(char* InputFile);
void Link(char* Output, char* Objects[]);
void Compile(struct FileData* InputFile);
void Assemble(struct FileData* InputFile);
void Link(char* Output, struct FileData* Objects[], int ObjectsLength);
void DisplayUsage(char* ProgName);
@ -276,15 +374,17 @@ void DisplayUsage(char* ProgName);
* * * * * * * * * L E X I N G * * * * * * * * *
* * * * * * * * * * * * * * * * * * * * * * * * * * * */
void Tokenise();
void VerifyToken(int Type, char* TokenExpected);
void RejectToken(struct Token* Token);
bool OptionallyConsume(int Type);
static int ReadIdentifier(int Char, char* Buffer, int Limit);
static int ReadKeyword(char* Str);
void ImportModule();
/* * * * * * * * * * * * * * * * * * * *
* * * * * T Y P E S * * * * * *
* * * * * * * * * * * * * * * * * * * */
@ -292,9 +392,11 @@ static int ReadKeyword(char* Str);
struct ASTNode* MutateType(struct ASTNode* Tree, int RightType, int Operation);
int TypeIsInt(int Type);
int TypeIsPtr(int Type);
char* TypeNames(int Type);
int TypeSize(int Type, struct SymbolTableEntry* Composite);
@ -323,48 +425,75 @@ struct ASTNode* ParsePrecedenceASTNode(int PreviousTokenPrecedence);
struct ASTNode* ParsePrimary(void);
struct ASTNode* ParseStatement(void);
struct ASTNode* PrefixStatement();
struct ASTNode* PostfixStatement();
void ParseGlobals();
struct ASTNode* ParseFunction(int Type);
int ParseDeclarationList(struct SymbolTableEntry** CompositeType, int ClassType, int StatementEndSymbool, int TerminateSymbol, struct ASTNode** Tree);
struct ASTNode* ParseCompound();
struct SymbolTableEntry* BeginStructDeclaration();
struct ASTNode* GetExpressionList();
struct SymbolTableEntry* BeginCompositeDeclaration(int Type);
struct ASTNode* ParseExpressionList(int terminateToken);
struct ASTNode* CallFunction();
struct ASTNode* ReturnStatement();
int ParseOptionalPointer();
struct ASTNode* BreakStatement();
struct ASTNode* ContinueStatement();
int ValueAt(int Type);
int PointerTo(int Type);
struct ASTNode* AccessArray();
struct ASTNode* AccessMember(bool Deref);
int ParseTokenToOperation(int Token);
struct ASTNode* PrintStatement(void);
/* * * * * * * * * * * * * * * * * * * * * * * * * * * *
* * * * * * S Y M B O L T A B L E * * * * * *
* * * * * * * * * * * * * * * * * * * * * * * * * * * */
void DumpAllLists();
void DumpList(struct SymbolTableEntry* List);
struct SymbolTableEntry* FindSymbol(char* Symbol);
struct SymbolTableEntry* FindLocal(char* Symbol);
struct SymbolTableEntry* FindGlobal(char* Symbol);
struct SymbolTableEntry* FindStruct(char* Symbol);
struct SymbolTableEntry* FindAlias(char* Symbol);
struct SymbolTableEntry* FindEnum(char* Symbol);
struct SymbolTableEntry* FindEnumMember(char* Symbol);
struct SymbolTableEntry* FindUnion(char* Symbol);
struct SymbolTableEntry* FindMember(char* Symbol);
void AppendSymbol(struct SymbolTableEntry** Head, struct SymbolTableEntry** Tail, struct SymbolTableEntry* Node);
void FreeLocals();
void ClearTables();
struct SymbolTableEntry* AddSymbol(char* Name, int Type, int Structure, int Storage, int Length, int SinkOffset, struct SymbolTableEntry* CompositeType);
struct SymbolTableEntry* AddSymbol(char* Name, int Type, int Structure, int Storage, int Length, int SinkOffset,
struct SymbolTableEntry* CompositeType);
/* * * * * * * * * * * * * * * * * * * * * * * * * * * *
* * * * C O N T R O L S T A T U S * * * *
@ -378,85 +507,110 @@ void DieDecimal(char* Error, int Number);
void DieChar(char* Error, int Char);
void DieBinary(char* Error, int Number);
void ErrorReport(char* message, ...);
void Safe();
/* * * * * * * * * * * * * * * * * * * * * * * * * * * *
* * * * C O D E G E N E R A T I O N * * * *
* * * * * * * * * * * * * * * * * * * * * * * * * * * */
int AssembleTree(struct ASTNode* Node, int Register, int ParentOp);
int PrimitiveSize (int);
void DeallocateAllRegisters();
/**
* All of the functions required to be implemented by an Assembler Module.
*/
struct AssemblerVtable {
// Entry Point
int (*AssembleTree)(struct ASTNode*, int, int, int, int);
// Register management
void (*DeallocateAllRegisters)();
int (*RetrieveRegister)();
void (*DeallocateRegister)(int);
// Alignment
int (*AsAlignMemory)(int, int, int);
int (*AsCalcOffset)(int);
void (*AsNewStackFrame)();
// Basic operations
int (*AsLoad)(int);
int (*AsAdd)(int, int);
int (*AsMul)(int, int);
int (*AsSub)(int, int);
int (*AsDiv)(int, int);
int (*AsLdGlobalVar)(struct SymbolTableEntry*, int);
int (*AsLdLocalVar)(struct SymbolTableEntry*, int);
int (*AsStrGlobalVar)(struct SymbolTableEntry*, int);
int (*AsStrLocalVar)(struct SymbolTableEntry*, int);
int (*AsDeref)(int, int);
int (*AsStrDeref)(int, int, int);
int (*AsAddr)(struct SymbolTableEntry*);
int (*AsNewString)(char*);
int (*AsLoadString)(int);
int RetrieveRegister();
// Comparisons
int (*AsEqual)(int, int);
int (*AsIneq)(int, int);
int (*AsLess)(int, int);
int (*AsGreat)(int, int);
int (*AsLessE)(int, int);
int (*AsGreatE)(int, int);
void DeallocateRegister(int Register);
// Binary operations
int (*AsBitwiseAND)(int, int);
int (*AsBitwiseOR)(int, int);
int (*AsBitwiseXOR)(int, int);
int (*AsNegate)(int);
int (*AsInvert)(int);
int (*AsBooleanNOT)(int);
int (*AsShiftLeft)(int, int);
int (*AsShiftRight)(int, int);
int PrimitiveSize(int Type);
int AsAlignMemory(int Type, int Offset, int Direction);
// Comparisons
int (*AsBooleanConvert)(int, int, int);
int (*AsCompareJmp)(int, int, int, int);
int (*AsCompare)(int, int, int);
int AsLoad(int Value);
int AsAdd(int Left, int Right);
int AsMul(int Left, int Right);
int AsSub(int Left, int Right);
int AsDiv(int Left, int Right);
// Loops and jumps
int (*AsIf)(struct ASTNode*, int, int);
int (*AsWhile)(struct ASTNode*);
int (*AsSwitch)(struct ASTNode*);
void (*AsSwitchTable)(int, int, int, int*, int*, int);
int (*NewLabel)();
void (*AsJmp)(int);
void (*AsLabel)(int);
int AsLdGlobalVar(struct SymbolTableEntry* Entry, int Operation);
int AsLdLocalVar(struct SymbolTableEntry* Entry, int Operation);
int AsStrGlobalVar(struct SymbolTableEntry* Entry, int Register);
int AsStrLocalVar(struct SymbolTableEntry* Entry, int Register);
// Call and return
int (*AsShl)(int, int);
int (*AsReturn)(struct SymbolTableEntry*, int);
int (*AsCallWrapper)(struct ASTNode*);
void (*AsCopyArgs)(int, int);
int (*AsCall)(struct SymbolTableEntry*, int);
void (*AssemblerPrint)(int);
int AsCalcOffset(int Type);
void AsNewStackFrame();
// Preamble and epilogue
void (*AsGlobalSymbol)(struct SymbolTableEntry*);
void (*AssemblerPreamble)();
void (*AsFunctionPreamble)(struct SymbolTableEntry*);
void (*AsFunctionEpilogue)(struct SymbolTableEntry*);
};
int AsDeref(int Reg, int Type);
int AsStrDeref(int Register1, int Register2, int Type);
int AsAddr(struct SymbolTableEntry* Entry);
struct AssemblerModule{
char* name;
const struct AssemblerVtable* vtable;
};
void AsGlobalSymbol(struct SymbolTableEntry* Entry);
int AsNewString(char* Value);
int RegisterModule(struct AssemblerModule*);
void RegisterAllModules();
int AsLoadString(int ID);
int AsEqual(int Left, int Right);
int AsIneq(int Left, int Right);
int AsLess(int Left, int Right);
int AsGreat(int Left, int Right);
int AsLessE(int Left, int Right);
int AsGreatE(int Left, int Right);
int AsBitwiseAND(int Left, int Right);
int AsBitwiseOR(int Left, int Right);
int AsBitwiseXOR(int Left, int Right);
int AsNegate(int Register);
int AsInvert(int Register);
int AsBooleanNOT(int Register);
int AsShiftLeft(int Left, int Right);
int AsShiftRight(int Left, int Right);
int AsBooleanConvert(int Register, int Operation, int Label);
int AsCompareJmp(int Operation, int RegisterLeft, int RegisterRight, int Label);
int AsCompare(int Operation, int RegisterLeft, int RegisterRight);
int AsIf(struct ASTNode* Node);
int NewLabel(void);
void AsJmp(int Label);
void AsLabel(int Label);
int AsShl(int Register, int Val);
int AsReturn(struct SymbolTableEntry* Entry, int Register);
int AsCallWrapper(struct ASTNode* Node);
void AsCopyArgs(int Register, int Position);
int AsCall(struct SymbolTableEntry* Entry, int Args);
int AsWhile(struct ASTNode* Node);
void AssemblerPrint(int Register);
void AssemblerPreamble();
void AsFunctionPreamble(struct SymbolTableEntry* Entry);
void AsFunctionEpilogue(struct SymbolTableEntry* Entry);
// Module List
void RegisterQBE();
void RegisterWin32ASM();
void RegisterLinuxASM();
void RegisterJVM();
/* * * * * * * * * * * * * * * * * * * * * * *
@ -464,11 +618,14 @@ void AsFunctionEpilogue(struct SymbolTableEntry* Entry);
* * * * * * * * * * * * * * * * * * * * * * */
struct SymbolTableEntry* BeginVariableDeclaration(int Type, struct SymbolTableEntry* Composite, int Scope);
struct ASTNode* ParseIdentifier(void);
struct ASTNode* IfStatement();
struct ASTNode* WhileStatement();
struct ASTNode* ForStatement();
struct ASTNode* SwitchStatement();
void DumpTree(struct ASTNode* node, int level);

137
plugins/c.js Normal file
View File

@ -0,0 +1,137 @@
const child = require("child_process");
const fs = require("fs");
let defaultCompiler = "gcc";
let tempDir;
let defaultLinkFlags = "%.o"
let defaultOutput = "$name"
let linkCache = "";
module.exports = {
/**
* Preprocess the buildscript.
* If it contains compile, assemble and link steps, it does nothing
* If it contains compile but no build, it implicitly adds it with the default arguments.
* @param {object} buildscript the JSON buildscript object
*/
extensionC: function(buildscript) {
console.log("c.js processing buildscript");
if(!("link" in buildscript.build)) {
console.log("Inserting link step for gcc");
buildscript.build["link"] = [defaultLinkFlags];
}
if(!("output" in buildscript.build)) {
console.log("Inserting output step");
buildscript.build["output"] = [defaultOutput];
}
tempDir = process.cwd() + "/bsTemp/";
if(!fs.existsSync(tempDir)) {
console.log("Creating temporary dir for object files");
fs.mkdirSync(tempDir);
}
},
extensionH: function() {},
extensionO: function() {},
extensionLD: function() {},
/**
* Called when it is time to execute the compile step.
* It is passed the array of strings associated with the step in the buildscript.
* @param {...string} params the list of strings
*/
stepCompile: function(...params) {
let cwd = process.cwd().replace(/\\/g, "/");
let compileFlags = "";
// Check whether we're doubly listed
if(Array.isArray(params[0])) {
params = params[0];
}
for(var param of params) {
console.log("stepCompile: param", param);
if(param.startsWith("-")) {
compileFlags = param;
} else {
let binPath = param.substr(param.lastIndexOf(cwd) + cwd.length + 1);
binPath = binPath.substr(0, binPath.lastIndexOf("."));
binPath = cwd + "/bsTemp/" + binPath;
// generate the file structure for it to go into
fs.mkdirSync(binPath.substr(0, binPath.lastIndexOf("/")), {recursive: true});
if(param.substr(param.lastIndexOf(".") + 1) != "c"
&& param.substr(param.lastIndexOf(".") + 1) != "s") {
fs.copyFileSync(param, binPath + ".o");
} else {
let compilerCommand =
defaultCompiler +
" -c " + param +
" -o " + binPath + ".o "
+ compileFlags;
child.execSync(compilerCommand);
}
}
}
},
/**
* Take in the compiled binary object files,
* prepare the link command, and save it for the link execution.
* @param {...string} params the object files to link.
*/
stepLink: function(...params) {
let linkerCommand = "";
// Check whether we're doubly listed
if(Array.isArray(params[0])) {
params = params[0];
}
for(var param of params) {
console.log("stepLink: param", param);
linkerCommand += param + " ";
}
linkCache = linkerCommand;
},
/**
* Take in the name of a file, execute the link command to save the output.
* @param {string} output the name of the wanted file
*/
stepOutput: function(output) {
// Check whether we're doubly listed
if(Array.isArray(output[0])) {
output = output[0];
}
let linkerCommand = defaultCompiler + " -o " + process.cwd() + "/" + output + " " + linkCache;
console.log("stepOutput: param", output, "command", linkerCommand);
child.execSync(linkerCommand);
},
/**
* Set the name of the compiler to be used.
* @param {string} comp
*/
setCompiler: function(comp) {
// Check whether we're doubly listed
if(Array.isArray(comp[0])) {
comp = comp[0];
}
defaultCompiler = comp;
console.log("Set compiler to", comp);
}
}

View File

@ -31,19 +31,19 @@
*/
char* Suffixate(char* String, char Suffix) {
char* Pos, *NewStr;
char* Pos, * NewStr;
if((NewStr = strdup(String)) == NULL)
if ((NewStr = strdup(String)) == NULL)
return NULL;
if((Pos = strrchr(NewStr, '.')) == NULL)
if ((Pos = strrchr(NewStr, '.')) == NULL)
return NULL;
Pos++;
if(*Pos == '\0')
if (*Pos == '\0')
return NULL;
*Pos++ = Suffix;
*Pos = '\0';
return NewStr;
@ -51,54 +51,57 @@ char* Suffixate(char* String, char Suffix) {
/*
* Starts most of the work to do with the Erythro compiler.
* It:
* Opens the input and output files,
* Parses the global symbols of the file, including function blocks.
* Generates the assembly representation of the source code
* Saves said assembly into the OutputFile
* Returns the name of the file containing the generated assembly.
* Note that the Input file must have a valid extension.
* For Erythro code, this is .er
* The generated assembly will have the extension .s
* Starts most of the work to do with the Erythro compiler.
* It:
* Opens the input and output files,
* Parses the global symbols of the file, including function blocks.
* Generates the assembly representation of the source code
* Saves said assembly into the OutputFile
* Returns the name of the file containing the generated assembly.
* Note that the Input file must have a valid extension.
* For Erythro code, this is .er
* The generated assembly will have the extension .s
*
* @param InputFile: The filename of the Erythro Source code to compile
* @return the filename of the generated PECOFF32+ assembly
* @param InputFile: A pointer to the data that we should use to compile this file.
* @return the filename of the generated PECOFF32+ assembly
*/
char* Compile(char* InputFile) {
void Compile(struct FileData* InputFile) {
char* OutputName;
OutputName = Suffixate(InputFile, 's');
if(OutputName == NULL) {
fprintf(stderr, "%s must have a suffix.\r\n", InputFile);
OutputName = Suffixate(InputFile->SourceName, 's');
if (OutputName == NULL) {
fprintf(stderr, "%s must have a suffix.\r\n", InputFile->SourceName);
exit(1);
}
if((SourceFile = fopen(InputFile, "r")) == NULL) {
fprintf(stderr, "Unable to open %s: %s\n", InputFile, strerror(errno));
if ((InputFile->Stream = fopen(InputFile->SourceName, "r")) == NULL) {
fprintf(stderr, "Unable to open %s: %s\n", InputFile->SourceName, strerror(errno));
exit(1);
}
}
if((OutputFile = fopen(OutputName, "w")) == NULL) {
if ((OutputFile = fopen(OutputName, "w")) == NULL) {
fprintf(stderr, "Unable to open %s: %s\n", OutputName, strerror(errno));
exit(1);
}
Line = 1;
Overread = '\n';
CurrentGlobal = 0;
CurrentLocal = SYMBOLS - 1;
InputFile->AssemblyName = OutputName;
CurrentFile = InputFile;
if(OptVerboseOutput)
printf("Compiling %s\r\n", InputFile);
CurrentFile->CurrentLine = 1;
Overread = '\n';
if (OptVerboseOutput)
printf("Compiling %s\r\n", CurrentFile->SourceName);
Tokenise();
AssemblerPreamble();
Assembler->vtable->AssemblerPreamble();
ParseGlobals();
// Output.Tree = ParseGlobals();
fclose(OutputFile);
return OutputName;
}
/*
@ -115,27 +118,28 @@ char* Compile(char* InputFile) {
*
*/
char* Assemble(char* InputFile) {
void Assemble(struct FileData* InputFile) {
char Command[TEXTLEN];
int Error;
char* OutputName;
OutputName = Suffixate(InputFile, 'o');
if(OutputName == NULL) {
fprintf(stderr, "%s must have a suffix.\r\n", InputFile);
OutputName = Suffixate(InputFile->AssemblyName, 'o');
if (OutputName == NULL) {
fprintf(stderr, "%s must have a suffix.\r\n", InputFile->AssemblyName);
exit(1);
}
snprintf(Command, TEXTLEN, "%s %s %s", "as -o ", OutputName, InputFile);
if(OptVerboseOutput)
InputFile->ObjectName = OutputName;
snprintf(Command, TEXTLEN, "%s %s %s", "as -o ", OutputName, InputFile->AssemblyName);
if (OptVerboseOutput)
printf("%s\n", Command);
Error = system(Command);
if(Error != 0) {
fprintf(stderr, "Assembling of %s failed with code %d\n", InputFile, Error);
if (Error != 0) {
fprintf(stderr, "Assembling of %s failed with error code %d\n", InputFile->AssemblyName, Error);
exit(1);
}
return OutputName;
}
/*
@ -150,28 +154,28 @@ char* Assemble(char* InputFile) {
*
*/
void Link(char* Output, char* Objects[]) {
int Count, Size = TEXTLEN, Error;
char Command[TEXTLEN], *CommandPtr;
void Link(char* Output, struct FileData** Objects, int ObjectsLength) {
int Count, Size = TEXTLEN, Error, ObjectIdx = 0;
char Command[TEXTLEN], * CommandPtr;
CommandPtr = Command;
Count = snprintf(CommandPtr, Size, "%s %s ", "gcc -o ", OutputFileName);
CommandPtr += Count;
Size -= Count;
while(*Objects != NULL) {
Count = snprintf(CommandPtr, Size, "%s ", *Objects);
while (ObjectIdx < ObjectsLength - 1) {
Count = snprintf(CommandPtr, Size, "%s ", Objects[ObjectIdx]->ObjectName);
CommandPtr += Count;
Size -= Count;
Objects++;
ObjectIdx++;
}
if(OptVerboseOutput)
if (OptVerboseOutput)
printf("%s\n", Command);
Error = system(Command);
if(Error != 0) {
if (Error != 0) {
fprintf(stderr, "Link failure\n");
exit(1);
}

View File

@ -16,16 +16,16 @@ static int GenerateSrg() {
* Walk the Node tree, and dump the AST tree to stdout.
*/
void DumpTree(struct ASTNode* Node, int level) {
int Lfalse, Lstart, Lend;
int Lstart, Lend;
// Handle weirdo loops and conditions first.
switch(Node->Operation) {
switch (Node->Operation) {
case OP_IF:
Lfalse = GenerateSrg();
for(int i = 0; i < level; i++)
GenerateSrg();
for (int i = 0; i < level; i++)
fprintf(stdout, " ");
fprintf(stdout, "IF");
if(Node->Right) {
if (Node->Right) {
Lend = GenerateSrg();
fprintf(stdout, ", end label %d", Lend);
}
@ -33,85 +33,171 @@ void DumpTree(struct ASTNode* Node, int level) {
fprintf(stdout, "\n");
DumpTree(Node->Left, level + 2);
DumpTree(Node->Middle, level + 2);
if(Node->Right)
if (Node->Right)
DumpTree(Node->Right, level + 2);
return;
case OP_LOOP:
Lstart = GenerateSrg();
for(int i = 0; i < level; i++)
for (int i = 0; i < level; i++)
fprintf(stdout, " ");
fprintf(stdout, "LOOP starts at %d\n", Lstart);
Lend = GenerateSrg();
GenerateSrg();
DumpTree(Node->Left, level + 2);
DumpTree(Node->Right, level + 2);
return;
}
// If current node is a compound, we treat it as if we didn't just enter a loop.
if(Node->Operation == OP_COMP)
if (Node->Operation == OP_COMP)
level = -2;
if(Node->Left)
if (Node->Left)
DumpTree(Node->Left, level + 2);
if(Node->Right)
if (Node->Right)
DumpTree(Node->Right, level + 2);
// The meat of this operation!
for(int i = 0; i < level; i++)
for (int i = 0; i < level; i++)
fprintf(stdout, " ");
switch (Node->Operation){
case OP_COMP: fprintf(stdout, "\n\n"); return;
case OP_FUNC: fprintf(stdout, "OP_FUNC %s\n", Node->Symbol->Name); return;
case OP_ADD: fprintf(stdout, "OP_ADD\n"); return;
case OP_SUBTRACT: fprintf(stdout, "OP_SUBTRACT\n"); return;
case OP_MULTIPLY: fprintf(stdout, "OP_MULTIPLY\n"); return;
case OP_DIVIDE: fprintf(stdout, "OP_DIVIDE\n"); return;
case OP_EQUAL: fprintf(stdout, "OP_EQUAL\n"); return;
case OP_INEQ: fprintf(stdout, "OP_INEQ\n"); return;
case OP_LESS: fprintf(stdout, "OP_LESS\n"); return;
case OP_GREAT: fprintf(stdout, "OP_GREAT\n"); return;
case OP_LESSE: fprintf(stdout, "OP_LESSE\n"); return;
case OP_GREATE: fprintf(stdout, "OP_GREATE\n"); return;
case TERM_INTLITERAL: fprintf(stdout, "TERM_INTLITERAL %d\n", Node->IntValue); return;
case TERM_STRLITERAL: fprintf(stdout, "TERM_STRLITERAL rval L%d\n", Node->IntValue); return;
case REF_IDENT:
if(Node->RVal)
fprintf(stdout, "REF_IDENT rval %s\n", Node->Symbol->Name);
else
fprintf(stdout, "REF_IDENT %s\n", Node->Symbol->Name);
switch (Node->Operation) {
case OP_COMP:
fprintf(stdout, "\n\n");
return;
case OP_CONTINUE:
fprintf(stdout, "OP_CONTINUE\n");
return;
case OP_BREAK:
fprintf(stdout, "OP_BREAK\n");
return;
case OP_FUNC:
fprintf(stdout, "OP_FUNC %s\n", Node->Symbol->Name);
return;
case OP_ADD:
fprintf(stdout, "OP_ADD\n");
return;
case OP_SUBTRACT:
fprintf(stdout, "OP_SUBTRACT\n");
return;
case OP_MULTIPLY:
fprintf(stdout, "OP_MULTIPLY\n");
return;
case OP_DIVIDE:
fprintf(stdout, "OP_DIVIDE\n");
return;
case OP_EQUAL:
fprintf(stdout, "OP_EQUAL\n");
return;
case OP_INEQ:
fprintf(stdout, "OP_INEQ\n");
return;
case OP_LESS:
fprintf(stdout, "OP_LESS\n");
return;
case OP_GREAT:
fprintf(stdout, "OP_GREAT\n");
return;
case OP_LESSE:
fprintf(stdout, "OP_LESSE\n");
return;
case OP_GREATE:
fprintf(stdout, "OP_GREATE\n");
return;
case TERM_INTLITERAL:
fprintf(stdout, "TERM_INTLITERAL %d\n", Node->IntValue);
return;
case TERM_STRLITERAL:
fprintf(stdout, "TERM_STRLITERAL rval L%d\n", Node->IntValue);
return;
case REF_IDENT:
fprintf(stdout, "REF_IDENT%s %s\n", Node->RVal ? " rval" : "", Node->Symbol->Name);
return;
case OP_ASSIGN:
fprintf(stdout, "OP_ASSIGN\n");
return;
case OP_WIDEN:
fprintf(stdout, "OP_WIDEN\n");
return;
case OP_RET:
fprintf(stdout, "OP_RET\n");
return;
case OP_CALL:
fprintf(stdout, "OP_CALL %s\n", Node->Symbol->Name);
return;
case OP_ADDRESS:
fprintf(stdout, "OP_ADDRESS %s\n", Node->Symbol->Name);
return;
case OP_DEREF:
fprintf(stdout, "OP_DEREF %s\n", Node->RVal ? "rval" : "");
return;
case OP_SCALE:
fprintf(stdout, "OP_SCALE %s\n", TypeNames(Node->Size));
return;
case OP_ASSIGN: fprintf(stdout, "OP_ASSIGN\n"); return;
case OP_WIDEN: fprintf(stdout, "OP_WIDEN\n"); return;
case OP_RET: fprintf(stdout, "OP_RET\n"); return;
case OP_CALL: fprintf(stdout, "OP_CALL %s\n", Node->Symbol->Name); return;
case OP_ADDRESS: fprintf(stdout, "OP_ADDRESS %s\n", Node->Symbol->Name); return;
case OP_DEREF:
fprintf(stdout, "OP_DEREF %s\n", Node->RVal ? "rval" : ""); return;
case OP_SCALE: fprintf(stdout, "OP_SCALE %s\n", TypeNames(Node->Size)); return;
case OP_BOOLOR: fprintf(stdout, "OP_BOOLOR\n"); return;
case OP_BOOLAND: fprintf(stdout, "OP_BOOLAND\n"); return;
case OP_BITOR: fprintf(stdout, "OP_BITOR\n"); return;
case OP_BITXOR: fprintf(stdout, "OP_BITXOR\n"); return;
case OP_BITAND: fprintf(stdout, "OP_BITAND\n"); return;
case OP_BOOLOR:
fprintf(stdout, "OP_BOOLOR\n");
return;
case OP_BOOLAND:
fprintf(stdout, "OP_BOOLAND\n");
return;
case OP_BITOR:
fprintf(stdout, "OP_BITOR\n");
return;
case OP_BITXOR:
fprintf(stdout, "OP_BITXOR\n");
return;
case OP_BITAND:
fprintf(stdout, "OP_BITAND\n");
return;
case OP_SHIFTL: fprintf(stdout, "OP_SHIFTL\n"); return;
case OP_SHIFTR: fprintf(stdout, "OP_SHIFTR\n"); return;
case OP_SHIFTL:
fprintf(stdout, "OP_SHIFTL\n");
return;
case OP_SHIFTR:
fprintf(stdout, "OP_SHIFTR\n");
return;
case OP_PREINC: fprintf(stdout, "OP_PREINC\n"); return;
case OP_PREDEC: fprintf(stdout, "OP_PREDEC\n"); return;
case OP_POSTINC: fprintf(stdout, "OP_POSTINC\n"); return;
case OP_POSTDEC: fprintf(stdout, "OP_POSTDEC\n"); return;
case OP_PREINC:
fprintf(stdout, "OP_PREINC\n");
return;
case OP_PREDEC:
fprintf(stdout, "OP_PREDEC\n");
return;
case OP_POSTINC:
fprintf(stdout, "OP_POSTINC\n");
return;
case OP_POSTDEC:
fprintf(stdout, "OP_POSTDEC\n");
return;
case OP_BITNOT: fprintf(stdout, "OP_BITNOT\n"); return;
case OP_BOOLNOT: fprintf(stdout, "OP_BOOLNOT\n"); return;
case OP_NEGATE: fprintf(stdout, "OP_NEGATE\n"); return;
case OP_BITNOT:
fprintf(stdout, "OP_BITNOT\n");
return;
case OP_BOOLNOT:
fprintf(stdout, "OP_BOOLNOT\n");
return;
case OP_NEGATE:
fprintf(stdout, "OP_NEGATE\n");
return;
case OP_BOOLCONV: fprintf(stdout, "OP_BOOLCONV\n"); return;
case OP_BOOLCONV:
fprintf(stdout, "OP_BOOLCONV\n");
return;
case OP_DEFAULT:
fprintf(stdout, "OP_DEFAULT\n");
return;
case OP_CASE:
fprintf(stdout, "OP_CASE %d\n", Node->IntValue);
return;
case OP_SWITCH:
fprintf(stdout, "SWITCH\n");
return;
default:
DieDecimal("Unknown Dump Operator", Node->Operation);

95
src/Errors.c Normal file
View File

@ -0,0 +1,95 @@
/*************/
/*GEMWIRE */
/* ERYTHRO*/
/*************/
#include <stdio.h>
#include <Defs.h>
#include <Data.h>
#include <stdarg.h>
void Safe() {
CurrentFile->CurrentSafeColumn = CurrentFile->CurrentColumn - 1;
}
void printLine(FILE* file, int ln) {
char buffer[256];
fgets(buffer, 256, file);
// Line number
printf("%03d|%s", ln + 1, buffer);
}
void printErrorLine(FILE* file, int ln) {
char firstBuffer[256], problemBuffer[256], tailBuffer[256];
// If highlight starts at column 0, don't try to print anything before it
if (CurrentFile->CurrentSafeColumn != 0)
fgets(firstBuffer, CurrentFile->CurrentSafeColumn, file);
// Print the safe column up to current column
fgets(problemBuffer, (CurrentFile->CurrentColumn > CurrentFile->CurrentSafeColumn ? CurrentFile->CurrentColumn - CurrentFile->CurrentSafeColumn : CurrentFile->CurrentColumn), file);
// Print the current column to the end of the line
if (CurrentFile->CurrentColumn > CurrentFile->CurrentSafeColumn)
fgets(tailBuffer, 256, file);
// Line number
printf("%03d|%s\033[0;31m%s\033[0m%s", ln + 1, firstBuffer, problemBuffer, tailBuffer);
}
void printHelpLine(int line, char* message) {
printf(" | %s", message);
}
void ErrorReport(char* message, ...) {
fflush(stdout);
char strbuf[256];
// Resolve varargs to a string
va_list args;
va_start(args, message);
vsprintf(strbuf, message, args);
va_end(args);
int line = CurrentFile->CurrentLine - 1;
FILE* file = fopen(CurrentFile->SourceName, "r");
int errorOnLastLine = CurrentFile->CurrentColumn == 0;
// Print context for the error - up to 2 lines above the error
if (line < 3) {
// If we're at 0 or 1, we need to be careful to not try to print -1 for example.
for (int i = 0; i < line; i++)
printLine(file, i);
} else {
// Skip to line - 2
char buffer[256];
int count = 0;
while (count < line - (errorOnLastLine ? 3 : 2)) {
fgets(buffer, 256, file);
count++;
}
if (errorOnLastLine)
printLine(file, line - 3);
printLine(file, line - 2);
if (!errorOnLastLine) printLine(file, line - 1);
}
if (errorOnLastLine) {
printErrorLine(file, line - 1);
printHelpLine(line, strbuf);
printLine(file, line);
if (!feof(file))
printLine(file, line + 1);
} else {
printErrorLine(file, line);
printHelpLine(line, strbuf);
if (!feof(file))
printLine(file, line + 1);
if (!feof(file))
printLine(file, line + 2);
}
exit(1);
}

135
src/Importer.c Normal file
View File

@ -0,0 +1,135 @@
/*************/
/*GEMWIRE */
/* ERYTHRO*/
/*************/
#include <Defs.h>
#include <Data.h>
#include <string.h>
#include <unistd.h>
#include <stdio.h>
#include <limits.h>
#include <sys/stat.h>
#if defined(__GNUC__) || defined(APPLE)
#include <errno.h>
#endif
#ifdef WIN32
#define realpath(N,R) _fullpath((R),(N),PATH_MAX)
#endif
/**
* The function of the importer is to read in definitions from a file, and store
* them into the symbol tables.
*
* The file to be imported is called a "module", which is Erythro terminology for C-like "headers".
* They contain extra metadata that allows for Erythro's enhanced debugging and error logging.
*
* Modules may also contain metadata about the contents within - allowing for multiple compile-time
* sourcesets with different arguments, all parsed at the same time as the source code.
*
* This allows Erythro to have first-class support for multiple-build-single-link situations,
* that would require the use of a build system like CMake in other languages.
*
*/
/**
* Read in the information of a module, check that it is valid, and then read the module itself.
* Import syntax looks like:
*
* > import "file"
*
* The string is appended to the current working directory and is checked.
* If the resulting path exists and resolves to a file, then the file's declarations are added to the symbol tables.
*
* Modules may not contain definitions. Only declarations
* TODO: Module metadata as described above.
*/
void ImportModule() {
// Skip the import keyword
Tokenise();
// Make sure there's a string after the import.
if (CurrentFile->CurrentSymbol.type != LI_STR)
Die("Import statement must be followed by a compile-time constant string.");
// Read in the string that we know must be there.
char* Module = strdup(CurrentIdentifier);
// Two strategies for finding the module; either it's relative to cwd, or it's relative to source.
bool FoundImport = false;
// Check the cwd first.
// Figure out the working directory
char CWD[PATH_MAX];
if (getcwd(CWD, sizeof(CWD)) == NULL)
DieMessage("Unable to find cwd when importing module", Module);
// Append the module name to the current working directory
char* ModulePath = malloc(strlen(CWD) + strlen(Module) + 1);
strcpy(ModulePath, CWD);
strcpy(ModulePath + strlen(CWD), "/");
strcpy(ModulePath + strlen(CWD) + 1, Module);
printf("Scanning %s for module definitions.\n", ModulePath);
// Stat the file to see if it exists
struct stat FileInfo;
if (stat(ModulePath, &FileInfo) != 0) {
free(ModulePath);
char SourcePath[PATH_MAX + 1];
realpath(CurrentFile->SourceName, SourcePath);
// Deal with windows being windows
char* SourceFolderLength = strrchr(SourcePath, '/');
if (SourceFolderLength == NULL) {
SourceFolderLength = strrchr(SourcePath, '\\');
}
*(SourceFolderLength + 1) = '\0';
size_t SourcePathLength = strlen(SourcePath);
ModulePath = malloc(SourcePathLength + sizeof(Module) + 1);
strcpy(ModulePath, SourcePath);
strcpy(ModulePath + SourcePathLength, Module);
printf("Scanning %s for module definitions.\n", ModulePath);
if (stat(ModulePath, &FileInfo) != 0)
DieMessage("Unable to access the imported module", ModulePath);
}
// At this point, the file exists and we have the path.
// Save the current file, so that we can restore it later
struct FileData* SavedFile = CurrentFile;
// Create a new file with the module name
struct FileData* ModuleData = malloc(sizeof(struct FileData));
memset(ModuleData, 0, sizeof(struct FileData));
ModuleData->AllowDefinitions = false;
ModuleData->SourceName = ModulePath;
printf("Swapping to module %s..\n\n", ModulePath);
// Parse all relevant data from the module file...
if ((ModuleData->Stream = fopen(ModuleData->SourceName, "r")) == NULL) {
fprintf(stderr, "Unable to open %s: %s\n", ModuleData->SourceName, strerror(errno));
exit(1);
}
CurrentFile = ModuleData;
CurrentFile->CurrentLine = 1;
Tokenise();
ParseGlobals();
fclose(CurrentFile->Stream);
printf("\n\nSwapping back to file %s..\n", SavedFile->SourceName);
// Reinstate the saved file
CurrentFile = SavedFile;
// Tokenise past the string we just parsed
Tokenise();
}

View File

@ -37,17 +37,21 @@ static void ReturnCharToStream(int Char) {
static int NextChar(void) {
int Char;
if(Overread) {
if (Overread) {
Char = Overread;
Overread = 0;
return Char;
}
Char = fgetc(SourceFile);
Char = fgetc(CurrentFile->Stream);
CurrentFile->CurrentColumn++;
if (Char == '\n') {
CurrentFile->CurrentLine++;
CurrentFile->CurrentColumn = 0;
}
if(Char == '\n')
Line++;
return Char;
}
@ -61,7 +65,7 @@ static int FindChar() {
Char = NextChar();
while(Char == ' ' || Char == '\t' || Char == '\n' || Char == '\r') {
while (Char == ' ' || Char == '\t' || Char == '\n' || Char == '\r') {
Char = NextChar();
}
@ -77,7 +81,7 @@ static int FindChar() {
static int FindDigitFromPos(char* String, char Char) {
char* Result = strchr(String, Char);
return(Result ? Result - String : -1);
return (Result ? Result - String : -1);
}
/*
@ -91,29 +95,22 @@ static int FindDigitFromPos(char* String, char Char) {
*/
void VerifyToken(int Type, char* TokenExpected) {
if(CurrentToken.type == Type)
if (CurrentFile->CurrentSymbol.type == Type)
Tokenise();
else {
printf("Expected %s on line %d\n", TokenExpected, Line);
Tokenise();
ErrorReport("Expected %s, but got %s instead.\n", TokenExpected, TokenNames[CurrentFile->CurrentSymbol.type]);
exit(1);
}
}
static struct Token* RejectedToken = NULL;
/*
* Rejected Tokens and the Overread Stream are identical concepts.
* This was implemented first, but it is no longer used.
* TODO: Refactor this function out.
*/
void RejectToken(struct Token* Token) {
if(RejectedToken != NULL)
Die("Cannot reject two tokens in a row!");
RejectedToken = Token;
bool OptionallyConsume(int Type) {
if (CurrentFile->CurrentSymbol.type == Type) {
Tokenise();
return true;
}
return false;
}
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* * * * L I T E R A L S A N D I D E N T I F I E R S * * * *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
@ -123,7 +120,7 @@ void RejectToken(struct Token* Token) {
* Currently only supports the decimal numbers, despite the
* FindDigitFromPos function allowing conversion.
*
* The functon loops over the characters, multiplying by 10 and adding
* The function loops over the characters, multiplying by 10 and adding
* the new value on top, until a non-numeric character is found.
* At that point, it returns the non-numeric character to the Overread Stream
* and returns the calculated number.
@ -137,7 +134,7 @@ static int ReadInteger(int Char) {
int CurrentChar = 0;
int IntegerValue = 0;
while((CurrentChar = FindDigitFromPos("0123456789", Char)) >= 0) {
while ((CurrentChar = FindDigitFromPos("0123456789", Char)) >= 0) {
IntegerValue = IntegerValue * 10 + CurrentChar;
Char = NextChar();
}
@ -165,12 +162,12 @@ static int ReadInteger(int Char) {
*
*/
static int ReadIdentifier(int Char, char* Buffer, int Limit) {
int ind = 0;
int ind = 0;
// This defines the valid chars in a keyword/variable/function.
while(isalpha(Char) || isdigit(Char) || Char == '_') {
while (isalpha(Char) || isdigit(Char) || Char == '_') {
if (ind >= Limit - 1) {
printf("Identifier too long: %d\n", Line);
printf("Identifier too long: %ld\n", CurrentFile->CurrentLine);
exit(1);
} else {
Buffer[ind++] = Char;
@ -199,18 +196,28 @@ static int ReadIdentifier(int Char, char* Buffer, int Limit) {
static int ReadCharLiteral() {
int Char;
Char = NextChar();
if(Char == '\\') {
switch(Char = NextChar()) {
case 'a': return '\a';
case 'b': return '\b';
case 'f': return '\f';
case 'n': return '\n';
case 'r': return '\r';
case 't': return '\t';
case 'v': return '\v';
case '\\': return '\\';
case '"': return '"';
case '\'': return '\'';
if (Char == '\\') {
switch (Char = NextChar()) {
case 'a':
return '\a';
case 'b':
return '\b';
case 'f':
return '\f';
case 'n':
return '\n';
case 'r':
return '\r';
case 't':
return '\t';
case 'v':
return '\v';
case '\\':
return '\\';
case '"':
return '"';
case '\'':
return '\'';
default:
DieChar("Unknown Escape: ", Char);
}
@ -236,11 +243,12 @@ static int ReadCharLiteral() {
static int ReadStringLiteral(char* Buffer) {
int Char;
for(int i = 0; i < TEXTLEN - 1; i++) {
if((Char = ReadCharLiteral()) == '"') {
Buffer[i] = 0; return i;
for (int i = 0; i < TEXTLEN - 1; i++) {
if ((Char = ReadCharLiteral()) == '"') {
Buffer[i] = 0;
return i;
}
Buffer[i] = Char;
}
@ -265,80 +273,110 @@ static int ReadStringLiteral(char* Buffer) {
*/
static int ReadKeyword(char* Str) {
// First, scan with reference intact.
switch(*Str) {
switch (*Str) {
// This lets us case against the first char:
case ':':
if(!strcmp(Str, "::"))
if (!strcmp(Str, "::"))
return KW_FUNC;
break;
case 'c':
if(!strcmp(Str, "char"))
return TY_CHAR;
case 'a':
if (!strcmp(Str, "alias"))
return KW_ALIAS;
break;
case 'b':
if (!strcmp(Str, "break"))
return KW_BREAK;
break;
case 'c':
if (!strcmp(Str, "char"))
return TY_CHAR;
if (!strcmp(Str, "continue"))
return KW_CONTINUE;
if (!strcmp(Str, "case"))
return KW_CASE;
break;
case 'd':
if (!strcmp(Str, "default"))
return KW_DEFAULT;
case 'e':
if(!strcmp(Str, "else"))
if (!strcmp(Str, "else"))
return KW_ELSE;
if (!strcmp(Str, "enum"))
return KW_ENUM;
break;
case 'f':
if(!strcmp(Str, "for"))
if (!strcmp(Str, "for"))
return KW_FOR;
break;
case 'i':
// alias char, int and long types
if(!strcmp(Str, "i8"))
if (!strcmp(Str, "i8"))
return TY_CHAR;
if(!strcmp(Str, "i32"))
if (!strcmp(Str, "i32"))
return TY_INT;
if(!strcmp(Str, "i64"))
if (!strcmp(Str, "i64"))
return TY_LONG;
if(!strcmp(Str, "int"))
if (!strcmp(Str, "int"))
return TY_INT;
if(!strcmp(Str, "if"))
if (!strcmp(Str, "import"))
return KW_IMPORT;
if (!strcmp(Str, "if"))
return KW_IF;
break;
case 'l':
if(!strcmp(Str, "long"))
if (!strcmp(Str, "long"))
return TY_LONG;
break;
case 'p':
if(!strcmp(Str, "print"))
if (!strcmp(Str, "print"))
return KW_PRINT;
break;
case 'r':
if(!strcmp(Str, "return"))
if (!strcmp(Str, "return"))
return KW_RETURN;
break;
case 's':
if(!strcmp(Str, "struct"))
if (!strcmp(Str, "struct"))
return KW_STRUCT;
if (!strcmp(Str, "switch"))
return KW_SWITCH;
break;
case 'u':
if(!strcmp(Str, "union"))
return KW_UNION;
break;
case 'v':
if(!strcmp(Str, "void"))
if (!strcmp(Str, "void"))
return TY_VOID;
break;
case 'w':
if(!strcmp(Str, "while"))
if (!strcmp(Str, "while"))
return KW_WHILE;
break;
}
return 0;
@ -362,25 +400,23 @@ static int ReadKeyword(char* Str) {
*/
void Tokenise() {
int Char, TokenType;
struct Token* Token = &CurrentToken;
if(RejectedToken != NULL) {
Token = RejectedToken;
RejectedToken = NULL;
return;
}
struct Token* Token = &CurrentFile->CurrentSymbol;
Char = FindChar();
switch(Char) {
switch (Char) {
case EOF:
Token->type = LI_EOF;
return;
case '.':
Token->type = LI_DOT;
return;
case '+':
// + can be either "+" or "++".
Char = NextChar();
if(Char == '+') {
if (Char == '+') {
Token->type = PPMM_PLUS;
} else {
Token->type = AR_PLUS;
@ -389,10 +425,12 @@ void Tokenise() {
break;
case '-':
// - can be either "-" or "--"
// - can be either "-" or "--" or "->"
Char = NextChar();
if(Char == '-') {
if (Char == '-') {
Token->type = PPMM_MINUS;
} else if (Char == '>') {
Token->type = LI_ARROW;
} else {
Token->type = AR_MINUS;
ReturnCharToStream(Char);
@ -409,28 +447,28 @@ void Tokenise() {
case '&':
Char = NextChar();
if(Char == '&') {
if (Char == '&') {
Token->type = BOOL_AND;
} else {
Token->type = BIT_AND;
ReturnCharToStream(Char);
}
break;
case '|':
Char = NextChar();
if(Char == '|') {
if (Char == '|') {
Token->type = BOOL_OR;
} else {
Token->type = BIT_OR;
ReturnCharToStream(Char);
}
break;
case '^':
Token->type = BIT_XOR;
break;
case '~':
Token->type = BIT_NOT;
break;
@ -438,40 +476,40 @@ void Tokenise() {
case ',':
Token->type = LI_COM;
break;
case '=':
Char = NextChar();
// If the next char is =, we have ==, the compare equality token.
if(Char == '?') {
if (Char == '?') {
Token->type = CMP_EQUAL;
// if the next char is >, we have =>, the greater than or equal token.
} else if(Char == '>') {
// if the next char is >, we have =>, the greater than or equal token.
} else if (Char == '>') {
Token->type = CMP_GTE;
// If none of the above match, we have = and an extra char. Return the char and set the token
// If none of the above match, we have = and an extra char. Return the char and set the token
} else {
ReturnCharToStream(Char);
Token->type = LI_EQUAL;
}
break;
case '!':
Char = NextChar();
// If the next char is =, we have !=, the compare inequality operator.
if(Char == '=') {
if (Char == '=') {
Token->type = CMP_INEQ;
// Otherwise, we have a spare char
// Otherwise, we have a spare char
} else {
Token->type = BOOL_INVERT;
ReturnCharToStream(Char);
ReturnCharToStream(Char);
}
break;
case '<':
Char = NextChar();
// If the next char is =, we have <=, the less than or equal comparator.
if(Char == '=') {
if (Char == '=') {
Token->type = CMP_LTE;
} else if(Char == '<') { // But if the next char is <, we have << - the Shift Left operator.
} else if (Char == '<') { // But if the next char is <, we have << - the Shift Left operator.
Token->type = SH_LEFT;
} else {
ReturnCharToStream(Char);
@ -482,7 +520,7 @@ void Tokenise() {
case '>':
// For >, Less than or equal is => so we can ignore it, but the Shift Right operator is >>.
Char = NextChar();
if(Char == '>') {
if (Char == '>') {
Token->type = SH_RIGHT;
} else {
Token->type = CMP_GT;
@ -497,11 +535,11 @@ void Tokenise() {
case '(':
Token->type = LI_LPARE;
break;
case ')':
Token->type = LI_RPARE;
break;
case '{':
Token->type = LI_LBRAC;
break;
@ -513,18 +551,18 @@ void Tokenise() {
case '[':
Token->type = LI_LBRAS;
break;
case ']':
Token->type = LI_RBRAS;
break;
case ':':
Char = NextChar();
if(Char == ':') {
if (Char == ':') {
Token->type = KW_FUNC;
} else {
ReturnCharToStream(Char);
Token->type = LI_COLON;
}
break;
@ -532,8 +570,8 @@ void Tokenise() {
Token->value = ReadCharLiteral();
Token->type = LI_INT;
if(NextChar() != '\'')
Die("Expected '\\'' at the end of a character.");
if (NextChar() != '\'')
ErrorReport("Expected '\\'' at the end of a character.\n");
break;
case '"':
@ -542,29 +580,26 @@ void Tokenise() {
break;
default:
if(isdigit(Char)) {
if (isdigit(Char)) {
Token->value = ReadInteger(Char);
Token->type = LI_INT;
break;
} else if(isalpha(Char) || Char == '_') { // This is what defines what a variable/function/keyword can START with.
} else if (isalpha(Char) ||
Char == '_') { // This is what defines what a variable/function/keyword can START with.
ReadIdentifier(Char, CurrentIdentifier, TEXTLEN);
if(TokenType = ReadKeyword(CurrentIdentifier)) {
if ((TokenType = ReadKeyword(CurrentIdentifier))) {
Token->type = TokenType;
break;
}
Token->type = TY_IDENTIFIER;
break;
//printf("Line %d: Unrecognized symbol %s\n", CurrentIdentifier, Line);
//exit(1);
}
DieChar("Unrecognized character", Char);
ErrorReport("Unrecognized character: %c\n", Char);
}
}

View File

@ -7,122 +7,220 @@
#define extern_
#include <Data.h>
#undef extern_
#include <errno.h>
#include <unistd.h>
int TypeSizes[5] = { 0, 1, 4, 8, 0}; // in BYTES
int TypeSizes[5] = {0, 1, 4, 8, 0}; // in BYTES
char* TokenNames[] = {
"End of file",
"Equivalency",
char* TokenNames[] = {
"End of file",
"Equivalency",
"Boolean Logic OR",
"Boolean Logic AND",
"Boolean Logic OR",
"Boolean Logic AND",
"Bitwise OR",
"Bitwise XOR",
"Bitwise AND",
"Bitwise OR",
"Bitwise XOR",
"Bitwise AND",
"Equality Check",
"Inequality Check",
"Less Than",
"Greater Than",
"Less Than or Equal",
"Greater Than or Equal",
"Equality Check",
"Inequality Check",
"Less Than",
"Greater Than",
"Less Than or Equal",
"Greater Than or Equal",
"Left Shift",
"Right Shift",
"Left Shift",
"Right Shift",
"Addition",
"Subtraction",
"Multiplication",
"Division",
"Addition",
"Subtraction",
"Multiplication",
"Division",
"Increment",
"Decrement",
"Increment",
"Decrement",
"Statement Logical Invert",
"Bitwise Invert",
"Integer literal",
"String literal",
"Statement End",
"Statement Logical Invert",
"Bitwise Invert",
"Compound Block Start",
"Compound Block End",
"Integer literal",
"String literal",
"Statement End",
"Colon",
"Array index start",
"Array index end",
"Compound Block Start",
"Compound Block End",
"Logical Block Start",
"Logical Block End",
"Array index start",
"Array index end",
"Comma",
"Logical Block Start",
"Logical Block End",
"Identifier",
"None Type",
"Char Type",
"Int Type",
"Long Type",
"Void Type",
"Comma",
"Dot",
"Arrow",
"Function keyword",
"Print Keyword",
"If keyword",
"Else keyword",
"While keyword",
"For keyword",
"Identifier",
"None Type",
"Char Type",
"Int Type",
"Long Type",
"Void Type",
"Return keyword",
"Struct keyword"
"Function keyword",
"Break keyword",
"Continue keyword",
"Switch Keyword",
"Default Keyword",
"Case Keyword",
"Print Keyword",
"If keyword",
"Else keyword",
"While keyword",
"For keyword",
"Return keyword",
"Struct keyword",
"Union keyword",
"Enum keyword",
"Alias keyword",
"Import keyword"
};
char* OperationNames[] = {
"OP_ASSIGN", // Assign an l-value
"OP_BOOLOR", // Boolean OR two statements
"OP_BOOLAND", // Boolean AND two statements
"OP_BITOR", // Bitwise OR a number
"OP_BITXOR", // Bitwise XOR a number
"OP_BITAND", // Bitwise AND a number
"OP_EQUAL", // Compare equality
"OP_INEQ", // Compare inequality
"OP_LESS", // Less than?
"OP_GREAT", // Greater than?
"OP_LESSE", // Less than or Equal to?
"OP_GREATE", // Greater than or Equal to?
"OP_SHIFTL", // Arithmetic Shift Left (Multiply by 2)
"OP_SHIFTR", // Arithmetic Shift Right (Divide by 2)
"OP_ADD", // Add two numbers.
"OP_SUBTRACT", // Subtract two numbers.
"OP_MULTIPLY", // Multiply two numbers.
"OP_DIVIDE", // Divide two numbers.
"OP_PREINC", // Increment var before reference.
"OP_PREDEC", // Decrement var before reference.
"OP_POSTINC", // Increment var after reference.
"OP_POSTDEC", // Decrement var after reference.
"OP_BITNOT", // Invert a number bitwise
"OP_BOOLNOT", // Invert a statement logically
"OP_NEGATE", // Negate a number (turn a positive number negative
"OP_BOOLCONV", // Convert an expression to a boolean.s
"OP_ADDRESS", // Fetch the address of a var
"OP_DEREF", // Get the value of the address in a pointer
"TERM_INTLITERAL", // Integer Literal. This is a virtual operation", so it's a terminal.
"TERM_STRLITERAL", // String Literal. Also terminal.
"REF_IDENT", // Reference (read) an identifier (variable).
"OP_WIDEN", // Something contains a type that needs to be casted up
"OP_SCALE", // We have a pointer that needs to be scaled!
"OP_CALL", // Call a function
"OP_RET", // Return from a function
"OP_COMP", // Compound statements need a way to be 'glued' together. This is one of those mechanisms
"OP_IF", // If statement
"OP_LOOP", // FOR", WHILE
"OP_PRINT", // Print statement
"OP_FUNC", // Define a function
"OP_BREAK", // Break out of the loop
"OP_CONTINUE", // Continue the loop
"OP_SWITCH", // Switch statement
"OP_DEFAULT", // Default case
"OP_CASE" // Case
};
char* ScopeNames[] = {
"INVALID",
"GLOBAL",
"STRUCT",
"UNION",
"ENUM",
"ENUM_ENTRY",
"ALIAS",
"MEMBER",
"PARAMETER",
"LOCAL"
};
int main(int argc, char* argv[]) {
// Option initialisers
OptDumpTree = false;
OptKeepAssembly = false;
OptAssembleFiles = false;
OptKeepAssembly = true;
OptAssembleFiles = true;
OptLinkFiles = true;
OptVerboseOutput = false;
OptAssemblerName = "Win32";
struct FileData* InitData = malloc(sizeof(struct FileData));
InitData->CurrentLine = 0;
CurrentFile = InitData;
// Temporary .o storage and counter
char* ObjectFiles[100];
int ObjectCount = 0;
// Parse command line arguments.
int i;
for(i = 1/*skip 0*/; i < argc; i++) {
for (i = 1/*skip 0*/; i < argc; i++) {
// If we're not a flag, we can skip.
// We only care about flags in rows.
// ie. erc >> -v -T -o << test.exe src/main.er
if(*argv[i] != '-')
if (*argv[i] != '-')
break;
// Once we identify a flag, we need to make sure it's not just a minus in-place.
for(int j = 1; (*argv[i] == '-') && argv[i][j]; j++) {
for (int j = 1; (*argv[i] == '-') && argv[i][j]; j++) {
// Finally, identify what option is being invoked.
switch(argv[i][j]) {
switch (argv[i][j]) {
case 'o': // output
OutputFileName = argv[++i];
break;
case 'T': // Debug
OptDumpTree = true;
break;
case 'T': // print Tree (debug)
OptDumpTree = true;
break;
case 'c': // Compile only
OptAssembleFiles = true;
OptKeepAssembly = false;
OptLinkFiles = false;
break;
case 'S': // aSsemble only
OptAssembleFiles = false;
OptAssembleFiles = true;
OptKeepAssembly = true;
OptLinkFiles = false;
break;
case 'v': // Verbose output
OptVerboseOutput = true;
break;
case 'm': // Specify Assembler Module
OptAssemblerName = argv[++i];
break;
default:
DisplayUsage(argv[0]);
}
@ -130,43 +228,50 @@ int main(int argc, char* argv[]) {
}
// If we didn't provide anything other than flags, we need to show how to use the program.
if(i >= argc)
if (i >= argc)
DisplayUsage(argv[0]);
int StartOfFiles = i;
// Allocate enough files for the full specified source code
Files = malloc(sizeof(struct FileData*) * (argc - i) + 1);
memset(Files, 0, sizeof(struct FileData*) * (argc - i) + 1);
RegisterAllModules();
// For the rest of the files specified, we can iterate them right to left.
while(i < argc) {
while (i < argc) {
// Prepare the source metadata before we start compiling
struct FileData* Source = malloc(sizeof(struct FileData));
memset(Source, 0, sizeof(struct FileData));
Source->SourceName = argv[i];
Source->AllowDefinitions = true;
printf("Compiling file %d (%s)\n", i - StartOfFiles, argv[i]);
Files[i - StartOfFiles] = Source;
// Compile the file by invoking the Delegate
CurrentASMFile = Compile(argv[i]);
if(OptLinkFiles || OptAssembleFiles) {
Compile(Source);
if (OptLinkFiles || OptAssembleFiles) {
// If we need to assemble (or link, which requires assembly)
// then we invoke the Delegate again
CurrentObjectFile = Assemble(CurrentASMFile);
// We can only keep track of 99 objects, so we should crash at 98 to ensure we have enough room for the output file too.
if(ObjectCount == 98) {
fprintf(stderr, "Too many inputs");
return 1; // We use return because we're in main, rather than invoking Die.
}
// Move the ObjectCount forward.
ObjectFiles[ObjectCount++] = CurrentObjectFile;
// Clear the new, forwarded index
ObjectFiles[ObjectCount] = NULL;
Assemble(Source);
}
if(!OptKeepAssembly)
if (!OptKeepAssembly)
// unlink = delete
unlink(CurrentASMFile);
unlink(Source->AssemblyName);
i++;
}
if(OptLinkFiles) {
if (OptLinkFiles) {
// If needed, invoke the Delegate one last time.
Link(OutputFileName, ObjectFiles);
if(!OptAssembleFiles) {
Link(OutputFileName, Files, (argc - StartOfFiles) + 1);
if (!OptAssembleFiles) {
// Even though we need to assemble to link, we can respect the user's options and delete the intermediary files.
for(i = 0; ObjectFiles[i] != NULL; i++)
unlink(ObjectFiles[i]);
for (i = 0; i < (argc - StartOfFiles) + 1; i++) {
unlink(Files[i]->AssemblyName);
unlink(Files[i]->ObjectName);
}
}
}
@ -180,7 +285,7 @@ int main(int argc, char* argv[]) {
*/
void Die(char* Error) {
fprintf(stderr, "%s on line %d\n", Error, Line);
fprintf(stderr, "%s on line %ld\n", Error, CurrentFile->CurrentLine);
fclose(OutputFile);
unlink(OutputFileName);
exit(1);
@ -190,7 +295,7 @@ void Die(char* Error) {
* A variant of Die with an extra String attached.
*/
void DieMessage(char* Error, char* Reason) {
fprintf(stderr, "%s: %s on line %d\n", Error, Reason, Line);
fprintf(stderr, "%s: %s on line %ld\n", Error, Reason, CurrentFile->CurrentLine);
fclose(OutputFile);
unlink(OutputFileName);
exit(1);
@ -200,7 +305,7 @@ void DieMessage(char* Error, char* Reason) {
* A variant of Die with an extra integer attached.
*/
void DieDecimal(char* Error, int Number) {
fprintf(stderr, "%s: %d on line %d\n", Error, Number, Line);
fprintf(stderr, "%s: %d on line %ld\n", Error, Number, CurrentFile->CurrentLine);
fclose(OutputFile);
unlink(OutputFileName);
exit(1);
@ -210,7 +315,7 @@ void DieDecimal(char* Error, int Number) {
* A variant of Die with an extra character attached.
*/
void DieChar(char* Error, int Char) {
fprintf(stderr, "%s: %c on line %d\n", Error, Char, Line);
fprintf(stderr, "%s: %c on line %ld\n", Error, Char, CurrentFile->CurrentLine);
fclose(OutputFile);
unlink(OutputFileName);
exit(1);

View File

@ -9,6 +9,10 @@
#include "Defs.h"
#include "Data.h"
#if defined(__GNUC__) || defined(APPLE)
#include <errno.h>
#endif
/*
* The Precedence of an operator is directly related to Token Type.
* Precedence determines how soon the operator and its surrounding values
@ -16,17 +20,17 @@
* This allows for things like the common Order of Operations.
*/
static int Precedence[] = {
0, 10, // EOF, ASSIGN
20, 30, // || &&
40, 50, // | ^
60, 70, // & =?
70, 80, // != <
80, 80, // > <=
80, 90, // => <<
90, 100, // >> +
0, 10, // EOF, ASSIGN
20, 30, // || &&
40, 50, // | ^
60, 70, // & =?
70, 80, // != <
80, 80, // > <=
80, 90, // => <<
90, 100, // >> +
100, 110, // - *
110 // /
};
};
/*
* Handles gathering the precedence of an operator from its token,
@ -38,8 +42,14 @@ static int Precedence[] = {
static int OperatorPrecedence(int Token) {
int Prec = Precedence[Token];
if(Prec == 0 || Token >= PPMM_PLUS) {
DieMessage("Attempting to determine operator precedence of an EOF or INT literal", TokenNames[Token]);
if (Prec == 0 || Token >= PPMM_PLUS) {
if (Token == TY_IDENTIFIER) {
ErrorReport("Attempting to determine operator precedence of identifier %s\n", CurrentIdentifier);
exit(1);
}
ErrorReport("Attempting to determine operator precedence of an EOF or INT literal: %s\n", TokenNames[Token]);
exit(1);
}
return Prec;
@ -53,7 +63,7 @@ static int OperatorPrecedence(int Token) {
*/
static int IsRightExpr(int Token) {
return (Token == LI_EQUAL);
return (Token == LI_EQUAL);
}
/* * * * * * * * * * * * * * * * * * * * * * * *
@ -89,13 +99,13 @@ struct ASTNode* ConstructASTNode(int Operation, int Type,
struct ASTNode* Right,
struct SymbolTableEntry* Symbol,
int IntValue) {
struct ASTNode* Node;
Node = (struct ASTNode*) malloc(sizeof(struct ASTNode));
if(!Node)
Die("Unable to allocate node!");
if (!Node)
ErrorReport("Unable to allocate node: %s\n", errno);
Node->Operation = Operation;
@ -149,10 +159,10 @@ struct ASTNode* ConstructASTBranch(int Operation, int Type, struct ASTNode* Left
*/
int ParseTokenToOperation(int Token) {
if(Token > LI_EOF && Token < LI_INT)
if (Token > LI_EOF && Token < LI_INT)
return Token;
DieDecimal("ParseToken: Unknown token", Token);
ErrorReport("ParseToken: Unknown token %s\n", TokenNames[Token]);
}
/*
@ -169,18 +179,18 @@ struct ASTNode* ParsePrimary(void) {
struct ASTNode* Node;
int ID;
switch(CurrentToken.type) {
switch (CurrentFile->CurrentSymbol.type) {
case LI_INT:
if((CurrentToken.value >= 0) && (CurrentToken.value < 256))
Node = ConstructASTLeaf(TERM_INTLITERAL, RET_CHAR, NULL, CurrentToken.value);
else
Node = ConstructASTLeaf(TERM_INTLITERAL, RET_INT, NULL, CurrentToken.value);
if ((CurrentFile->CurrentSymbol.value >= 0) && (CurrentFile->CurrentSymbol.value < 256))
Node = ConstructASTLeaf(TERM_INTLITERAL, RET_CHAR, NULL, CurrentFile->CurrentSymbol.value);
else
Node = ConstructASTLeaf(TERM_INTLITERAL, RET_INT, NULL, CurrentFile->CurrentSymbol.value);
break;
case LI_STR:
ID = AsNewString(CurrentIdentifier);
ID = Assembler->vtable->AsNewString(CurrentIdentifier);
Node = ConstructASTLeaf(TERM_STRLITERAL, PointerTo(RET_CHAR), NULL, ID);
break;
@ -198,9 +208,8 @@ struct ASTNode* ParsePrimary(void) {
return Node;
}
Tokenise();
Safe();
return Node;
}
@ -211,7 +220,7 @@ struct ASTNode* ParsePrimary(void) {
* the order of operations is upheld, that the precedence of the prior
* iteration is considered, and that every error is handled.
*
* This is where all of the right-associative statements are folded, where
* This is where all the right-associative statements are folded, where
* type mismatches and widening are handled properly, and that all parsing
* is over by the time the end tokens ") } ] ;" are encountered.
*
@ -220,27 +229,34 @@ struct ASTNode* ParsePrimary(void) {
*
*/
struct ASTNode* ParsePrecedenceASTNode(int PreviousTokenPrecedence) {
struct ASTNode* LeftNode, *RightNode;
struct ASTNode* LeftTemp, *RightTemp;
struct ASTNode* LeftNode, * RightNode;
struct ASTNode* LeftTemp, * RightTemp;
// int LeftType, RightType;
int NodeType, OpType;
Safe();
LeftNode = PrefixStatement();
NodeType = CurrentToken.type;
NodeType = CurrentFile->CurrentSymbol.type;
if(NodeType == LI_SEMIC || NodeType == LI_RPARE || NodeType == LI_RBRAS || NodeType == LI_COM) {
LeftNode->RVal = 1; return LeftNode;
if (NodeType == LI_SEMIC || NodeType == LI_COLON || NodeType == LI_RPARE || NodeType == LI_RBRAS || NodeType == LI_COM || NodeType == LI_INT) {
LeftNode->RVal = 1;
return LeftNode;
}
while((OperatorPrecedence(NodeType) > PreviousTokenPrecedence) || (IsRightExpr(OpType) && OperatorPrecedence(OpType) == PreviousTokenPrecedence)) {
Safe();
while ((OperatorPrecedence(NodeType) > PreviousTokenPrecedence) ||
(IsRightExpr(OpType) && OperatorPrecedence(OpType) == PreviousTokenPrecedence)) {
Tokenise();
if(CurrentToken.type == LI_RPARE)
if (CurrentFile->CurrentSymbol.type == LI_RPARE)
break;
Safe();
RightNode = ParsePrecedenceASTNode(Precedence[NodeType]);
Safe();
/**
* While parsing this node, we may need to widen some types.
* This requires a few functions and checks.
@ -248,14 +264,14 @@ struct ASTNode* ParsePrecedenceASTNode(int PreviousTokenPrecedence) {
OpType = ParseTokenToOperation(NodeType);
if(OpType == OP_ASSIGN) {
if (OpType == OP_ASSIGN) {
printf("\tParsePrecedenceASTNode: Assignment statement\r\n");
RightNode->RVal = 1;
LeftNode->RVal = 0;
RightNode = MutateType(RightNode, LeftNode->ExprType, 0);
if(LeftNode == NULL)
Die("Incompatible Expression encountered in assignment");
if (RightNode == NULL)
ErrorReport("Incompatible types encountered in assignment: %s, %s\n", TypeNames(RightNode->ExprType), TypeNames(LeftNode->ExprType));
// LeftNode holds the target, the target variable in this case
printf("\t\tAssigning variable: %s\n", LeftNode->Symbol->Name);
@ -263,12 +279,12 @@ struct ASTNode* ParsePrecedenceASTNode(int PreviousTokenPrecedence) {
LeftTemp = LeftNode;
LeftNode = RightNode;
RightNode = LeftTemp;
// Clear temps as ensurance
// Clear temps as insurance
RightTemp = NULL;
LeftTemp = NULL;
} else {
printf("\t\tAttempting to handle a %d in Binary Expression parsing\r\n", CurrentToken.type);
printf("\t\tAttempting to handle a %s in Binary Expression parsing\r\n", TokenNames[CurrentFile->CurrentSymbol.type]);
LeftNode->RVal = 1;
RightNode->RVal = 1;
@ -279,18 +295,19 @@ struct ASTNode* ParsePrecedenceASTNode(int PreviousTokenPrecedence) {
* If both are null, the types are incompatible.
*/
if(LeftTemp == NULL && RightTemp == NULL)
Die("Incompatible types in parsing nodes");
if (LeftTemp == NULL && RightTemp == NULL)
ErrorReport("Incompatible types in parsing nodes: %s, %s\n", TypeNames(LeftNode->ExprType), TypeNames(RightNode->ExprType));
/**
* If the left was valid, or valid for
* If the left was valid, or valid for
* expansion, then it will be non-null.
*
* If it was valid, then this will be
*
* If it was valid, then this will be
* equivalent to LeftNode = LeftNode
*/
if(LeftTemp)
if (LeftTemp != NULL)
LeftNode = LeftTemp;
/**
@ -299,26 +316,19 @@ struct ASTNode* ParsePrecedenceASTNode(int PreviousTokenPrecedence) {
* to the nature of widening types.
*/
if(RightTemp)
if (RightTemp != NULL)
RightNode = RightTemp;
}
/**
* Checks over, back to normal parsing.
*/
if(LeftTemp != NULL)
LeftNode = LeftTemp; //ConstructASTBranch(LeftType, RightNode->ExprType, LeftNode, 0);
if(RightTemp != NULL)
RightNode = RightTemp; // ConstructASTBranch(RightType, LeftNode->ExprType, RightNode, 0);
LeftNode = ConstructASTNode(ParseTokenToOperation(NodeType), LeftNode->ExprType, LeftNode, NULL, RightNode, NULL, 0);
NodeType = CurrentToken.type;
if(NodeType == LI_SEMIC || NodeType == LI_RPARE || NodeType == LI_RBRAS) {
LeftNode = ConstructASTNode(ParseTokenToOperation(NodeType), LeftNode->ExprType, LeftNode, NULL, RightNode,
NULL, 0);
NodeType = CurrentFile->CurrentSymbol.type;
if (NodeType == LI_SEMIC || NodeType == LI_RPARE || NodeType == LI_RBRAS) {
LeftNode->RVal = 1;
return LeftNode;
}
}
LeftNode->RVal = 1;
return LeftNode;
@ -345,12 +355,12 @@ struct ASTNode* CallFunction() {
struct SymbolTableEntry* Function;
//TODO: Test structural type!
if((Function = FindSymbol(CurrentIdentifier)) == NULL || (Function->Structure != ST_FUNC))
DieMessage("Undeclared function", CurrentIdentifier);
if ((Function = FindSymbol(CurrentIdentifier)) == NULL || (Function->Structure != ST_FUNC))
ErrorReport("Undeclared function: %s\n", CurrentIdentifier);
VerifyToken(LI_LPARE, "(");
Tree = GetExpressionList();
Tree = ParseExpressionList(LI_RPARE);
Tree = ConstructASTBranch(OP_CALL, Function->Type, Tree, Function, 0);
@ -374,25 +384,23 @@ struct ASTNode* CallFunction() {
* end with a COMPOSITE operation.
*
*/
struct ASTNode* GetExpressionList() {
struct ASTNode* Tree = NULL, *Child = NULL;
int Count;
struct ASTNode* ParseExpressionList(int terminate) {
struct ASTNode* Tree = NULL, * Child = NULL;
int Count = 0;
while(CurrentToken.type != LI_RPARE) {
Safe();
while (CurrentFile->CurrentSymbol.type != terminate) {
// TODO: for(int x = 0;
Child = ParsePrecedenceASTNode(0);
printf("\nFunction parameter %d is type %s.\n", Count, TypeNames(Child->ExprType));
Count++;
Tree = ConstructASTNode(OP_COMP, PointerTo(RET_VOID), Tree, NULL, Child, NULL, Count);
switch(CurrentToken.type) {
case LI_COM:
Tokenise();
break;
case LI_RPARE:
break;
default:
Die("Unexpected token in argument list");
}
if (CurrentFile->CurrentSymbol.type == terminate)
break;
VerifyToken(LI_COM, ",");
Safe();
}
return Tree;
@ -405,95 +413,79 @@ struct ASTNode* GetExpressionList() {
/*
* Handles parsing an individual statement.
* This has the ability to parse Compounds in the case it starts with a left brace.
* This solves the dangling else problem for the parser.
*
* It serves as a wrapper around:
* * If Statement
* * While Statement
* * For Statement
* * Switch Statement
* * Return Statement
* * Numeric literals and variables
* * Binary Expressions
*
* @return the AST Node representing this single statement
*/
struct ASTNode* ParseStatement(void) {
int Type;
printf("\t\tBranch leads to here, type %s/%d\r\n", TokenNames[CurrentToken.type], CurrentToken.type);
switch(CurrentToken.type) {
struct ASTNode* Node;
struct SymbolTableEntry* Composite;
printf("\t\tBranch leads to type %s/%d\r\n", TokenNames[CurrentFile->CurrentSymbol.type], CurrentFile->CurrentSymbol.type);
switch (CurrentFile->CurrentSymbol.type) {
case LI_LBRAC:
Tokenise();
Node = ParseCompound();
VerifyToken(LI_RBRAC, "}");
return Node;
case TY_IDENTIFIER:
if (FindAlias(CurrentIdentifier) == NULL) {
Node = ParsePrecedenceASTNode(0);
VerifyToken(LI_SEMIC, ";");
return Node;
}
case TY_CHAR:
case TY_LONG:
case TY_INT:
printf("\t\tNew Variable: %s\n", CurrentIdentifier);
Type = ParseOptionalPointer(NULL);
VerifyToken(TY_IDENTIFIER, "ident");
BeginVariableDeclaration(Type, NULL, SC_LOCAL);
VerifyToken(LI_SEMIC, ";"); // TODO: single line assignment?
case KW_STRUCT:
case KW_UNION:
case KW_ENUM:
case KW_ALIAS:
printf("\t\tTrying new Variable: %s\n", CurrentIdentifier);
ParseDeclarationList(&Composite, SC_LOCAL, LI_SEMIC, LI_EOF, &Node);
VerifyToken(LI_SEMIC, ";");
Safe();
return NULL;
case KW_SWITCH:
return SwitchStatement();
case KW_IF:
return IfStatement();
case KW_WHILE:
return WhileStatement();
case KW_FOR:
return ForStatement();
case KW_RETURN:
return ReturnStatement();
case KW_BREAK:
return BreakStatement();
case KW_CONTINUE:
return ContinueStatement();
default:
ParsePrecedenceASTNode(0);
}
}
/*
* Handles parsing multiple statements or expressions in a row.
* These are typically grouped together with the Compound tokens "{ }"
* and seperated by the semicolon ";".
*
* Single Statements are parsed until a semicolon is reached, at which
* point another statement will be parsed, or until a Right Compound
* token is reached ("}"), at which point parsing will stop.
*
* It is useful for:
* * Tightly identifying related blocks of code
* * Containing the many statements of functions
*
* @return the AST Node representing this compound statement
*
*/
struct ASTNode* ParseCompound() {
struct ASTNode* Left = NULL, *Tree;
// Compound statements are defined by comprising
// multiple statements inside { a bracket block }
VerifyToken(LI_LBRAC, "{");
while(1) {
printf("\tNew branch in compound\n");
Tree = ParseStatement();
if(Tree && (Tree->Operation == OP_PRINT || Tree->Operation == OP_ASSIGN
|| Tree->Operation == OP_RET || Tree->Operation == OP_CALL))
Node = ParsePrecedenceASTNode(0);
VerifyToken(LI_SEMIC, ";");
if(Tree) {
if(Left == NULL)
Left = Tree;
else
Left = ConstructASTNode(OP_COMP, RET_NONE, Left, NULL, Tree, NULL, 0);
}
if(CurrentToken.type == LI_RBRAC) {
VerifyToken(LI_RBRAC, "}");
return Left;
}
return Node;
}
}
/*
* This is the entry point to the parser/lexer.
*
@ -510,42 +502,16 @@ struct ASTNode* ParseCompound() {
*/
void ParseGlobals() {
struct ASTNode* Tree;
int Type, FunctionComing;
struct SymbolTableEntry* Composite;
struct ASTNode* empty;
printf("Parsing global definitions\r\n");
while(1) {
printf("New definition incoming..\r\n\n");
Type = ParseOptionalPointer(NULL);
while (CurrentFile->CurrentSymbol.type != LI_EOF) {
// Read in a declaration, or list thereof
ParseDeclarationList(&Composite, SC_GLOBAL, LI_SEMIC, LI_EOF, &empty);
//TODO: converge pathways on this block?
if(CurrentToken.type == KW_FUNC) {
VerifyToken(KW_FUNC, "::");
FunctionComing = 1;
}
VerifyToken(TY_IDENTIFIER, "ident");
if(FunctionComing && CurrentToken.type == LI_LPARE) {
printf("\tParsing function");
Tree = ParseFunction(Type);
if(Tree) {
printf("\nBeginning assembler creation of new function %s\n", Tree->Symbol->Name);
AssembleTree(Tree, -1, 0);
FreeLocals();
} else {
printf("\nFunction prototype saved\r\n");
}
} else {
printf("\tParsing global variable declaration\n");
BeginVariableDeclaration(Type, NULL, SC_GLOBAL);
VerifyToken(LI_SEMIC, ";");
}
if(CurrentToken.type == LI_EOF)
break;
// Consume semicolons if present
OptionallyConsume(LI_SEMIC);
}
}

View File

@ -36,8 +36,8 @@
*/
int PointerTo(int Type) {
if((Type & 0xf) == 0xf)
DieDecimal("Unrecognized type in pointerisation", Type);
if ((Type & 0xf) == 0xf)
ErrorReport("Unrecognized type in pointerisation: %d\n", Type);
printf("\t\tPointerising a %s\n", TypeNames(Type));
return (Type + 1);
}
@ -52,71 +52,11 @@ int PointerTo(int Type) {
int ValueAt(int Type) {
printf("\t\tDereferencing a %s\n", TypeNames(Type));
if((Type & 0xf) == 0x0)
DieDecimal("Unrecognized type in defererencing", Type);
if ((Type & 0xf) == 0x0)
ErrorReport("Unrecognized type in defererencing: %d (%s)\n", Type, TypeNames(Type));
return (Type - 1);
}
/*
* Type declarations may be raw, they may be pointers.
* If they are pointers, we need to be able to check
* how many levels of indirection.
* However, being a pointer is optional.
*
* This can parase in just a lone type specifier, or
* any valid level of indirection therefore.
*
* @param Composite: unused
* @return the parsed DataType, with any indirection.
*
*/
int ParseOptionalPointer(struct SymbolTableEntry** Composite) {
int Type;
switch(CurrentToken.type) {
case TY_VOID:
Type = RET_VOID;
Tokenise();
break;
case TY_CHAR:
Type = RET_CHAR;
Tokenise();
break;
case TY_INT:
Type = RET_INT;
Tokenise();
break;
case TY_LONG:
Type = RET_LONG;
Tokenise();
break;
case KW_STRUCT:
Type = DAT_STRUCT;
*Composite = BeginStructDeclaration();
break;
default:
DieDecimal("Illegal type for pointerisation", CurrentToken.type);
}
// Recursively scan more *s
// This makes things like:
// x = **y;
// possible.
while(1) {
Tokenise();
printf("\t\t\tType on parsing is %d\n", CurrentToken.type);
if(CurrentToken.type != AR_STAR)
break;
Type = PointerTo(Type);
// Tokenise(); TODO: is this skipping pointers?
}
return Type;
}
/*
* Array Accesses come in the form of x[y].
*
@ -129,13 +69,13 @@ int ParseOptionalPointer(struct SymbolTableEntry** Composite) {
*/
struct ASTNode* AccessArray() {
struct ASTNode* LeftNode, *RightNode;
struct ASTNode* LeftNode, * RightNode;
struct SymbolTableEntry* Entry;
printf("\tAccessing array %s as requested\r\n", CurrentIdentifier);
if ((Entry = FindSymbol(CurrentIdentifier)) == NULL || Entry->Structure != ST_ARR)
DieMessage("Accessing undeclared array", CurrentIdentifier);
ErrorReport("Accessing undeclared array: %s\n", CurrentIdentifier);
LeftNode = ConstructASTLeaf(OP_ADDRESS, Entry->Type, Entry, 0);
Tokenise();
@ -143,15 +83,72 @@ struct ASTNode* AccessArray() {
VerifyToken(LI_RBRAS, "]");
if(!TypeIsInt(RightNode->ExprType))
Die("Array index is not integer");
printf("\t\tPreparing types - RightNode of type %s must be mutated to LeftNode type %s\r\n", (RightNode->ExprType), TypeNames(LeftNode->ExprType));
if (!TypeIsInt(RightNode->ExprType))
ErrorReport("Array index is not integer");
printf("\t\tPreparing types - RightNode of type %s must be mutated to LeftNode type %s\r\n", TypeNames(RightNode->ExprType),
TypeNames(LeftNode->ExprType));
RightNode = MutateType(RightNode, LeftNode->ExprType, OP_ADD);
LeftNode = ConstructASTNode(OP_ADD, Entry->Type, LeftNode, NULL, RightNode, NULL, 0);
printf("\tAccessArray: Preparing LeftNode for dereference.\r\n");
LeftNode = ConstructASTBranch(OP_DEREF, ValueAt(LeftNode->ExprType), LeftNode, NULL, 0);
LeftNode = ConstructASTBranch(OP_DEREF, ValueAt(LeftNode->ExprType), LeftNode, Entry, 0);
printf("\tArray Access constructed\r\n");
return LeftNode;
}
/**
* Members of enums and structs are accessed with x.y or *x->y
*
* x must be enum, struct, or pointer to struct.
* y must be a valid member of any of the above.
*
* It is a wrapper around *((imax*)x + xType.ordinal(y))
*
* @return the AST Node representing this statement.
*/
struct ASTNode* AccessMember(bool Deref) {
struct ASTNode* LeftNode, * RightNode;
struct SymbolTableEntry* CompositeVar, * TypePtr, * Member;
if ((CompositeVar = FindSymbol(CurrentIdentifier)) == NULL)
ErrorReport("Undeclared variable: %s\n", CurrentIdentifier);
if (Deref && (CompositeVar->Type != PointerTo(DAT_STRUCT) && CompositeVar->Type != PointerTo(DAT_UNION)))
ErrorReport("Undeclared struct: %s\n", CurrentIdentifier);
if (!Deref && (CompositeVar->Type != DAT_STRUCT && CompositeVar->Type != DAT_UNION))
ErrorReport("Undeclared struct: %s\n", CurrentIdentifier);
Safe();
if (Deref)
LeftNode = ConstructASTLeaf(REF_IDENT, PointerTo(CompositeVar->Type), CompositeVar, 0);
else
LeftNode = ConstructASTLeaf(OP_ADDRESS, CompositeVar->Type, CompositeVar, 0);
LeftNode->RVal = true;
TypePtr = CompositeVar->CompositeType;
Tokenise();
VerifyToken(TY_IDENTIFIER, "identifier");
for (Member = TypePtr->Start; Member != NULL; Member = Member->NextSymbol) {
printf("\tComparing composite entry %s with the wanted %s. Index %d.\r\n", Member->Name, CurrentIdentifier,
Member->SinkOffset);
if (!strcmp(Member->Name, CurrentIdentifier))
break;
}
if (Member == NULL)
ErrorReport("Invalid composite member: %s\n", CurrentIdentifier);
Safe();
RightNode = ConstructASTLeaf(TERM_INTLITERAL, RET_INT, NULL, Member->SinkOffset);
LeftNode = ConstructASTNode(OP_ADD, PointerTo(Member->Type), LeftNode, NULL, RightNode, NULL, 0);
LeftNode = ConstructASTBranch(OP_DEREF, Member->Type, LeftNode, Member, 0);
return LeftNode;
}

File diff suppressed because it is too large Load Diff

View File

@ -7,8 +7,49 @@
#include <Defs.h>
#include <Data.h>
/**
* Dump all symbol tables to the console.
*/
void DumpAllLists() {
printf("Initiating table dump. Expect lots of spam.\n");
printf("Global symbols:\n");
DumpList(Globals);
printf("\nLocal symbols:\n");
DumpList(Locals);
printf("\nParameters:\n");
if (CurrentFile->FunctionEntry != NULL && CurrentFile->FunctionEntry->Start != NULL)
DumpList(CurrentFile->FunctionEntry->Start);
DumpList(Params);
printf("\nStructs:\n");
DumpList(Structs);
printf("\nComposite Members:\n");
DumpList(CompositeMembers);
printf("\nEnum Members:\n");
DumpList(EnumMembers);
printf("\nUnions:\n");
DumpList(Unions);
printf("\nEnums:\n");
DumpList(Enums);
printf("\nTypes:\n");
DumpList(Types);
printf("\n\nDump over.\n");
}
/**
* Dump all the items in the list.
* Prints their names to stdout, tab separated.
*
* @param List the list to dump
*/
void DumpList(struct SymbolTableEntry* List) {
for (; List != NULL; List = List->NextSymbol)
if ((List->Name != NULL))
printf("%s\t", List->Name);
}
/*
* Find the position of a symbol in a given symbol table.
*
* @param Name: The string name of the symbol
* @param List: The linked list to search in.
* @return the list if found,
@ -16,8 +57,8 @@
*/
static struct SymbolTableEntry* SearchList(char* Name, struct SymbolTableEntry* List) {
for(; List != NULL; List = List->NextSymbol)
if((List->Name != NULL) && !strcmp(Name, List->Name))
for (; List != NULL; List = List->NextSymbol)
if ((List->Name != NULL) && !strcmp(Name, List->Name))
return (List);
return NULL;
}
@ -36,16 +77,17 @@ static struct SymbolTableEntry* SearchList(char* Name, struct SymbolTableEntry*
struct SymbolTableEntry* FindSymbol(char* Symbol) {
struct SymbolTableEntry* Node;
if(CurrentFunction) {
Node = SearchList(Symbol, FunctionEntry->Start);
if(Node)
if (CurrentFile->FunctionEntry) {
Node = SearchList(Symbol, CurrentFile->FunctionEntry->Start);
if (Node)
return Node;
}
Node = SearchList(Symbol, Locals);
if(Node)
if (Node)
return Node;
return SearchList(Symbol, Globals);
}
@ -58,9 +100,9 @@ struct SymbolTableEntry* FindSymbol(char* Symbol) {
struct SymbolTableEntry* FindLocal(char* Symbol) {
struct SymbolTableEntry* Node;
if(FunctionEntry) {
Node = SearchList(Symbol, FunctionEntry->Start);
if(Node)
if (CurrentFile->FunctionEntry) {
Node = SearchList(Symbol, CurrentFile->FunctionEntry->Start);
if (Node)
return Node;
}
@ -89,6 +131,50 @@ struct SymbolTableEntry* FindStruct(char* Symbol) {
return SearchList(Symbol, Structs);
}
/*
* An override for FindSymbol.
* Searches only the defined Enums.
* @param Symbol: The string name of the symbol to search for.
* @return a pointer to the node if found, else NULL
*
*/
struct SymbolTableEntry* FindEnum(char* Symbol) {
return SearchList(Symbol, Enums);
}
/*
* An override for FindSymbol.
* Searches only the defined enum members.
* @param Symbol: The string name of the symbol to search for.
* @return a pointer to the node if found, else NULL
*
*/
struct SymbolTableEntry* FindEnumMember(char* Symbol) {
return SearchList(Symbol, EnumMembers);
}
/*
* An override for FindSymbol.
* Searches only the defined type names.
* @param Symbol: The string name of the symbol to search for.
* @return a pointer to the node if found, else NULL
*
*/
struct SymbolTableEntry* FindAlias(char* Symbol) {
return SearchList(Symbol, Types);
}
/*
* An override for FindSymbol.
* Searches only the defined Unions.
* @param Symbol: The string name of the symbol to search for.
* @return a pointer to the node if found, else NULL
*
*/
struct SymbolTableEntry* FindUnion(char* Symbol) {
return SearchList(Symbol, Unions);
}
/*
* An override for FindSymbol.
* Searches only the defined Struct & Enum Members.
@ -97,7 +183,7 @@ struct SymbolTableEntry* FindStruct(char* Symbol) {
*
*/
struct SymbolTableEntry* FindMember(char* Symbol) {
return SearchList(Symbol, StructMembers);
return SearchList(Symbol, CompositeMembers);
}
/*
@ -113,10 +199,10 @@ struct SymbolTableEntry* FindMember(char* Symbol) {
*
*/
void AppendSymbol(struct SymbolTableEntry** Head, struct SymbolTableEntry** Tail, struct SymbolTableEntry* Node) {
if(Head == NULL || Tail == NULL || Node == NULL)
Die("Not enough data to append a symbol to the tables");
if(*Tail) {
if (Head == NULL || Tail == NULL || Node == NULL)
ErrorReport("Not enough data to append a symbol to the tables. Missing: %s\n", Head == NULL ? "Head" : Tail == NULL ? "Tail" : "Node");
if (*Tail) {
(*Tail)->NextSymbol = Node;
*Tail = Node;
} else {
@ -134,7 +220,7 @@ void AppendSymbol(struct SymbolTableEntry** Head, struct SymbolTableEntry** Tail
void FreeLocals() {
Locals = LocalsEnd = NULL;
Params = ParamsEnd = NULL;
FunctionEntry = NULL;
CurrentFile->FunctionEntry = NULL;
}
@ -145,7 +231,7 @@ void ClearTables() {
Globals = GlobalsEnd = NULL;
Locals = LocalsEnd = NULL;
Params = ParamsEnd = NULL;
StructMembers = StructMembersEnd = NULL;
CompositeMembers = CompositeMembersEnd = NULL;
Structs = StructsEnd = NULL;
}
@ -161,10 +247,11 @@ void ClearTables() {
*
* @return The SymbolTableEntry* pointer that corresponds to this newly constructed node.
*/
struct SymbolTableEntry* AddSymbol(char* Name, int Type, int Structure, int Storage, int Length, int SinkOffset, struct SymbolTableEntry* CompositeType) {
struct SymbolTableEntry* AddSymbol(char* Name, int Type, int Structure, int Storage, int Length, int SinkOffset,
struct SymbolTableEntry* CompositeType) {
struct SymbolTableEntry* Node =
(struct SymbolTableEntry*) malloc(sizeof(struct SymbolTableEntry));
struct SymbolTableEntry* Node =
(struct SymbolTableEntry*) malloc(sizeof(struct SymbolTableEntry));
Node->Name = strdup(Name);
Node->Type = Type;
@ -174,26 +261,44 @@ struct SymbolTableEntry* AddSymbol(char* Name, int Type, int Structure, int Stor
Node->SinkOffset = SinkOffset;
Node->CompositeType = CompositeType;
switch(Storage) {
if (TypeIsPtr(Type) || TypeIsInt(Type))
Node->Size = Length * TypeSize(Type, CompositeType);
printf("Adding a %s symbol of name %s, type %s to the tables.\n", ScopeNames[Node->Storage], Node->Name,
TypeNames(Node->Type));
switch (Storage) {
case SC_GLOBAL:
AppendSymbol(&Globals, &GlobalsEnd, Node);
// We don't want to generate a static block for functions.
if(Structure != ST_FUNC) AsGlobalSymbol(Node);
if (Structure != ST_FUNC) Assembler->vtable->AsGlobalSymbol(Node);
break;
case SC_STRUCT:
AppendSymbol(&Structs, &StructsEnd, Node);
break;
case SC_UNION:
AppendSymbol(&Unions, &UnionsEnd, Node);
break;
case SC_ENUM:
AppendSymbol(&Enums, &EnumsEnd, Node);
break;
case SC_ALIAS:
AppendSymbol(&Types, &TypesEnd, Node);
break;
case SC_ENUMENTRY:
AppendSymbol(&EnumMembers, &EnumMembersEnd, Node);
break;
case SC_MEMBER:
AppendSymbol(&StructMembers, &StructMembersEnd, Node);
AppendSymbol(&CompositeMembers, &CompositeMembersEnd, Node);
break;
case SC_LOCAL:
AppendSymbol(&Locals, &LocalsEnd, Node);
break;
case SC_PARAM:
AppendSymbol(&Params, &ParamsEnd, Node);
break;
}
return Node;
}

View File

@ -17,7 +17,8 @@
*/
int TypeIsInt(int Type) {
return ((Type & 0xf) == 0);
printf("\tComparing type %s.\n", TypeNames(Type));
return ( ((Type & 0xf) == 0) && (Type >= RET_CHAR && Type <= RET_LONG));
}
/*
@ -41,14 +42,16 @@ int TypeIsPtr(int Type) {
*/
int PrimitiveSize(int Type) {
if(TypeIsPtr(Type)) return 8;
switch(Type) {
case RET_CHAR: return 1;
case RET_INT: return 4;
case RET_LONG: return 8;
default:
DieDecimal("Bad type in PrimitiveSize", Type);
if (TypeIsPtr(Type)) return 8;
switch (Type) {
case RET_CHAR:
return 1;
case RET_INT:
return 4;
case RET_LONG:
return 8;
default:
ErrorReport("Bad type in PrimitiveSize: %s\n", TypeNames(Type));
}
return 0;
}
@ -61,7 +64,7 @@ int PrimitiveSize(int Type) {
*/
int TypeSize(int Type, struct SymbolTableEntry* Composite) {
if(Type == DAT_STRUCT) return Composite->Length;
if (Type == DAT_STRUCT || Type == DAT_UNION) return Composite->Length;
return PrimitiveSize(Type);
}
@ -76,17 +79,26 @@ static char TypeBuffer[7];
* Get the name of the input Type as a string.
*/
char* TypeNames(int Type) {
switch(Type) {
case RET_CHAR: memcpy(TypeBuffer, "Char", 4); break;
case RET_INT: memcpy(TypeBuffer, "Int ", 4); break;
case RET_LONG: memcpy(TypeBuffer, "Long", 4); break;
case RET_VOID: memcpy(TypeBuffer, "Void", 4); break;
default: DieDecimal("Bad size for printing", Type);
switch (Type) {
case RET_CHAR:
memcpy(TypeBuffer, "Char", 4);
break;
case RET_INT:
memcpy(TypeBuffer, "Int ", 4);
break;
case RET_LONG:
memcpy(TypeBuffer, "Long", 4);
break;
case RET_VOID:
memcpy(TypeBuffer, "Void", 4);
break;
default:
break;
};
if(TypeIsPtr(Type)) memcpy((void*)((size_t) TypeBuffer + 4), "Ptr", 3);
else memcpy((void*)((size_t) TypeBuffer + 4), " ", 3);
if (TypeIsPtr(Type)) memcpy((void*) ((size_t) TypeBuffer + 4), "Ptr", 3);
else memcpy((void*) ((size_t) TypeBuffer + 4), "\0", 1);
return TypeBuffer;
}
/*
@ -104,7 +116,7 @@ int TypesCompatible(int* Left, int* Right, int STRICT) {
int LeftSize, RightSize;
// Same types are compatible. No shrinking required
if(*Left == *Right) {
if (*Left == *Right) {
*Left = *Right = 0;
return 1;
}
@ -114,7 +126,7 @@ int TypesCompatible(int* Left, int* Right, int STRICT) {
// Types of size 0 are incompatible
if((LeftSize == 0) || (RightSize == 0))
if ((LeftSize == 0) || (RightSize == 0))
return 0;
@ -126,7 +138,7 @@ int TypesCompatible(int* Left, int* Right, int STRICT) {
* x needs to be widened, y copied in, then x shrunk back down
* AKA, the left must be widened.
*/
if(LeftSize < RightSize) {
if (LeftSize < RightSize) {
*Left = OP_WIDEN;
*Right = 0;
return 1;
@ -145,10 +157,10 @@ int TypesCompatible(int* Left, int* Right, int STRICT) {
*
*/
if(LeftSize > RightSize) {
if(STRICT)
if (LeftSize > RightSize) {
if (STRICT)
return 0; // Not compatible if STRICT
*Left = 0;
*Right = OP_WIDEN;
return 1; // Compatible by default
@ -190,11 +202,11 @@ struct ASTNode* MutateType(struct ASTNode* Tree, int RightType, int Operation) {
LeftType = Tree->ExprType;
printf("\tCalculating compatibility between ltype %d and rtype %d\r\n", LeftType, RightType);
if(TypeIsInt(LeftType) && TypeIsInt(RightType)) {
printf("\tCalculating compatibility between ltype %s and rtype %s\r\n", TypeNames(LeftType), TypeNames(RightType));
if (TypeIsInt(LeftType) && TypeIsInt(RightType)) {
// Short-circuit for valid types
if(LeftType == RightType) {
if (LeftType == RightType) {
return Tree;
}
@ -208,7 +220,7 @@ struct ASTNode* MutateType(struct ASTNode* Tree, int RightType, int Operation) {
* (The left branch of the tree contains the current AST)
*
*/
if(LeftSize > RightSize)
if (LeftSize > RightSize)
return NULL;
/**
@ -220,19 +232,19 @@ struct ASTNode* MutateType(struct ASTNode* Tree, int RightType, int Operation) {
* BUT it is possible!
*/
if(RightSize > LeftSize)
if (RightSize > LeftSize)
return ConstructASTBranch(OP_WIDEN, RightType, Tree, NULL, 0);
}
// Left branch pointers are compatible if we're not doing operations
if(TypeIsPtr(LeftType)) {
if(Operation == 0 && LeftType == RightType)
if (TypeIsPtr(LeftType)) {
if (Operation == 0 && LeftType == RightType)
return Tree;
}
// Otherwise, we can perform some scaling for pointer addition & subtraction
if(Operation == OP_ADD || Operation == OP_SUBTRACT) {
if (Operation == OP_ADD || Operation == OP_SUBTRACT) {
/**
* Left int, right pointer:
@ -242,11 +254,11 @@ struct ASTNode* MutateType(struct ASTNode* Tree, int RightType, int Operation) {
* x = *(y + 1);
*/
if(TypeIsInt(LeftType) && TypeIsPtr(RightType)) {
if (TypeIsInt(LeftType) && TypeIsPtr(RightType)) {
printf("\t\t\tMutateType: Right node needs adjustment\r\n");
RightSize = PrimitiveSize(ValueAt(RightType));
if(RightSize > 1)
if (RightSize > 1)
return ConstructASTBranch(OP_SCALE, RightType, Tree, NULL, RightSize);
}
}

View File

@ -0,0 +1,40 @@
/*************/
/*GEMWIRE */
/* ERYTHRO*/
/*************/
#include <Defs.h>
#include <Data.h>
#define MODULES_SIZE 4
struct AssemblerModule* modules[MODULES_SIZE];
static int moduleID = 0;
void RegisterAllModules() {
RegisterWin32ASM();
RegisterLinuxASM();
RegisterQBE();
RegisterJVM();
for (size_t i = 0; i < moduleID; i++) {
if (strcmp(modules[i]->name, OptAssemblerName) == 0) {
Assembler = modules[i];
break;
}
}
if (Assembler == NULL) {
DieMessage("Unable to find an Assembler for ", OptAssemblerName);
} else {
printf("Using %s assembler.\r\n", OptAssemblerName);
}
}
int RegisterModule(struct AssemblerModule* mod) {
printf("Registering Assembler Module for %s output.\r\n", mod->name);
modules[moduleID] = mod;
moduleID++;
return 0;
}

180
src/assemble/JVMAssembler.c Normal file
View File

@ -0,0 +1,180 @@
/*************/
/*GEMWIRE */
/* ERYTHRO*/
/*************/
#include "Defs.h"
#include "Data.h"
#define AGGREGATE(x) ":##x"
#define GLOBAL(x) "$##x"
#define TEMPORARY(x) "%##x"
#define LABEL(x) "@##x"
/* * * * * * * * * * * * * * * * * * * * * * * * * * * *
* * * * R O O T O F A S S E M B L E R * * * *
* * * * * * * * * * * * * * * * * * * * * * * * * * * */
// Just a short "hack" to make sure we only dump the tree the first time this function is called
static int Started = 0;
/*
* Walk the AST tree given, and generate the assembly code that represents
* it.
*
* @param Node: The current Node to compile. If needed, its children will be parsed recursively.
* @param Register: The index of Registers to store the result of the current compilation.
* @param ParentOp: The Operation of the parent of the current Node.
*
* @return dependant on the Node. Typically the Register that stores the result of the Node's operation.
*
*/
static int AssembleTree(struct ASTNode* Node, int Register, int LoopBeginLabel, int LoopEndLabel, int ParentOp) {
int LeftVal, RightVal;
if (!Started && OptDumpTree)
DumpTree(Node, 0);
Started = 1;
printf("Current operation: %d\r\n", Node->Operation);
switch (Node->Operation) {
case OP_IF:
case OP_LOOP:
case OP_COMP:
case OP_CALL:
case OP_FUNC:
break;
}
if (Node->Left)
LeftVal = AssembleTree(Node->Left, -1, LoopBeginLabel, LoopEndLabel, Node->Operation);
if (Node->Right)
RightVal = AssembleTree(Node->Right, LeftVal, LoopBeginLabel, LoopEndLabel, Node->Operation);
switch (Node->Operation) {
case OP_ADD:
case OP_SUBTRACT:
case OP_MULTIPLY:
case OP_DIVIDE:
case OP_SCALE:
switch (Node->Size) {
case 2:
case 4:
case 8:
default:
break;
}
case OP_BREAK:
case OP_CONTINUE:
case OP_ADDRESS:
case OP_DEREF:
case OP_ASSIGN:
printf("Preparing for assignment..\r\n");
if (Node->Right == NULL)
Die("Fault in assigning a null rvalue");
printf("\tCalculating assignment for target %s:\r\n", Node->Right->Symbol->Name);
switch (Node->Right->Operation) {
case REF_IDENT:
if (Node->Right->Symbol->Storage == SC_LOCAL) (void)0;
case OP_DEREF:
default:
ErrorReport("Can't ASSIGN in AssembleTree: %s", OperationNames[Node->Operation]);
}; return 0;
case OP_WIDEN:
case OP_RET:
case OP_EQUAL:
case OP_INEQ:
case OP_LESS:
case OP_GREAT:
case OP_LESSE:
case OP_GREATE:
if (ParentOp == OP_IF || ParentOp == OP_LOOP) (void)0;
case REF_IDENT:
if (TypeIsPtr(Node->ExprType)) {
}
if (Node->RVal || ParentOp == OP_DEREF) {
if (Node->Symbol->Storage == SC_LOCAL || Node->Symbol->Storage == SC_PARAM) (void)0;
} else
return -1;
case TERM_INTLITERAL:
case TERM_STRLITERAL:
case OP_PRINT:
case OP_BITAND:
case OP_BITOR:
case OP_BITXOR:
case OP_SHIFTL:
case OP_SHIFTR:
case OP_POSTINC:
if (Node->Symbol->Storage == SC_LOCAL || Node->Symbol->Storage == SC_PARAM) (void)0;
case OP_POSTDEC:
if (Node->Symbol->Storage == SC_LOCAL || Node->Symbol->Storage == SC_PARAM) (void)0;
case OP_PREINC:
if (Node->Symbol->Storage == SC_LOCAL || Node->Symbol->Storage == SC_PARAM) (void)0;
case OP_PREDEC:
if (Node->Symbol->Storage == SC_LOCAL || Node->Symbol->Storage == SC_PARAM) (void)0;
case OP_BOOLNOT:
case OP_BITNOT:
case OP_NEGATE:
case OP_BOOLCONV:
return 0;
default:
DieDecimal("Unknown ASM Operation", Node->Operation);
return 0;
}
}
static const struct AssemblerVtable JVMAssemblerVtable = {
.AssembleTree = AssembleTree
};
static const struct AssemblerModule JVMAssemblerModule = {
.name = "JVM",
.vtable = &JVMAssemblerVtable
};
void RegisterJVM() {
RegisterModule(&JVMAssemblerModule);
}

File diff suppressed because it is too large Load Diff

180
src/assemble/QBEAssembler.c Normal file
View File

@ -0,0 +1,180 @@
/*************/
/*GEMWIRE */
/* ERYTHRO*/
/*************/
#include "Defs.h"
#include "Data.h"
#define AGGREGATE(x) ":##x"
#define GLOBAL(x) "$##x"
#define TEMPORARY(x) "%##x"
#define LABEL(x) "@##x"
/* * * * * * * * * * * * * * * * * * * * * * * * * * * *
* * * * R O O T O F A S S E M B L E R * * * *
* * * * * * * * * * * * * * * * * * * * * * * * * * * */
// Just a short "hack" to make sure we only dump the tree the first time this function is called
static int Started = 0;
/*
* Walk the AST tree given, and generate the assembly code that represents
* it.
*
* @param Node: The current Node to compile. If needed, its children will be parsed recursively.
* @param Register: The index of Registers to store the result of the current compilation.
* @param ParentOp: The Operation of the parent of the current Node.
*
* @return dependant on the Node. Typically the Register that stores the result of the Node's operation.
*
*/
static int AssembleTree(struct ASTNode* Node, int Register, int LoopBeginLabel, int LoopEndLabel, int ParentOp) {
int LeftVal, RightVal;
if (!Started && OptDumpTree)
DumpTree(Node, 0);
Started = 1;
printf("Current operation: %d\r\n", Node->Operation);
switch (Node->Operation) {
case OP_IF:
case OP_LOOP:
case OP_COMP:
case OP_CALL:
case OP_FUNC:
break;
}
if (Node->Left)
LeftVal = AssembleTree(Node->Left, -1, LoopBeginLabel, LoopEndLabel, Node->Operation);
if (Node->Right)
RightVal = AssembleTree(Node->Right, LeftVal, LoopBeginLabel, LoopEndLabel, Node->Operation);
switch (Node->Operation) {
case OP_ADD:
case OP_SUBTRACT:
case OP_MULTIPLY:
case OP_DIVIDE:
case OP_SCALE:
switch (Node->Size) {
case 2:
case 4:
case 8:
default:
break;
}
case OP_BREAK:
case OP_CONTINUE:
case OP_ADDRESS:
case OP_DEREF:
case OP_ASSIGN:
printf("Preparing for assignment..\r\n");
if (Node->Right == NULL)
Die("Fault in assigning a null rvalue");
printf("\tCalculating assignment for target %s:\r\n", Node->Right->Symbol->Name);
switch (Node->Right->Operation) {
case REF_IDENT:
if (Node->Right->Symbol->Storage == SC_LOCAL) (void)0;
case OP_DEREF:
default:
DieDecimal("Can't ASSIGN in AssembleTree: ", Node->Operation);
}; return 0;
case OP_WIDEN:
case OP_RET:
case OP_EQUAL:
case OP_INEQ:
case OP_LESS:
case OP_GREAT:
case OP_LESSE:
case OP_GREATE:
if (ParentOp == OP_IF || ParentOp == OP_LOOP) (void)0;
case REF_IDENT:
if (TypeIsPtr(Node->ExprType)) {
}
if (Node->RVal || ParentOp == OP_DEREF) {
if (Node->Symbol->Storage == SC_LOCAL || Node->Symbol->Storage == SC_PARAM) (void)0;
} else
return -1;
case TERM_INTLITERAL:
case TERM_STRLITERAL:
case OP_PRINT:
case OP_BITAND:
case OP_BITOR:
case OP_BITXOR:
case OP_SHIFTL:
case OP_SHIFTR:
case OP_POSTINC:
if (Node->Symbol->Storage == SC_LOCAL || Node->Symbol->Storage == SC_PARAM) (void)0;
case OP_POSTDEC:
if (Node->Symbol->Storage == SC_LOCAL || Node->Symbol->Storage == SC_PARAM) (void)0;
case OP_PREINC:
if (Node->Symbol->Storage == SC_LOCAL || Node->Symbol->Storage == SC_PARAM) (void)0;
case OP_PREDEC:
if (Node->Symbol->Storage == SC_LOCAL || Node->Symbol->Storage == SC_PARAM) (void)0;
case OP_BOOLNOT:
case OP_BITNOT:
case OP_NEGATE:
case OP_BOOLCONV:
return 0;
default:
DieDecimal("Unknown ASM Operation", Node->Operation);
return 0;
}
}
static const struct AssemblerVtable QBEAssemblerVtable = {
.AssembleTree = AssembleTree
};
static const struct AssemblerModule QBEAssemblerModule = {
.name = "QBE",
.vtable = &QBEAssemblerVtable
};
void RegisterQBE() {
RegisterModule(&QBEAssemblerModule);
}

File diff suppressed because it is too large Load Diff

29
tests/alias.er Normal file
View File

@ -0,0 +1,29 @@
int :: printf(char* format);
alias int water;
water drink;
struct fruit {
int x,
int y
};
alias struct fruit basket;
basket food;
alias basket shop;
shop market;
int :: main() {
drink = 5;
printf("%d\n", drink);
food.x = 10;
food.y = 66;
printf("%d\n", food.y);
market.y = 150;
printf("%d\n", market.y);
return (0);
}

21
tests/breakcontinue.er Normal file
View File

@ -0,0 +1,21 @@
import "tests/import/defs.eh"
int :: main() {
int x;
x = 5;
while (x < 15) {
printf("%d\n", x);
if (x =? 12)
break;
if (x =? 10) {
x = x + 2;
continue;
}
x = x + 1;
}
return (0);
}

6
tests/calls.c Normal file
View File

@ -0,0 +1,6 @@
#include <stdio.h>
int main() {
printf("%d\n", 55);
puts("more sup\n");
}

View File

@ -6,8 +6,8 @@ int :: close(int fd);
char* textbuffer;
int :: main() {
int sourcefile;
int count;
long sourcefile;
long count;
textbuffer = " ";

18
tests/enum.er Normal file
View File

@ -0,0 +1,18 @@
int :: printf(char* format);
enum fruit { apple, pear, shallot };
enum basket {
abc = 15,
def
};
enum basket thing;
enum fruit stuff;
int :: main() {
int temp;
temp = apple + pear + abc;
printf("%d\n", temp);
return (0);
}

View File

@ -0,0 +1,22 @@
#ifndef __FREEGLUT_H__
#define __FREEGLUT_H__
/*
* freeglut.h
*
* The freeglut library include file
*
* 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
* PAWEL W. OLSZTA 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.
*/
#include "freeglut_std.h"
#include "freeglut_ext.h"
/*** END OF FILE ***/
#endif /* __FREEGLUT_H__ */

View File

@ -0,0 +1,271 @@
#ifndef __FREEGLUT_EXT_H__
#define __FREEGLUT_EXT_H__
/*
* freeglut_ext.h
*
* The non-GLUT-compatible extensions to the freeglut library include file
*
* Copyright (c) 1999-2000 Pawel W. Olszta. All Rights Reserved.
* Written by Pawel W. Olszta, <olszta@sourceforge.net>
* Creation date: Thu Dec 2 1999
*
* 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
* PAWEL W. OLSZTA 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.
*/
#ifdef __cplusplus
extern "C" {
#endif
/*
* Additional GLUT Key definitions for the Special key function
*/
#define GLUT_KEY_NUM_LOCK 0x006D
#define GLUT_KEY_BEGIN 0x006E
#define GLUT_KEY_DELETE 0x006F
#define GLUT_KEY_SHIFT_L 0x0070
#define GLUT_KEY_SHIFT_R 0x0071
#define GLUT_KEY_CTRL_L 0x0072
#define GLUT_KEY_CTRL_R 0x0073
#define GLUT_KEY_ALT_L 0x0074
#define GLUT_KEY_ALT_R 0x0075
/*
* GLUT API Extension macro definitions -- behaviour when the user clicks on an "x" to close a window
*/
#define GLUT_ACTION_EXIT 0
#define GLUT_ACTION_GLUTMAINLOOP_RETURNS 1
#define GLUT_ACTION_CONTINUE_EXECUTION 2
/*
* Create a new rendering context when the user opens a new window?
*/
#define GLUT_CREATE_NEW_CONTEXT 0
#define GLUT_USE_CURRENT_CONTEXT 1
/*
* Direct/Indirect rendering context options (has meaning only in Unix/X11)
*/
#define GLUT_FORCE_INDIRECT_CONTEXT 0
#define GLUT_ALLOW_DIRECT_CONTEXT 1
#define GLUT_TRY_DIRECT_CONTEXT 2
#define GLUT_FORCE_DIRECT_CONTEXT 3
/*
* GLUT API Extension macro definitions -- the glutGet parameters
*/
#define GLUT_INIT_STATE 0x007C
#define GLUT_ACTION_ON_WINDOW_CLOSE 0x01F9
#define GLUT_WINDOW_BORDER_WIDTH 0x01FA
#define GLUT_WINDOW_BORDER_HEIGHT 0x01FB
#define GLUT_WINDOW_HEADER_HEIGHT 0x01FB /* Docs say it should always have been GLUT_WINDOW_BORDER_HEIGHT, keep this for backward compatibility */
#define GLUT_VERSION 0x01FC
#define GLUT_RENDERING_CONTEXT 0x01FD
#define GLUT_DIRECT_RENDERING 0x01FE
#define GLUT_FULL_SCREEN 0x01FF
#define GLUT_SKIP_STALE_MOTION_EVENTS 0x0204
#define GLUT_GEOMETRY_VISUALIZE_NORMALS 0x0205
#define GLUT_STROKE_FONT_DRAW_JOIN_DOTS 0x0206 /* Draw dots between line segments of stroke fonts? */
/*
* New tokens for glutInitDisplayMode.
* Only one GLUT_AUXn bit may be used at a time.
* Value 0x0400 is defined in OpenGLUT.
*/
#define GLUT_AUX 0x1000
#define GLUT_AUX1 0x1000
#define GLUT_AUX2 0x2000
#define GLUT_AUX3 0x4000
#define GLUT_AUX4 0x8000
/*
* Context-related flags, see fg_state.c
* Set the requested OpenGL version
*/
#define GLUT_INIT_MAJOR_VERSION 0x0200
#define GLUT_INIT_MINOR_VERSION 0x0201
#define GLUT_INIT_FLAGS 0x0202
#define GLUT_INIT_PROFILE 0x0203
/*
* Flags for glutInitContextFlags, see fg_init.c
*/
#define GLUT_DEBUG 0x0001
#define GLUT_FORWARD_COMPATIBLE 0x0002
/*
* Flags for glutInitContextProfile, see fg_init.c
*/
#define GLUT_CORE_PROFILE 0x0001
#define GLUT_COMPATIBILITY_PROFILE 0x0002
/*
* Process loop function, see fg_main.c
*/
FGAPI void FGAPIENTRY glutMainLoopEvent( void );
FGAPI void FGAPIENTRY glutLeaveMainLoop( void );
FGAPI void FGAPIENTRY glutExit ( void );
/*
* Window management functions, see fg_window.c
*/
FGAPI void FGAPIENTRY glutFullScreenToggle( void );
FGAPI void FGAPIENTRY glutLeaveFullScreen( void );
/*
* Menu functions
*/
FGAPI void FGAPIENTRY glutSetMenuFont( int menuID, void* font );
/*
* Window-specific callback functions, see fg_callbacks.c
*/
FGAPI void FGAPIENTRY glutMouseWheelFunc( void (* callback)( int, int, int, int ) );
FGAPI void FGAPIENTRY glutPositionFunc( void (* callback)( int, int ) );
FGAPI void FGAPIENTRY glutCloseFunc( void (* callback)( void ) );
FGAPI void FGAPIENTRY glutWMCloseFunc( void (* callback)( void ) );
/* And also a destruction callback for menus */
FGAPI void FGAPIENTRY glutMenuDestroyFunc( void (* callback)( void ) );
/*
* State setting and retrieval functions, see fg_state.c
*/
FGAPI void FGAPIENTRY glutSetOption ( GLenum option_flag, int value );
FGAPI int * FGAPIENTRY glutGetModeValues(GLenum mode, int * size);
/* A.Donev: User-data manipulation */
FGAPI void* FGAPIENTRY glutGetWindowData( void );
FGAPI void FGAPIENTRY glutSetWindowData(void* data);
FGAPI void* FGAPIENTRY glutGetMenuData( void );
FGAPI void FGAPIENTRY glutSetMenuData(void* data);
/*
* Font stuff, see fg_font.c
*/
FGAPI int FGAPIENTRY glutBitmapHeight( void* font );
FGAPI GLfloat FGAPIENTRY glutStrokeHeight( void* font );
FGAPI void FGAPIENTRY glutBitmapString( void* font, const unsigned char *string );
FGAPI void FGAPIENTRY glutStrokeString( void* font, const unsigned char *string );
/*
* Geometry functions, see fg_geometry.c
*/
FGAPI void FGAPIENTRY glutWireRhombicDodecahedron( void );
FGAPI void FGAPIENTRY glutSolidRhombicDodecahedron( void );
FGAPI void FGAPIENTRY glutWireSierpinskiSponge ( int num_levels, double offset[3], double scale );
FGAPI void FGAPIENTRY glutSolidSierpinskiSponge ( int num_levels, double offset[3], double scale );
FGAPI void FGAPIENTRY glutWireCylinder( double radius, double height, GLint slices, GLint stacks);
FGAPI void FGAPIENTRY glutSolidCylinder( double radius, double height, GLint slices, GLint stacks);
/*
* Rest of functions for rendering Newell's teaset, found in fg_teapot.c
* NB: front facing polygons have clockwise winding, not counter clockwise
*/
FGAPI void FGAPIENTRY glutWireTeacup( double size );
FGAPI void FGAPIENTRY glutSolidTeacup( double size );
FGAPI void FGAPIENTRY glutWireTeaspoon( double size );
FGAPI void FGAPIENTRY glutSolidTeaspoon( double size );
/*
* Extension functions, see fg_ext.c
*/
typedef void (*GLUTproc)();
FGAPI GLUTproc FGAPIENTRY glutGetProcAddress( const char *procName );
/*
* Multi-touch/multi-pointer extensions
*/
#define GLUT_HAS_MULTI 1
/* TODO: add device_id parameter,
cf. http://sourceforge.net/mailarchive/forum.php?thread_name=20120518071314.GA28061%40perso.beuc.net&forum_name=freeglut-developer */
FGAPI void FGAPIENTRY glutMultiEntryFunc( void (* callback)( int, int ) );
FGAPI void FGAPIENTRY glutMultiButtonFunc( void (* callback)( int, int, int, int, int ) );
FGAPI void FGAPIENTRY glutMultiMotionFunc( void (* callback)( int, int, int ) );
FGAPI void FGAPIENTRY glutMultiPassiveFunc( void (* callback)( int, int, int ) );
/*
* Joystick functions, see fg_joystick.c
*/
/* USE OF THESE FUNCTIONS IS DEPRECATED !!!!! */
/* If you have a serious need for these functions in your application, please either
* contact the "freeglut" developer community at freeglut-developer@lists.sourceforge.net,
* switch to the OpenGLUT library, or else port your joystick functionality over to PLIB's
* "js" library.
*/
int glutJoystickGetNumAxes( int ident );
int glutJoystickGetNumButtons( int ident );
int glutJoystickNotWorking( int ident );
float glutJoystickGetDeadBand( int ident, int axis );
void glutJoystickSetDeadBand( int ident, int axis, float db );
float glutJoystickGetSaturation( int ident, int axis );
void glutJoystickSetSaturation( int ident, int axis, float st );
void glutJoystickSetMinRange( int ident, float *axes );
void glutJoystickSetMaxRange( int ident, float *axes );
void glutJoystickSetCenter( int ident, float *axes );
void glutJoystickGetMinRange( int ident, float *axes );
void glutJoystickGetMaxRange( int ident, float *axes );
void glutJoystickGetCenter( int ident, float *axes );
/*
* Initialization functions, see fg_init.c
*/
/* to get the typedef for va_list */
#include <stdarg.h>
FGAPI void FGAPIENTRY glutInitContextVersion( int majorVersion, int minorVersion );
FGAPI void FGAPIENTRY glutInitContextFlags( int flags );
FGAPI void FGAPIENTRY glutInitContextProfile( int profile );
FGAPI void FGAPIENTRY glutInitErrorFunc( void (* callback)( const char *fmt, va_list ap ) );
FGAPI void FGAPIENTRY glutInitWarningFunc( void (* callback)( const char *fmt, va_list ap ) );
/* OpenGL >= 2.0 support */
FGAPI void FGAPIENTRY glutSetVertexAttribCoord3(GLint attrib);
FGAPI void FGAPIENTRY glutSetVertexAttribNormal(GLint attrib);
FGAPI void FGAPIENTRY glutSetVertexAttribTexCoord2(GLint attrib);
/* Mobile platforms lifecycle */
FGAPI void FGAPIENTRY glutInitContextFunc(void (* callback)());
FGAPI void FGAPIENTRY glutAppStatusFunc(void (* callback)(int));
/* state flags that can be passed to callback set by glutAppStatusFunc */
#define GLUT_APPSTATUS_PAUSE 0x0001
#define GLUT_APPSTATUS_RESUME 0x0002
/*
* GLUT API macro definitions -- the display mode definitions
*/
#define GLUT_CAPTIONLESS 0x0400
#define GLUT_BORDERLESS 0x0800
#define GLUT_SRGB 0x1000
#ifdef __cplusplus
}
#endif
/*** END OF FILE ***/
#endif /* __FREEGLUT_EXT_H__ */

View File

@ -0,0 +1,653 @@
#ifndef __FREEGLUT_STD_H__
#define __FREEGLUT_STD_H__
/*
* freeglut_std.h
*
* The GLUT-compatible part of the freeglut library include file
*
* Copyright (c) 1999-2000 Pawel W. Olszta. All Rights Reserved.
* Written by Pawel W. Olszta, <olszta@sourceforge.net>
* Creation date: Thu Dec 2 1999
*
* 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
* PAWEL W. OLSZTA 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.
*/
#ifdef __cplusplus
extern "C" {
#endif
/*
* Under windows, we have to differentiate between static and dynamic libraries
*/
#ifdef _WIN32
/* #pragma may not be supported by some compilers.
* Discussion by FreeGLUT developers suggests that
* Visual C++ specific code involving pragmas may
* need to move to a separate header. 24th Dec 2003
*/
/* Define FREEGLUT_LIB_PRAGMAS to 1 to include library
* pragmas or to 0 to exclude library pragmas.
* The default behavior depends on the compiler/platform.
*/
# ifndef FREEGLUT_LIB_PRAGMAS
# if ( defined(_MSC_VER) || defined(__WATCOMC__) ) && !defined(_WIN32_WCE)
# define FREEGLUT_LIB_PRAGMAS 1
# else
# define FREEGLUT_LIB_PRAGMAS 0
# endif
# endif
# ifndef WIN32_LEAN_AND_MEAN
# define WIN32_LEAN_AND_MEAN 1
# endif
# ifndef NOMINMAX
# define NOMINMAX
# endif
# include <windows.h>
/* Windows static library */
# ifdef FREEGLUT_STATIC
# define FGAPI
# define FGAPIENTRY
/* Link with Win32 static freeglut lib */
# if FREEGLUT_LIB_PRAGMAS
# ifdef NDEBUG
# pragma comment (lib, "freeglut_static.lib")
# else
# pragma comment (lib, "freeglut_staticd.lib")
# endif
# endif
/* Windows shared library (DLL) */
# else
# define FGAPIENTRY __stdcall
# if defined(FREEGLUT_EXPORTS)
# define FGAPI __declspec(dllexport)
# else
# define FGAPI __declspec(dllimport)
/* Link with Win32 shared freeglut lib */
# if FREEGLUT_LIB_PRAGMAS
# ifdef NDEBUG
# pragma comment (lib, "freeglut.lib")
# else
# pragma comment (lib, "freeglutd.lib")
# endif
# endif
# endif
# endif
/* Drag in other Windows libraries as required by FreeGLUT */
# if FREEGLUT_LIB_PRAGMAS
# pragma comment (lib, "glu32.lib") /* link OpenGL Utility lib */
# pragma comment (lib, "opengl32.lib") /* link Microsoft OpenGL lib */
# pragma comment (lib, "gdi32.lib") /* link Windows GDI lib */
# pragma comment (lib, "winmm.lib") /* link Windows MultiMedia lib */
# pragma comment (lib, "user32.lib") /* link Windows user lib */
# endif
#else
/* Non-Windows definition of FGAPI and FGAPIENTRY */
# define FGAPI
# define FGAPIENTRY
#endif
/*
* The freeglut and GLUT API versions
*/
#define FREEGLUT 1
#define GLUT_API_VERSION 4
#define GLUT_XLIB_IMPLEMENTATION 13
/* Deprecated:
cf. http://sourceforge.net/mailarchive/forum.php?thread_name=CABcAi1hw7cr4xtigckaGXB5X8wddLfMcbA_rZ3NAuwMrX_zmsw%40mail.gmail.com&forum_name=freeglut-developer */
#define FREEGLUT_VERSION_2_0 1
/*
* Always include OpenGL and GLU headers
*/
/* Note: FREEGLUT_GLES is only used to cleanly bootstrap headers
inclusion here; use GLES constants directly
(e.g. GL_ES_VERSION_2_0) for all other needs */
#ifdef FREEGLUT_GLES
# include <EGL/egl.h>
# include <GLES/gl.h>
# include <GLES2/gl2.h>
#elif __APPLE__
# include <OpenGL/gl.h>
# include <OpenGL/glu.h>
#else
# include <GL/gl.h>
# include <GL/glu.h>
#endif
/*
* GLUT API macro definitions -- the special key codes:
*/
#define GLUT_KEY_F1 0x0001
#define GLUT_KEY_F2 0x0002
#define GLUT_KEY_F3 0x0003
#define GLUT_KEY_F4 0x0004
#define GLUT_KEY_F5 0x0005
#define GLUT_KEY_F6 0x0006
#define GLUT_KEY_F7 0x0007
#define GLUT_KEY_F8 0x0008
#define GLUT_KEY_F9 0x0009
#define GLUT_KEY_F10 0x000A
#define GLUT_KEY_F11 0x000B
#define GLUT_KEY_F12 0x000C
#define GLUT_KEY_LEFT 0x0064
#define GLUT_KEY_UP 0x0065
#define GLUT_KEY_RIGHT 0x0066
#define GLUT_KEY_DOWN 0x0067
#define GLUT_KEY_PAGE_UP 0x0068
#define GLUT_KEY_PAGE_DOWN 0x0069
#define GLUT_KEY_HOME 0x006A
#define GLUT_KEY_END 0x006B
#define GLUT_KEY_INSERT 0x006C
/*
* GLUT API macro definitions -- mouse state definitions
*/
#define GLUT_LEFT_BUTTON 0x0000
#define GLUT_MIDDLE_BUTTON 0x0001
#define GLUT_RIGHT_BUTTON 0x0002
#define GLUT_DOWN 0x0000
#define GLUT_UP 0x0001
#define GLUT_LEFT 0x0000
#define GLUT_ENTERED 0x0001
/*
* GLUT API macro definitions -- the display mode definitions
*/
#define GLUT_RGB 0x0000
#define GLUT_RGBA 0x0000
#define GLUT_INDEX 0x0001
#define GLUT_SINGLE 0x0000
#define GLUT_DOUBLE 0x0002
#define GLUT_ACCUM 0x0004
#define GLUT_ALPHA 0x0008
#define GLUT_DEPTH 0x0010
#define GLUT_STENCIL 0x0020
#define GLUT_MULTISAMPLE 0x0080
#define GLUT_STEREO 0x0100
#define GLUT_LUMINANCE 0x0200
/*
* GLUT API macro definitions -- windows and menu related definitions
*/
#define GLUT_MENU_NOT_IN_USE 0x0000
#define GLUT_MENU_IN_USE 0x0001
#define GLUT_NOT_VISIBLE 0x0000
#define GLUT_VISIBLE 0x0001
#define GLUT_HIDDEN 0x0000
#define GLUT_FULLY_RETAINED 0x0001
#define GLUT_PARTIALLY_RETAINED 0x0002
#define GLUT_FULLY_COVERED 0x0003
/*
* GLUT API macro definitions -- fonts definitions
*
* Steve Baker suggested to make it binary compatible with GLUT:
*/
#if defined(_MSC_VER) || defined(__CYGWIN__) || defined(__MINGW32__) || defined(__WATCOMC__)
# define GLUT_STROKE_ROMAN ((void *)0x0000)
# define GLUT_STROKE_MONO_ROMAN ((void *)0x0001)
# define GLUT_BITMAP_9_BY_15 ((void *)0x0002)
# define GLUT_BITMAP_8_BY_13 ((void *)0x0003)
# define GLUT_BITMAP_TIMES_ROMAN_10 ((void *)0x0004)
# define GLUT_BITMAP_TIMES_ROMAN_24 ((void *)0x0005)
# define GLUT_BITMAP_HELVETICA_10 ((void *)0x0006)
# define GLUT_BITMAP_HELVETICA_12 ((void *)0x0007)
# define GLUT_BITMAP_HELVETICA_18 ((void *)0x0008)
#else
/*
* I don't really know if it's a good idea... But here it goes:
*/
extern void* glutStrokeRoman;
extern void* glutStrokeMonoRoman;
extern void* glutBitmap9By15;
extern void* glutBitmap8By13;
extern void* glutBitmapTimesRoman10;
extern void* glutBitmapTimesRoman24;
extern void* glutBitmapHelvetica10;
extern void* glutBitmapHelvetica12;
extern void* glutBitmapHelvetica18;
/*
* Those pointers will be used by following definitions:
*/
# define GLUT_STROKE_ROMAN ((void *) &glutStrokeRoman)
# define GLUT_STROKE_MONO_ROMAN ((void *) &glutStrokeMonoRoman)
# define GLUT_BITMAP_9_BY_15 ((void *) &glutBitmap9By15)
# define GLUT_BITMAP_8_BY_13 ((void *) &glutBitmap8By13)
# define GLUT_BITMAP_TIMES_ROMAN_10 ((void *) &glutBitmapTimesRoman10)
# define GLUT_BITMAP_TIMES_ROMAN_24 ((void *) &glutBitmapTimesRoman24)
# define GLUT_BITMAP_HELVETICA_10 ((void *) &glutBitmapHelvetica10)
# define GLUT_BITMAP_HELVETICA_12 ((void *) &glutBitmapHelvetica12)
# define GLUT_BITMAP_HELVETICA_18 ((void *) &glutBitmapHelvetica18)
#endif
/*
* GLUT API macro definitions -- the glutGet parameters
*/
#define GLUT_WINDOW_X 0x0064
#define GLUT_WINDOW_Y 0x0065
#define GLUT_WINDOW_WIDTH 0x0066
#define GLUT_WINDOW_HEIGHT 0x0067
#define GLUT_WINDOW_BUFFER_SIZE 0x0068
#define GLUT_WINDOW_STENCIL_SIZE 0x0069
#define GLUT_WINDOW_DEPTH_SIZE 0x006A
#define GLUT_WINDOW_RED_SIZE 0x006B
#define GLUT_WINDOW_GREEN_SIZE 0x006C
#define GLUT_WINDOW_BLUE_SIZE 0x006D
#define GLUT_WINDOW_ALPHA_SIZE 0x006E
#define GLUT_WINDOW_ACCUM_RED_SIZE 0x006F
#define GLUT_WINDOW_ACCUM_GREEN_SIZE 0x0070
#define GLUT_WINDOW_ACCUM_BLUE_SIZE 0x0071
#define GLUT_WINDOW_ACCUM_ALPHA_SIZE 0x0072
#define GLUT_WINDOW_DOUBLEBUFFER 0x0073
#define GLUT_WINDOW_RGBA 0x0074
#define GLUT_WINDOW_PARENT 0x0075
#define GLUT_WINDOW_NUM_CHILDREN 0x0076
#define GLUT_WINDOW_COLORMAP_SIZE 0x0077
#define GLUT_WINDOW_NUM_SAMPLES 0x0078
#define GLUT_WINDOW_STEREO 0x0079
#define GLUT_WINDOW_CURSOR 0x007A
#define GLUT_SCREEN_WIDTH 0x00C8
#define GLUT_SCREEN_HEIGHT 0x00C9
#define GLUT_SCREEN_WIDTH_MM 0x00CA
#define GLUT_SCREEN_HEIGHT_MM 0x00CB
#define GLUT_MENU_NUM_ITEMS 0x012C
#define GLUT_DISPLAY_MODE_POSSIBLE 0x0190
#define GLUT_INIT_WINDOW_X 0x01F4
#define GLUT_INIT_WINDOW_Y 0x01F5
#define GLUT_INIT_WINDOW_WIDTH 0x01F6
#define GLUT_INIT_WINDOW_HEIGHT 0x01F7
#define GLUT_INIT_DISPLAY_MODE 0x01F8
#define GLUT_ELAPSED_TIME 0x02BC
#define GLUT_WINDOW_FORMAT_ID 0x007B
/*
* GLUT API macro definitions -- the glutDeviceGet parameters
*/
#define GLUT_HAS_KEYBOARD 0x0258
#define GLUT_HAS_MOUSE 0x0259
#define GLUT_HAS_SPACEBALL 0x025A
#define GLUT_HAS_DIAL_AND_BUTTON_BOX 0x025B
#define GLUT_HAS_TABLET 0x025C
#define GLUT_NUM_MOUSE_BUTTONS 0x025D
#define GLUT_NUM_SPACEBALL_BUTTONS 0x025E
#define GLUT_NUM_BUTTON_BOX_BUTTONS 0x025F
#define GLUT_NUM_DIALS 0x0260
#define GLUT_NUM_TABLET_BUTTONS 0x0261
#define GLUT_DEVICE_IGNORE_KEY_REPEAT 0x0262
#define GLUT_DEVICE_KEY_REPEAT 0x0263
#define GLUT_HAS_JOYSTICK 0x0264
#define GLUT_OWNS_JOYSTICK 0x0265
#define GLUT_JOYSTICK_BUTTONS 0x0266
#define GLUT_JOYSTICK_AXES 0x0267
#define GLUT_JOYSTICK_POLL_RATE 0x0268
/*
* GLUT API macro definitions -- the glutLayerGet parameters
*/
#define GLUT_OVERLAY_POSSIBLE 0x0320
#define GLUT_LAYER_IN_USE 0x0321
#define GLUT_HAS_OVERLAY 0x0322
#define GLUT_TRANSPARENT_INDEX 0x0323
#define GLUT_NORMAL_DAMAGED 0x0324
#define GLUT_OVERLAY_DAMAGED 0x0325
/*
* GLUT API macro definitions -- the glutVideoResizeGet parameters
*/
#define GLUT_VIDEO_RESIZE_POSSIBLE 0x0384
#define GLUT_VIDEO_RESIZE_IN_USE 0x0385
#define GLUT_VIDEO_RESIZE_X_DELTA 0x0386
#define GLUT_VIDEO_RESIZE_Y_DELTA 0x0387
#define GLUT_VIDEO_RESIZE_WIDTH_DELTA 0x0388
#define GLUT_VIDEO_RESIZE_HEIGHT_DELTA 0x0389
#define GLUT_VIDEO_RESIZE_X 0x038A
#define GLUT_VIDEO_RESIZE_Y 0x038B
#define GLUT_VIDEO_RESIZE_WIDTH 0x038C
#define GLUT_VIDEO_RESIZE_HEIGHT 0x038D
/*
* GLUT API macro definitions -- the glutUseLayer parameters
*/
#define GLUT_NORMAL 0x0000
#define GLUT_OVERLAY 0x0001
/*
* GLUT API macro definitions -- the glutGetModifiers parameters
*/
#define GLUT_ACTIVE_SHIFT 0x0001
#define GLUT_ACTIVE_CTRL 0x0002
#define GLUT_ACTIVE_ALT 0x0004
/*
* GLUT API macro definitions -- the glutSetCursor parameters
*/
#define GLUT_CURSOR_RIGHT_ARROW 0x0000
#define GLUT_CURSOR_LEFT_ARROW 0x0001
#define GLUT_CURSOR_INFO 0x0002
#define GLUT_CURSOR_DESTROY 0x0003
#define GLUT_CURSOR_HELP 0x0004
#define GLUT_CURSOR_CYCLE 0x0005
#define GLUT_CURSOR_SPRAY 0x0006
#define GLUT_CURSOR_WAIT 0x0007
#define GLUT_CURSOR_TEXT 0x0008
#define GLUT_CURSOR_CROSSHAIR 0x0009
#define GLUT_CURSOR_UP_DOWN 0x000A
#define GLUT_CURSOR_LEFT_RIGHT 0x000B
#define GLUT_CURSOR_TOP_SIDE 0x000C
#define GLUT_CURSOR_BOTTOM_SIDE 0x000D
#define GLUT_CURSOR_LEFT_SIDE 0x000E
#define GLUT_CURSOR_RIGHT_SIDE 0x000F
#define GLUT_CURSOR_TOP_LEFT_CORNER 0x0010
#define GLUT_CURSOR_TOP_RIGHT_CORNER 0x0011
#define GLUT_CURSOR_BOTTOM_RIGHT_CORNER 0x0012
#define GLUT_CURSOR_BOTTOM_LEFT_CORNER 0x0013
#define GLUT_CURSOR_INHERIT 0x0064
#define GLUT_CURSOR_NONE 0x0065
#define GLUT_CURSOR_FULL_CROSSHAIR 0x0066
/*
* GLUT API macro definitions -- RGB color component specification definitions
*/
#define GLUT_RED 0x0000
#define GLUT_GREEN 0x0001
#define GLUT_BLUE 0x0002
/*
* GLUT API macro definitions -- additional keyboard and joystick definitions
*/
#define GLUT_KEY_REPEAT_OFF 0x0000
#define GLUT_KEY_REPEAT_ON 0x0001
#define GLUT_KEY_REPEAT_DEFAULT 0x0002
#define GLUT_JOYSTICK_BUTTON_A 0x0001
#define GLUT_JOYSTICK_BUTTON_B 0x0002
#define GLUT_JOYSTICK_BUTTON_C 0x0004
#define GLUT_JOYSTICK_BUTTON_D 0x0008
/*
* GLUT API macro definitions -- game mode definitions
*/
#define GLUT_GAME_MODE_ACTIVE 0x0000
#define GLUT_GAME_MODE_POSSIBLE 0x0001
#define GLUT_GAME_MODE_WIDTH 0x0002
#define GLUT_GAME_MODE_HEIGHT 0x0003
#define GLUT_GAME_MODE_PIXEL_DEPTH 0x0004
#define GLUT_GAME_MODE_REFRESH_RATE 0x0005
#define GLUT_GAME_MODE_DISPLAY_CHANGED 0x0006
/*
* Initialization functions, see fglut_init.c
*/
FGAPI void FGAPIENTRY glutInit( int* pargc, char** argv );
FGAPI void FGAPIENTRY glutInitWindowPosition( int x, int y );
FGAPI void FGAPIENTRY glutInitWindowSize( int width, int height );
FGAPI void FGAPIENTRY glutInitDisplayMode( unsigned int displayMode );
FGAPI void FGAPIENTRY glutInitDisplayString( const char* displayMode );
/*
* Process loop function, see fg_main.c
*/
FGAPI void FGAPIENTRY glutMainLoop( void );
/*
* Window management functions, see fg_window.c
*/
FGAPI int FGAPIENTRY glutCreateWindow( const char* title );
FGAPI int FGAPIENTRY glutCreateSubWindow( int window, int x, int y, int width, int height );
FGAPI void FGAPIENTRY glutDestroyWindow( int window );
FGAPI void FGAPIENTRY glutSetWindow( int window );
FGAPI int FGAPIENTRY glutGetWindow( void );
FGAPI void FGAPIENTRY glutSetWindowTitle( const char* title );
FGAPI void FGAPIENTRY glutSetIconTitle( const char* title );
FGAPI void FGAPIENTRY glutReshapeWindow( int width, int height );
FGAPI void FGAPIENTRY glutPositionWindow( int x, int y );
FGAPI void FGAPIENTRY glutShowWindow( void );
FGAPI void FGAPIENTRY glutHideWindow( void );
FGAPI void FGAPIENTRY glutIconifyWindow( void );
FGAPI void FGAPIENTRY glutPushWindow( void );
FGAPI void FGAPIENTRY glutPopWindow( void );
FGAPI void FGAPIENTRY glutFullScreen( void );
/*
* Display-related functions, see fg_display.c
*/
FGAPI void FGAPIENTRY glutPostWindowRedisplay( int window );
FGAPI void FGAPIENTRY glutPostRedisplay( void );
FGAPI void FGAPIENTRY glutSwapBuffers( void );
/*
* Mouse cursor functions, see fg_cursor.c
*/
FGAPI void FGAPIENTRY glutWarpPointer( int x, int y );
FGAPI void FGAPIENTRY glutSetCursor( int cursor );
/*
* Overlay stuff, see fg_overlay.c
*/
FGAPI void FGAPIENTRY glutEstablishOverlay( void );
FGAPI void FGAPIENTRY glutRemoveOverlay( void );
FGAPI void FGAPIENTRY glutUseLayer( GLenum layer );
FGAPI void FGAPIENTRY glutPostOverlayRedisplay( void );
FGAPI void FGAPIENTRY glutPostWindowOverlayRedisplay( int window );
FGAPI void FGAPIENTRY glutShowOverlay( void );
FGAPI void FGAPIENTRY glutHideOverlay( void );
/*
* Menu stuff, see fg_menu.c
*/
FGAPI int FGAPIENTRY glutCreateMenu( void (* callback)( int menu ) );
FGAPI void FGAPIENTRY glutDestroyMenu( int menu );
FGAPI int FGAPIENTRY glutGetMenu( void );
FGAPI void FGAPIENTRY glutSetMenu( int menu );
FGAPI void FGAPIENTRY glutAddMenuEntry( const char* label, int value );
FGAPI void FGAPIENTRY glutAddSubMenu( const char* label, int subMenu );
FGAPI void FGAPIENTRY glutChangeToMenuEntry( int item, const char* label, int value );
FGAPI void FGAPIENTRY glutChangeToSubMenu( int item, const char* label, int value );
FGAPI void FGAPIENTRY glutRemoveMenuItem( int item );
FGAPI void FGAPIENTRY glutAttachMenu( int button );
FGAPI void FGAPIENTRY glutDetachMenu( int button );
/*
* Global callback functions, see fg_callbacks.c
*/
FGAPI void FGAPIENTRY glutTimerFunc( unsigned int time, void (* callback)( int ), int value );
FGAPI void FGAPIENTRY glutIdleFunc( void (* callback)( void ) );
/*
* Window-specific callback functions, see fg_callbacks.c
*/
FGAPI void FGAPIENTRY glutKeyboardFunc( void (* callback)( unsigned char, int, int ) );
FGAPI void FGAPIENTRY glutSpecialFunc( void (* callback)( int, int, int ) );
FGAPI void FGAPIENTRY glutReshapeFunc( void (* callback)( int, int ) );
FGAPI void FGAPIENTRY glutVisibilityFunc( void (* callback)( int ) );
FGAPI void FGAPIENTRY glutDisplayFunc( void (* callback)( void ) );
FGAPI void FGAPIENTRY glutMouseFunc( void (* callback)( int, int, int, int ) );
FGAPI void FGAPIENTRY glutMotionFunc( void (* callback)( int, int ) );
FGAPI void FGAPIENTRY glutPassiveMotionFunc( void (* callback)( int, int ) );
FGAPI void FGAPIENTRY glutEntryFunc( void (* callback)( int ) );
FGAPI void FGAPIENTRY glutKeyboardUpFunc( void (* callback)( unsigned char, int, int ) );
FGAPI void FGAPIENTRY glutSpecialUpFunc( void (* callback)( int, int, int ) );
FGAPI void FGAPIENTRY glutJoystickFunc( void (* callback)( unsigned int, int, int, int ), int pollInterval );
FGAPI void FGAPIENTRY glutMenuStateFunc( void (* callback)( int ) );
FGAPI void FGAPIENTRY glutMenuStatusFunc( void (* callback)( int, int, int ) );
FGAPI void FGAPIENTRY glutOverlayDisplayFunc( void (* callback)( void ) );
FGAPI void FGAPIENTRY glutWindowStatusFunc( void (* callback)( int ) );
FGAPI void FGAPIENTRY glutSpaceballMotionFunc( void (* callback)( int, int, int ) );
FGAPI void FGAPIENTRY glutSpaceballRotateFunc( void (* callback)( int, int, int ) );
FGAPI void FGAPIENTRY glutSpaceballButtonFunc( void (* callback)( int, int ) );
FGAPI void FGAPIENTRY glutButtonBoxFunc( void (* callback)( int, int ) );
FGAPI void FGAPIENTRY glutDialsFunc( void (* callback)( int, int ) );
FGAPI void FGAPIENTRY glutTabletMotionFunc( void (* callback)( int, int ) );
FGAPI void FGAPIENTRY glutTabletButtonFunc( void (* callback)( int, int, int, int ) );
/*
* State setting and retrieval functions, see fg_state.c
*/
FGAPI int FGAPIENTRY glutGet( GLenum query );
FGAPI int FGAPIENTRY glutDeviceGet( GLenum query );
FGAPI int FGAPIENTRY glutGetModifiers( void );
FGAPI int FGAPIENTRY glutLayerGet( GLenum query );
/*
* Font stuff, see fg_font.c
*/
FGAPI void FGAPIENTRY glutBitmapCharacter( void* font, int character );
FGAPI int FGAPIENTRY glutBitmapWidth( void* font, int character );
FGAPI void FGAPIENTRY glutStrokeCharacter( void* font, int character );
FGAPI int FGAPIENTRY glutStrokeWidth( void* font, int character );
FGAPI GLfloat FGAPIENTRY glutStrokeWidthf( void* font, int character ); /* GLUT 3.8 */
FGAPI int FGAPIENTRY glutBitmapLength( void* font, const unsigned char* string );
FGAPI int FGAPIENTRY glutStrokeLength( void* font, const unsigned char* string );
FGAPI GLfloat FGAPIENTRY glutStrokeLengthf( void* font, const unsigned char *string ); /* GLUT 3.8 */
/*
* Geometry functions, see fg_geometry.c
*/
FGAPI void FGAPIENTRY glutWireCube( double size );
FGAPI void FGAPIENTRY glutSolidCube( double size );
FGAPI void FGAPIENTRY glutWireSphere( double radius, GLint slices, GLint stacks );
FGAPI void FGAPIENTRY glutSolidSphere( double radius, GLint slices, GLint stacks );
FGAPI void FGAPIENTRY glutWireCone( double base, double height, GLint slices, GLint stacks );
FGAPI void FGAPIENTRY glutSolidCone( double base, double height, GLint slices, GLint stacks );
FGAPI void FGAPIENTRY glutWireTorus( double innerRadius, double outerRadius, GLint sides, GLint rings );
FGAPI void FGAPIENTRY glutSolidTorus( double innerRadius, double outerRadius, GLint sides, GLint rings );
FGAPI void FGAPIENTRY glutWireDodecahedron( void );
FGAPI void FGAPIENTRY glutSolidDodecahedron( void );
FGAPI void FGAPIENTRY glutWireOctahedron( void );
FGAPI void FGAPIENTRY glutSolidOctahedron( void );
FGAPI void FGAPIENTRY glutWireTetrahedron( void );
FGAPI void FGAPIENTRY glutSolidTetrahedron( void );
FGAPI void FGAPIENTRY glutWireIcosahedron( void );
FGAPI void FGAPIENTRY glutSolidIcosahedron( void );
/*
* Teapot rendering functions, found in fg_teapot.c
* NB: front facing polygons have clockwise winding, not counter clockwise
*/
FGAPI void FGAPIENTRY glutWireTeapot( double size );
FGAPI void FGAPIENTRY glutSolidTeapot( double size );
/*
* Game mode functions, see fg_gamemode.c
*/
FGAPI void FGAPIENTRY glutGameModeString( const char* string );
FGAPI int FGAPIENTRY glutEnterGameMode( void );
FGAPI void FGAPIENTRY glutLeaveGameMode( void );
FGAPI int FGAPIENTRY glutGameModeGet( GLenum query );
/*
* Video resize functions, see fg_videoresize.c
*/
FGAPI int FGAPIENTRY glutVideoResizeGet( GLenum query );
FGAPI void FGAPIENTRY glutSetupVideoResizing( void );
FGAPI void FGAPIENTRY glutStopVideoResizing( void );
FGAPI void FGAPIENTRY glutVideoResize( int x, int y, int width, int height );
FGAPI void FGAPIENTRY glutVideoPan( int x, int y, int width, int height );
/*
* Colormap functions, see fg_misc.c
*/
FGAPI void FGAPIENTRY glutSetColor( int color, GLfloat red, GLfloat green, GLfloat blue );
FGAPI GLfloat FGAPIENTRY glutGetColor( int color, int component );
FGAPI void FGAPIENTRY glutCopyColormap( int window );
/*
* Misc keyboard and joystick functions, see fg_misc.c
*/
FGAPI void FGAPIENTRY glutIgnoreKeyRepeat( int ignore );
FGAPI void FGAPIENTRY glutSetKeyRepeat( int repeatMode );
FGAPI void FGAPIENTRY glutForceJoystickFunc( void );
/*
* Misc functions, see fg_misc.c
*/
FGAPI int FGAPIENTRY glutExtensionSupported( const char* extension );
FGAPI void FGAPIENTRY glutReportErrors( void );
/* Comment from glut.h of classic GLUT:
Win32 has an annoying issue where there are multiple C run-time
libraries (CRTs). If the executable is linked with a different CRT
from the GLUT DLL, the GLUT DLL will not share the same CRT static
data seen by the executable. In particular, atexit callbacks registered
in the executable will not be called if GLUT calls its (different)
exit routine). GLUT is typically built with the
"/MD" option (the CRT with multithreading DLL support), but the Visual
C++ linker default is "/ML" (the single threaded CRT).
One workaround to this issue is requiring users to always link with
the same CRT as GLUT is compiled with. That requires users supply a
non-standard option. GLUT 3.7 has its own built-in workaround where
the executable's "exit" function pointer is covertly passed to GLUT.
GLUT then calls the executable's exit function pointer to ensure that
any "atexit" calls registered by the application are called if GLUT
needs to exit.
Note that the __glut*WithExit routines should NEVER be called directly.
To avoid the atexit workaround, #define GLUT_DISABLE_ATEXIT_HACK. */
/* to get the prototype for exit() */
#include <stdlib.h>
#if defined(_WIN32) && !defined(GLUT_DISABLE_ATEXIT_HACK) && !defined(__WATCOMC__)
FGAPI void FGAPIENTRY __glutInitWithExit(int *argcp, char **argv, void (__cdecl *exitfunc)(int));
FGAPI int FGAPIENTRY __glutCreateWindowWithExit(const char *title, void (__cdecl *exitfunc)(int));
FGAPI int FGAPIENTRY __glutCreateMenuWithExit(void (* func)(int), void (__cdecl *exitfunc)(int));
#ifndef FREEGLUT_BUILDING_LIB
#if defined(__GNUC__)
#define FGUNUSED __attribute__((unused))
#else
#define FGUNUSED
#endif
static void FGAPIENTRY FGUNUSED glutInit_ATEXIT_HACK(int *argcp, char **argv) { __glutInitWithExit(argcp, argv, exit); }
#define glutInit glutInit_ATEXIT_HACK
static int FGAPIENTRY FGUNUSED glutCreateWindow_ATEXIT_HACK(const char *title) { return __glutCreateWindowWithExit(title, exit); }
#define glutCreateWindow glutCreateWindow_ATEXIT_HACK
static int FGAPIENTRY FGUNUSED glutCreateMenu_ATEXIT_HACK(void (* func)(int)) { return __glutCreateMenuWithExit(func, exit); }
#define glutCreateMenu glutCreateMenu_ATEXIT_HACK
#endif
#endif
#ifdef __cplusplus
}
#endif
/*** END OF FILE ***/
#endif /* __FREEGLUT_STD_H__ */

View File

@ -0,0 +1,21 @@
#ifndef __GLUT_H__
#define __GLUT_H__
/*
* glut.h
*
* The freeglut library include file
*
* 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
* PAWEL W. OLSZTA 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.
*/
#include "freeglut_std.h"
/*** END OF FILE ***/
#endif /* __GLUT_H__ */

33
tests/gcctest.c Normal file
View File

@ -0,0 +1,33 @@
#include <stdio.h>
int a;
int b[1000000000000];
int x;
int main() {
b[3] = 12;
a = b[3];
printf("%d\r\n",a);
printf("%d\r\n",b[5]);
x = 0;
while(x < 500) {
b[x] = x + b[x - 1];
x = x + 1;
int tmp1;
tmp1 = b[x] - 2;
while(tmp1 < 30) {
int lol;
lol = 0;
while(lol < tmp1) {
lol = lol + 1;
printf("%d\r\n",lol);
}
tmp1 = tmp1 + 1;
}
}
return(0);
}

40
tests/gl.er Normal file
View File

@ -0,0 +1,40 @@
void :: glClear();
void :: glBegin();
void :: glVertex3f();
void :: glEnd();
void :: glFlush();
void :: glutInit();
void :: glutInitDisplayMode();
void :: glutInitWindowPosition();
void :: glutInitWindowSize();
void :: glutCreateWindow();
void :: glutDisplayFunc();
void :: glutMainLoop();
void :: display() {
glClear(16384);
glBegin(9);
glVertex3f(0, 0, 0);
glVertex3f(1, 0, 0);
glVertex3f(1, 1, 0);
glVertex3f(0, 1, 0);
glEnd();
glFlush();
}
int :: main(int argc, char** argv) {
glutInit(&argc, argv);
glutInitDisplayMode(0);
glutInitWindowSize(300, 300);
glutInitWindowPosition(100, 100);
glutCreateWindow("Hello");
glutDisplayFunc(display);
glutMainLoop();
return (0);
}

1
tests/import/defs.eh Normal file
View File

@ -0,0 +1 @@
int :: printf(char* format);

6
tests/import/source.er Normal file
View File

@ -0,0 +1,6 @@
import "tests/import/defs.eh"
int :: main() {
printf("tests\n");
return (0);
}

11
tests/localinit.er Normal file
View File

@ -0,0 +1,11 @@
import "import/defs.eh"
int :: main() {
int x = 3, y = 14;
int z = 2 * x + y;
char* str = "Hello world";
printf("%s %d %d\n", str, x + y, z);
return (0);
}

1
tests/print.em Normal file
View File

@ -0,0 +1 @@
int :: printf(char* fmt);

View File

@ -1,4 +1,4 @@
int :: printf(char* format);
import "print.em"
int :: main () {
printf("%s\r\n", "hi there");

30
tests/sieve.er Normal file
View File

@ -0,0 +1,30 @@
import "import/defs.eh"
long num[100];
int :: main() {
long i = 0;
long j = 0;
for (i = 0; i < 100; i++) {
num[i] = i + 1;
}
for (i = 1; (num[i] * num[i]) <= 100; i++) {
if (num[i] != 0) {
for (j = num[i] * num[i]; j <= 100; j = num[i] + j) {
num[j - 1] = 0;
}
}
}
printf("Finding primes 2..%d\n\n",100);
for (i = 1; i < 100; i++) {
if (num[i] != 0) {
printf("%d\t", num[i]);
}
}
printf("\n");
return (0);
}

14
tests/struct.er Normal file
View File

@ -0,0 +1,14 @@
struct a {
int x,
int y
};
int :: printf(char* fmt);
struct a str;
int :: main() {
str.y = 55;
printf("%d\n", str.y);
return (0);
}

23
tests/structbrutal.er Normal file
View File

@ -0,0 +1,23 @@
int :: printf(char* fmt);
struct banana {
int x,
int y
};
struct banana bread;
struct banana* loaf;
int :: main() {
bread.y = 5;
loaf->y = 10;
printf("%d\n", bread.y);
printf("%d\n", loaf->y);
bread.x = 7;
printf("%d\n", bread.y + bread.x);
return (0);
}

25
tests/switch.er Normal file
View File

@ -0,0 +1,25 @@
import "import/defs.eh"
int stuff[] = { 5, 7, 9 };
int :: main() {
for (int x = 0; x < 5; x++) {
int y = 0;
switch(x) {
case 1: {
y = stuff[0];
break; }
case 2:
y = stuff[1];
break;
case 3:
y = stuff[2];
default:
y = 100;
}
printf("%d\n", y);
}
return 0;
}

5
tests/test.java Normal file
View File

@ -0,0 +1,5 @@
class Test {
public static void main(String[] args) {
java.lang.System.out.println("hi");
}
}

21
tests/union.er Normal file
View File

@ -0,0 +1,21 @@
int :: printf(char* format);
union fruit {
char cherry,
int apple,
int orange,
long banana
};
union fruit basket;
int :: main() {
basket.apple = 55;
printf("1 %d b\n", basket.cherry);
printf("2 %d a\n", basket.orange);
basket.orange = 100;
printf("3 %d c\n", basket.banana);
printf("4 %d d\n", basket.apple);
return (0);
}