Compare commits
36 Commits
dev-refact
...
master
Author | SHA1 | Date | |
---|---|---|---|
6e1129cb6b | |||
dc4d4aba24 | |||
c11e0792f4 | |||
84c5c9f4f2 | |||
5f014fed8b | |||
cdd8e017e2 | |||
29b797d7dc | |||
bfebf647eb | |||
bc787c3adb | |||
0f77480d5b | |||
e42a2cfd8d | |||
96f6773904 | |||
4e47cdcaf6 | |||
70ae06af44 | |||
09af190aa9 | |||
4d5fd36390 | |||
216d6c6b5e | |||
39756f4e89 | |||
734bc049e7 | |||
334b02cd76 | |||
0454c38a7e | |||
b7f8d8666e | |||
4e62bbdc51 | |||
2c27f2eb40 | |||
37cdaacc71 | |||
f2d2d07709 | |||
2c87817904 | |||
628c7a3a13 | |||
3717b310be | |||
537246daae | |||
ac8c0ed9c7 | |||
8e45ea5eef | |||
2bdbe6e6c0 | |||
d848425701 | |||
f766d02467 | |||
8263fb853b |
8
.gitignore
vendored
8
.gitignore
vendored
|
@ -1,6 +1,14 @@
|
|||
.idea
|
||||
.vscode
|
||||
.cache
|
||||
|
||||
out
|
||||
bin
|
||||
|
||||
build
|
||||
Erythro
|
||||
test
|
||||
cmake-build-debug
|
||||
|
||||
*.s
|
||||
*.o
|
26
CMakeLists.txt
Normal file
26
CMakeLists.txt
Normal 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
20
build.json
Normal file
|
@ -0,0 +1,20 @@
|
|||
{
|
||||
"name": "Erythro",
|
||||
"author": "Curle",
|
||||
|
||||
"source": {
|
||||
"src": [
|
||||
"$root/src/*.c"
|
||||
],
|
||||
"inc": [
|
||||
"$root/include/"
|
||||
]
|
||||
},
|
||||
|
||||
"build": {
|
||||
"compile": [
|
||||
"-g -I$inc",
|
||||
"$src"
|
||||
]
|
||||
}
|
||||
}
|
|
@ -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;
|
369
include/Defs.h
369
include/Defs.h
|
@ -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
137
plugins/c.js
Normal 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);
|
||||
}
|
||||
|
||||
}
|
110
src/Delegate.c
110
src/Delegate.c
|
@ -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);
|
||||
}
|
||||
|
|
208
src/Dump.c
208
src/Dump.c
|
@ -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
95
src/Errors.c
Normal 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
135
src/Importer.c
Normal 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();
|
||||
|
||||
}
|
261
src/Lexer.c
261
src/Lexer.c
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
287
src/Main.c
287
src/Main.c
|
@ -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);
|
||||
|
|
308
src/Parser.c
308
src/Parser.c
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
141
src/Pointers.c
141
src/Pointers.c
|
@ -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;
|
||||
}
|
1183
src/Statements.c
1183
src/Statements.c
File diff suppressed because it is too large
Load Diff
155
src/Symbols.c
155
src/Symbols.c
|
@ -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;
|
||||
}
|
82
src/Types.c
82
src/Types.c
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
40
src/assemble/AssemblerDispatcher.c
Normal file
40
src/assemble/AssemblerDispatcher.c
Normal 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
180
src/assemble/JVMAssembler.c
Normal 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);
|
||||
}
|
1334
src/assemble/LinuxGASAssembler.c
Normal file
1334
src/assemble/LinuxGASAssembler.c
Normal file
File diff suppressed because it is too large
Load Diff
180
src/assemble/QBEAssembler.c
Normal file
180
src/assemble/QBEAssembler.c
Normal 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
29
tests/alias.er
Normal 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
21
tests/breakcontinue.er
Normal 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
6
tests/calls.c
Normal file
|
@ -0,0 +1,6 @@
|
|||
#include <stdio.h>
|
||||
|
||||
int main() {
|
||||
printf("%d\n", 55);
|
||||
puts("more sup\n");
|
||||
}
|
|
@ -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
18
tests/enum.er
Normal 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);
|
||||
}
|
22
tests/freeglut/include/GL/freeglut.h
Normal file
22
tests/freeglut/include/GL/freeglut.h
Normal 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__ */
|
271
tests/freeglut/include/GL/freeglut_ext.h
Normal file
271
tests/freeglut/include/GL/freeglut_ext.h
Normal 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__ */
|
653
tests/freeglut/include/GL/freeglut_std.h
Normal file
653
tests/freeglut/include/GL/freeglut_std.h
Normal 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__ */
|
||||
|
21
tests/freeglut/include/GL/glut.h
Normal file
21
tests/freeglut/include/GL/glut.h
Normal 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
33
tests/gcctest.c
Normal 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
40
tests/gl.er
Normal 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
1
tests/import/defs.eh
Normal file
|
@ -0,0 +1 @@
|
|||
int :: printf(char* format);
|
6
tests/import/source.er
Normal file
6
tests/import/source.er
Normal file
|
@ -0,0 +1,6 @@
|
|||
import "tests/import/defs.eh"
|
||||
|
||||
int :: main() {
|
||||
printf("tests\n");
|
||||
return (0);
|
||||
}
|
11
tests/localinit.er
Normal file
11
tests/localinit.er
Normal 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
1
tests/print.em
Normal file
|
@ -0,0 +1 @@
|
|||
int :: printf(char* fmt);
|
|
@ -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
30
tests/sieve.er
Normal 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
14
tests/struct.er
Normal 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
23
tests/structbrutal.er
Normal 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
25
tests/switch.er
Normal 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
5
tests/test.java
Normal 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
21
tests/union.er
Normal 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);
|
||||
}
|
Loading…
Reference in New Issue
Block a user