2018-08-26 17:12:30 +01:00
|
|
|
## This file was generated by running:
|
|
|
|
## cat functions/file.c functions/malloc.c functions/calloc.c functions/exit.c functions/match.c functions/numerate_number.c functions/file_print.c functions/string.c cc.h cc_reader.c cc_strings.c cc_types.c cc_core.c cc.c >| ../stage0/stage3/M2-Planet_x86.c
|
|
|
|
## inside M2-Planet's repo
|
|
|
|
|
|
|
|
/* Copyright (C) 2016 Jeremiah Orians
|
|
|
|
* This file is part of stage0.
|
|
|
|
*
|
|
|
|
* stage0 is free software: you can redistribute it and/or modify
|
|
|
|
* it under the terms of the GNU General Public License as published by
|
|
|
|
* the Free Software Foundation, either version 3 of the License, or
|
|
|
|
* (at your option) any later version.
|
|
|
|
*
|
|
|
|
* stage0 is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
* GNU General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU General Public License
|
|
|
|
* along with stage0. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
*/
|
|
|
|
|
|
|
|
// CONSTANT stdin 0
|
|
|
|
// CONSTANT stdout 1
|
|
|
|
// CONSTANT stderr 2
|
|
|
|
// CONSTANT EOF 0xFFFFFFFF
|
|
|
|
|
|
|
|
int fgetc(FILE* f)
|
|
|
|
{
|
|
|
|
asm("LOAD_IMMEDIATE_eax %3"
|
|
|
|
"LOAD_EFFECTIVE_ADDRESS_ebx %4"
|
|
|
|
"LOAD_INTEGER_ebx"
|
|
|
|
"PUSH_ebx"
|
|
|
|
"COPY_esp_to_ecx"
|
|
|
|
"LOAD_IMMEDIATE_edx %1"
|
|
|
|
"INT_80"
|
|
|
|
"TEST"
|
|
|
|
"POP_eax"
|
|
|
|
"JUMP_NE8 !FUNCTION_fgetc_Done"
|
|
|
|
"LOAD_IMMEDIATE_eax %-1"
|
|
|
|
":FUNCTION_fgetc_Done");
|
|
|
|
}
|
|
|
|
|
|
|
|
void fputc(char s, FILE* f)
|
|
|
|
{
|
|
|
|
asm("LOAD_IMMEDIATE_eax %4"
|
|
|
|
"LOAD_EFFECTIVE_ADDRESS_ebx %4"
|
|
|
|
"LOAD_INTEGER_ebx"
|
|
|
|
"LOAD_EFFECTIVE_ADDRESS_ecx %8"
|
|
|
|
"LOAD_IMMEDIATE_edx %1"
|
|
|
|
"INT_80");
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Important values needed for open
|
|
|
|
* O_RDONLY => 0
|
|
|
|
* O_WRONLY => 1
|
|
|
|
* O_RDWR => 2
|
|
|
|
* O_CREAT => 64
|
|
|
|
* O_TRUNC => 512
|
|
|
|
* S_IRWXU => 00700
|
|
|
|
* S_IXUSR => 00100
|
|
|
|
* S_IWUSR => 00200
|
|
|
|
* S_IRUSR => 00400
|
|
|
|
*/
|
|
|
|
|
|
|
|
FILE* open(char* name, int flag, int mode)
|
|
|
|
{
|
|
|
|
asm("LOAD_EFFECTIVE_ADDRESS_ebx %12"
|
|
|
|
"LOAD_INTEGER_ebx"
|
|
|
|
"LOAD_EFFECTIVE_ADDRESS_ecx %8"
|
|
|
|
"LOAD_INTEGER_ecx"
|
|
|
|
"LOAD_EFFECTIVE_ADDRESS_edx %4"
|
|
|
|
"LOAD_INTEGER_edx"
|
|
|
|
"LOAD_IMMEDIATE_eax %5"
|
|
|
|
"INT_80");
|
|
|
|
}
|
|
|
|
|
|
|
|
FILE* fopen(char* filename, char* mode)
|
|
|
|
{
|
|
|
|
FILE* f;
|
|
|
|
if('w' == mode[0])
|
|
|
|
{ /* 577 is O_WRONLY|O_CREAT|O_TRUNC, 384 is 600 in octal */
|
|
|
|
f = open(filename, 577 , 384);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{ /* Everything else is a read */
|
|
|
|
f = open(filename, 0, 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Negative numbers are error codes */
|
|
|
|
if(0 > f)
|
|
|
|
{
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
return f;
|
|
|
|
}
|
|
|
|
|
|
|
|
int close(int fd)
|
|
|
|
{
|
|
|
|
asm("LOAD_EFFECTIVE_ADDRESS_ebx %4"
|
|
|
|
"LOAD_IMMEDIATE_eax %6"
|
|
|
|
"INT_80");
|
|
|
|
}
|
|
|
|
int fclose(FILE* stream)
|
|
|
|
{
|
|
|
|
int error = close(stream);
|
|
|
|
return error;
|
|
|
|
}
|
|
|
|
## Copyright (C) 2016 Jeremiah Orians
|
|
|
|
## This file is part of stage0.
|
|
|
|
##
|
2018-08-27 02:50:34 +01:00
|
|
|
## stage0 is free software: you can redistribute it and/or modify
|
2018-08-26 17:12:30 +01:00
|
|
|
## it under the terms of the GNU General Public License as published by
|
|
|
|
## the Free Software Foundation, either version 3 of the License, or
|
|
|
|
## (at your option) any later version.
|
|
|
|
##
|
|
|
|
## stage0 is distributed in the hope that it will be useful,
|
|
|
|
## but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
## GNU General Public License for more details.
|
|
|
|
##
|
|
|
|
## You should have received a copy of the GNU General Public License
|
|
|
|
## along with stage0. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
// CONSTANT NULL 0
|
|
|
|
|
|
|
|
void* malloc(int size)
|
|
|
|
{
|
|
|
|
asm("STORE_eax_into_ESP_IMMEDIATE8 !4"
|
|
|
|
"PUSH_eax"
|
|
|
|
"LOAD_IMMEDIATE_eax %45"
|
|
|
|
"LOAD_IMMEDIATE_ebx %0"
|
|
|
|
"INT_80"
|
|
|
|
"POP_ebx"
|
|
|
|
"ADD_eax_to_ebx"
|
|
|
|
"PUSH_eax"
|
|
|
|
"PUSH_ebx"
|
|
|
|
"LOAD_IMMEDIATE_eax %45"
|
|
|
|
"INT_80"
|
|
|
|
"POP_ebx"
|
|
|
|
"CMP"
|
|
|
|
"POP_eax"
|
|
|
|
"JUMP_EQ8 !FUNCTION_malloc_Done"
|
|
|
|
"LOAD_IMMEDIATE_eax %-1"
|
|
|
|
":FUNCTION_malloc_Done");
|
|
|
|
}
|
|
|
|
/* Copyright (C) 2016 Jeremiah Orians
|
|
|
|
* This file is part of stage0.
|
|
|
|
*
|
|
|
|
* stage0 is free software: you can redistribute it and/or modify
|
|
|
|
* it under the terms of the GNU General Public License as published by
|
|
|
|
* the Free Software Foundation, either version 3 of the License, or
|
|
|
|
* (at your option) any later version.
|
|
|
|
*
|
|
|
|
* stage0 is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
* GNU General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU General Public License
|
|
|
|
* along with stage0. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
*/
|
|
|
|
// void* malloc(int size);
|
|
|
|
|
|
|
|
void* memset(void* ptr, int value, int num)
|
|
|
|
{
|
|
|
|
char* s;
|
|
|
|
for(s = ptr; 0 < num; num = num - 1)
|
|
|
|
{
|
|
|
|
s[0] = value;
|
|
|
|
s = s + 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void* calloc(int count, int size)
|
|
|
|
{
|
|
|
|
void* ret = malloc(count * size);
|
|
|
|
memset(ret, 0, (count * size));
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
void free(void* l)
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
## Copyright (C) 2016 Jeremiah Orians
|
|
|
|
## This file is part of stage0.
|
|
|
|
##
|
2018-08-27 02:50:34 +01:00
|
|
|
## stage0 is free software: you can redistribute it and/or modify
|
2018-08-26 17:12:30 +01:00
|
|
|
## it under the terms of the GNU General Public License as published by
|
|
|
|
## the Free Software Foundation, either version 3 of the License, or
|
|
|
|
## (at your option) any later version.
|
|
|
|
##
|
|
|
|
## stage0 is distributed in the hope that it will be useful,
|
|
|
|
## but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
## GNU General Public License for more details.
|
|
|
|
##
|
|
|
|
## You should have received a copy of the GNU General Public License
|
|
|
|
## along with stage0. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
// CONSTANT EXIT_FAILURE 1
|
|
|
|
// CONSTANT EXIT_SUCCESS 0
|
|
|
|
|
|
|
|
void exit(int value)
|
|
|
|
{
|
|
|
|
asm("POP_ebx"
|
|
|
|
"POP_ebx"
|
|
|
|
"LOAD_IMMEDIATE_eax %1"
|
|
|
|
"INT_80");
|
|
|
|
}
|
|
|
|
/* Copyright (C) 2016 Jeremiah Orians
|
|
|
|
* This file is part of stage0.
|
|
|
|
*
|
|
|
|
* stage0 is free software: you can redistribute it and/or modify
|
|
|
|
* it under the terms of the GNU General Public License as published by
|
|
|
|
* the Free Software Foundation, either version 3 of the License, or
|
|
|
|
* (at your option) any later version.
|
|
|
|
*
|
|
|
|
* stage0 is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
* GNU General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU General Public License
|
|
|
|
* along with stage0. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#define FALSE 0
|
|
|
|
// CONSTANT FALSE 0
|
|
|
|
#define TRUE 1
|
|
|
|
// CONSTANT TRUE 1
|
|
|
|
|
|
|
|
int match(char* a, char* b)
|
|
|
|
{
|
|
|
|
int i = -1;
|
|
|
|
do
|
|
|
|
{
|
|
|
|
i = i + 1;
|
|
|
|
if(a[i] != b[i])
|
|
|
|
{
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
} while((0 != a[i]) && (0 !=b[i]));
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
/* Copyright (C) 2016 Jeremiah Orians
|
|
|
|
* This file is part of stage0.
|
|
|
|
*
|
|
|
|
* stage0 is free software: you can redistribute it and/or modify
|
|
|
|
* it under the terms of the GNU General Public License as published by
|
|
|
|
* the Free Software Foundation, either version 3 of the License, or
|
|
|
|
* (at your option) any later version.
|
|
|
|
*
|
|
|
|
* stage0 is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
* GNU General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU General Public License
|
|
|
|
* along with stage0. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
*/
|
|
|
|
#include<stdlib.h>
|
|
|
|
#include<string.h>
|
|
|
|
// void* calloc(int count, int size);
|
|
|
|
#define TRUE 1
|
|
|
|
//CONSTANT TRUE 1
|
|
|
|
#define FALSE 0
|
|
|
|
//CONSTANT FALSE 0
|
|
|
|
|
|
|
|
char* numerate_number(int a)
|
|
|
|
{
|
|
|
|
char* result = calloc(16, sizeof(char));
|
|
|
|
int i = 0;
|
|
|
|
|
|
|
|
/* Deal with Zero case */
|
|
|
|
if(0 == a)
|
|
|
|
{
|
|
|
|
result[0] = '0';
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Deal with negatives */
|
|
|
|
if(0 > a)
|
|
|
|
{
|
|
|
|
result[0] = '-';
|
|
|
|
i = 1;
|
|
|
|
a = a * -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Using the largest 10^n number possible in 32bits */
|
|
|
|
int divisor = 0x3B9ACA00;
|
|
|
|
/* Skip leading Zeros */
|
|
|
|
while(0 == (a / divisor)) divisor = divisor / 10;
|
|
|
|
|
|
|
|
/* Now simply collect numbers until divisor is gone */
|
|
|
|
while(0 < divisor)
|
|
|
|
{
|
|
|
|
result[i] = ((a / divisor) + 48);
|
|
|
|
a = a % divisor;
|
|
|
|
divisor = divisor / 10;
|
|
|
|
i = i + 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
int char2hex(int c)
|
|
|
|
{
|
|
|
|
if (c >= '0' && c <= '9') return (c - 48);
|
|
|
|
else if (c >= 'a' && c <= 'f') return (c - 87);
|
|
|
|
else if (c >= 'A' && c <= 'F') return (c - 55);
|
|
|
|
else return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
int hex2char(int c)
|
|
|
|
{
|
|
|
|
if((c >= 0) && (c <= 9)) return (c + 48);
|
|
|
|
else if((c >= 10) && (c <= 15)) return (c + 55);
|
|
|
|
else return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
int char2dec(int c)
|
|
|
|
{
|
|
|
|
if (c >= '0' && c <= '9') return (c - 48);
|
|
|
|
else return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
int dec2char(int c)
|
|
|
|
{
|
|
|
|
if((c >= 0) && (c <= 9)) return (c + 48);
|
|
|
|
else return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
int numerate_string(char *a)
|
|
|
|
{
|
|
|
|
int count = 0;
|
|
|
|
int index;
|
|
|
|
int negative;
|
|
|
|
|
|
|
|
/* If NULL string */
|
|
|
|
if(0 == a[0])
|
|
|
|
{
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
/* Deal with hex */
|
|
|
|
else if (a[0] == '0' && a[1] == 'x')
|
|
|
|
{
|
|
|
|
if('-' == a[2])
|
|
|
|
{
|
|
|
|
negative = TRUE;
|
|
|
|
index = 3;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
negative = FALSE;
|
|
|
|
index = 2;
|
|
|
|
}
|
|
|
|
|
|
|
|
while(0 != a[index])
|
|
|
|
{
|
|
|
|
if(-1 == char2hex(a[index])) return 0;
|
|
|
|
count = (16 * count) + char2hex(a[index]);
|
|
|
|
index = index + 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
/* Deal with decimal */
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if('-' == a[0])
|
|
|
|
{
|
|
|
|
negative = TRUE;
|
|
|
|
index = 1;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
negative = FALSE;
|
|
|
|
index = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
while(0 != a[index])
|
|
|
|
{
|
|
|
|
if(-1 == char2dec(a[index])) return 0;
|
|
|
|
count = (10 * count) + char2dec(a[index]);
|
|
|
|
index = index + 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if(negative)
|
|
|
|
{
|
|
|
|
count = count * -1;
|
|
|
|
}
|
|
|
|
return count;
|
|
|
|
}
|
|
|
|
/* Copyright (C) 2016 Jeremiah Orians
|
|
|
|
* This file is part of stage0.
|
|
|
|
*
|
|
|
|
* stage0 is free software: you can redistribute it and/or modify
|
|
|
|
* it under the terms of the GNU General Public License as published by
|
|
|
|
* the Free Software Foundation, either version 3 of the License, or
|
|
|
|
* (at your option) any later version.
|
|
|
|
*
|
|
|
|
* stage0 is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
* GNU General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU General Public License
|
|
|
|
* along with stage0. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
*/
|
|
|
|
#include<stdio.h>
|
|
|
|
// void fputc(char s, FILE* f);
|
|
|
|
|
|
|
|
void file_print(char* s, FILE* f)
|
|
|
|
{
|
|
|
|
while(0 != s[0])
|
|
|
|
{
|
|
|
|
fputc(s[0], f);
|
|
|
|
s = s + 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
/* Copyright (C) 2016 Jeremiah Orians
|
|
|
|
* This file is part of stage0.
|
|
|
|
*
|
|
|
|
* stage0 is free software: you can redistribute it and/or modify
|
|
|
|
* it under the terms of the GNU General Public License as published by
|
|
|
|
* the Free Software Foundation, either version 3 of the License, or
|
|
|
|
* (at your option) any later version.
|
|
|
|
*
|
|
|
|
* stage0 is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
* GNU General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU General Public License
|
|
|
|
* along with stage0. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
*/
|
|
|
|
#include<stdlib.h>
|
|
|
|
#define MAX_STRING 4096
|
|
|
|
//CONSTANT MAX_STRING 4096
|
|
|
|
// void* calloc(int count, int size);
|
|
|
|
|
|
|
|
char* copy_string(char* target, char* source)
|
|
|
|
{
|
|
|
|
while(0 != source[0])
|
|
|
|
{
|
|
|
|
target[0] = source[0];
|
|
|
|
target = target + 1;
|
|
|
|
source = source + 1;
|
|
|
|
}
|
|
|
|
return target;
|
|
|
|
}
|
|
|
|
|
|
|
|
char* postpend_char(char* s, char a)
|
|
|
|
{
|
|
|
|
char* ret = calloc(MAX_STRING, sizeof(char));
|
|
|
|
char* hold = copy_string(ret, s);
|
|
|
|
hold[0] = a;
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
char* prepend_char(char a, char* s)
|
|
|
|
{
|
|
|
|
char* ret = calloc(MAX_STRING, sizeof(char));
|
|
|
|
ret[0] = a;
|
|
|
|
copy_string((ret+1), s);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
char* prepend_string(char* add, char* base)
|
|
|
|
{
|
|
|
|
char* ret = calloc(MAX_STRING, sizeof(char));
|
|
|
|
copy_string(copy_string(ret, add), base);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
int string_length(char* a)
|
|
|
|
{
|
|
|
|
int i = 0;
|
|
|
|
while(0 != a[i]) i = i + 1;
|
|
|
|
return i;
|
|
|
|
}
|
|
|
|
/* Copyright (C) 2016 Jeremiah Orians
|
|
|
|
* This file is part of stage0.
|
|
|
|
*
|
|
|
|
* stage0 is free software: you can redistribute it and/or modify
|
|
|
|
* it under the terms of the GNU General Public License as published by
|
|
|
|
* the Free Software Foundation, either version 3 of the License, or
|
|
|
|
* (at your option) any later version.
|
|
|
|
*
|
|
|
|
* stage0 is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
* GNU General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU General Public License
|
|
|
|
* along with stage0. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <string.h>
|
|
|
|
|
|
|
|
#define MAX_STRING 4096
|
|
|
|
// CONSTANT MAX_STRING 4096
|
|
|
|
#define FALSE 0
|
|
|
|
// CONSTANT FALSE 0
|
|
|
|
#define TRUE 1
|
|
|
|
// CONSTANT TRUE 1
|
|
|
|
|
|
|
|
void file_print(char* s, FILE* f);
|
|
|
|
int match(char* a, char* b);
|
|
|
|
char* copy_string(char* target, char* source);
|
|
|
|
void reset_hold_string();
|
|
|
|
int in_set(int c, char* s);
|
|
|
|
|
|
|
|
struct type
|
|
|
|
{
|
|
|
|
struct type* next;
|
|
|
|
int size;
|
|
|
|
int offset;
|
|
|
|
struct type* indirect;
|
|
|
|
struct type* members;
|
|
|
|
struct type* type;
|
|
|
|
char* name;
|
|
|
|
};
|
|
|
|
|
|
|
|
struct token_list
|
|
|
|
{
|
|
|
|
struct token_list* next;
|
|
|
|
union
|
|
|
|
{
|
|
|
|
struct token_list* locals;
|
|
|
|
struct token_list* prev;
|
|
|
|
};
|
|
|
|
char* s;
|
|
|
|
union
|
|
|
|
{
|
|
|
|
struct type* type;
|
|
|
|
char* filename;
|
|
|
|
};
|
|
|
|
union
|
|
|
|
{
|
|
|
|
struct token_list* arguments;
|
|
|
|
int depth;
|
|
|
|
int linenumber;
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
|
|
|
/* What types we have */
|
|
|
|
struct type* global_types;
|
|
|
|
struct type* prim_types;
|
|
|
|
|
|
|
|
/* What we are currently working on */
|
|
|
|
struct token_list* global_token;
|
|
|
|
|
|
|
|
/* Output reorder collections*/
|
|
|
|
struct token_list* strings_list;
|
|
|
|
struct token_list* globals_list;
|
|
|
|
|
|
|
|
/* Make our string collection more efficient */
|
|
|
|
char* hold_string;
|
|
|
|
int string_index;
|
|
|
|
/* Copyright (C) 2016 Jeremiah Orians
|
|
|
|
* This file is part of stage0.
|
|
|
|
*
|
|
|
|
* stage0 is free software: you can redistribute it and/or modify
|
|
|
|
* it under the terms of the GNU General Public License as published by
|
|
|
|
* the Free Software Foundation, either version 3 of the License, or
|
|
|
|
* (at your option) any later version.
|
|
|
|
*
|
|
|
|
* stage0 is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
* GNU General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU General Public License
|
|
|
|
* along with stage0. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "cc.h"
|
|
|
|
FILE* input;
|
|
|
|
struct token_list* token;
|
|
|
|
int line;
|
|
|
|
char* file;
|
|
|
|
|
|
|
|
int clearWhiteSpace(int c)
|
|
|
|
{
|
|
|
|
if((32 == c) || (9 == c)) return clearWhiteSpace(fgetc(input));
|
|
|
|
else if (10 == c)
|
|
|
|
{
|
|
|
|
line = line + 1;
|
|
|
|
return clearWhiteSpace(fgetc(input));
|
|
|
|
}
|
|
|
|
return c;
|
|
|
|
}
|
|
|
|
|
|
|
|
int consume_byte(int c)
|
|
|
|
{
|
|
|
|
hold_string[string_index] = c;
|
|
|
|
string_index = string_index + 1;
|
|
|
|
return fgetc(input);
|
|
|
|
}
|
|
|
|
|
|
|
|
int consume_word(int c, int frequent)
|
|
|
|
{
|
|
|
|
int escape = FALSE;
|
|
|
|
do
|
|
|
|
{
|
|
|
|
if(!escape && '\\' == c ) escape = TRUE;
|
|
|
|
else escape = FALSE;
|
|
|
|
c = consume_byte(c);
|
|
|
|
} while(escape || (c != frequent));
|
|
|
|
return fgetc(input);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void fixup_label()
|
|
|
|
{
|
|
|
|
int hold = ':';
|
|
|
|
int prev;
|
|
|
|
int i = 0;
|
|
|
|
do
|
|
|
|
{
|
|
|
|
prev = hold;
|
|
|
|
hold = hold_string[i];
|
|
|
|
hold_string[i] = prev;
|
|
|
|
i = i + 1;
|
|
|
|
} while(0 != hold);
|
|
|
|
}
|
|
|
|
|
|
|
|
int in_set(int c, char* s)
|
|
|
|
{
|
|
|
|
while(0 != s[0])
|
|
|
|
{
|
|
|
|
if(c == s[0]) return TRUE;
|
|
|
|
s = s + 1;
|
|
|
|
}
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
int preserve_keyword(int c)
|
|
|
|
{
|
|
|
|
while(in_set(c, "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_"))
|
|
|
|
{
|
|
|
|
c = consume_byte(c);
|
|
|
|
}
|
|
|
|
if(':' == c)
|
|
|
|
{
|
|
|
|
fixup_label();
|
|
|
|
return 32;
|
|
|
|
}
|
|
|
|
return c;
|
|
|
|
}
|
|
|
|
|
|
|
|
int preserve_symbol(int c)
|
|
|
|
{
|
|
|
|
while(in_set(c, "<=>|&!-"))
|
|
|
|
{
|
|
|
|
c = consume_byte(c);
|
|
|
|
}
|
|
|
|
return c;
|
|
|
|
}
|
|
|
|
|
|
|
|
int purge_macro(int ch)
|
|
|
|
{
|
|
|
|
while(10 != ch) ch = fgetc(input);
|
|
|
|
return ch;
|
|
|
|
}
|
|
|
|
|
|
|
|
void reset_hold_string()
|
|
|
|
{
|
|
|
|
int i = string_index + 2;
|
|
|
|
while(0 != i)
|
|
|
|
{
|
|
|
|
hold_string[i] = 0;
|
|
|
|
i = i - 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
int get_token(int c)
|
|
|
|
{
|
|
|
|
struct token_list* current = calloc(1, sizeof(struct token_list));
|
|
|
|
|
|
|
|
reset:
|
|
|
|
reset_hold_string();
|
|
|
|
string_index = 0;
|
|
|
|
|
|
|
|
c = clearWhiteSpace(c);
|
|
|
|
if('#' == c)
|
|
|
|
{
|
|
|
|
c = purge_macro(c);
|
|
|
|
goto reset;
|
|
|
|
}
|
|
|
|
else if(in_set(c, "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_"))
|
|
|
|
{
|
|
|
|
c = preserve_keyword(c);
|
|
|
|
}
|
|
|
|
else if(in_set(c, "<=>|&!-"))
|
|
|
|
{
|
|
|
|
c = preserve_symbol(c);
|
|
|
|
}
|
|
|
|
else if(c == '\'')
|
|
|
|
{ /* 39 == ' */
|
|
|
|
c = consume_word(c, '\'');
|
|
|
|
}
|
|
|
|
else if(c == '"')
|
|
|
|
{
|
|
|
|
c = consume_word(c, '"');
|
|
|
|
}
|
|
|
|
else if(c == '/')
|
|
|
|
{
|
|
|
|
c = consume_byte(c);
|
|
|
|
if(c == '*')
|
|
|
|
{
|
|
|
|
c = fgetc(input);
|
|
|
|
while(c != '/')
|
|
|
|
{
|
|
|
|
while(c != '*')
|
|
|
|
{
|
|
|
|
c = fgetc(input);
|
|
|
|
if(10 == c) line = line + 1;
|
|
|
|
}
|
|
|
|
c = fgetc(input);
|
|
|
|
if(10 == c) line = line + 1;
|
|
|
|
}
|
|
|
|
c = fgetc(input);
|
|
|
|
goto reset;
|
|
|
|
}
|
|
|
|
else if(c == '/')
|
|
|
|
{
|
|
|
|
c = fgetc(input);
|
|
|
|
goto reset;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if(c == EOF)
|
|
|
|
{
|
|
|
|
free(current);
|
|
|
|
return c;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
c = consume_byte(c);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* More efficiently allocate memory for string */
|
|
|
|
current->s = calloc(string_index + 2, sizeof(char));
|
|
|
|
copy_string(current->s, hold_string);
|
|
|
|
|
|
|
|
current->prev = token;
|
|
|
|
current->next = token;
|
|
|
|
current->linenumber = line;
|
|
|
|
current->filename = file;
|
|
|
|
token = current;
|
|
|
|
return c;
|
|
|
|
}
|
|
|
|
|
|
|
|
struct token_list* reverse_list(struct token_list* head)
|
|
|
|
{
|
|
|
|
struct token_list* root = NULL;
|
|
|
|
while(NULL != head)
|
|
|
|
{
|
|
|
|
struct token_list* next = head->next;
|
|
|
|
head->next = root;
|
|
|
|
root = head;
|
|
|
|
head = next;
|
|
|
|
}
|
|
|
|
return root;
|
|
|
|
}
|
|
|
|
|
|
|
|
struct token_list* read_all_tokens(FILE* a, struct token_list* current, char* filename)
|
|
|
|
{
|
|
|
|
input = a;
|
|
|
|
line = 1;
|
|
|
|
file = filename;
|
|
|
|
token = current;
|
|
|
|
int ch =fgetc(input);
|
|
|
|
while(EOF != ch) ch = get_token(ch);
|
|
|
|
|
|
|
|
return token;
|
|
|
|
}
|
|
|
|
/* Copyright (C) 2016 Jeremiah Orians
|
2018-09-01 00:08:06 +01:00
|
|
|
* Copyright (C) 2018 Jan (janneke) Nieuwenhuizen <janneke@gnu.org>
|
2018-08-26 17:12:30 +01:00
|
|
|
* This file is part of stage0.
|
|
|
|
*
|
|
|
|
* stage0 is free software: you can redistribute it and/or modify
|
|
|
|
* it under the terms of the GNU General Public License as published by
|
|
|
|
* the Free Software Foundation, either version 3 of the License, or
|
|
|
|
* (at your option) any later version.
|
|
|
|
*
|
|
|
|
* stage0 is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
* GNU General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU General Public License
|
|
|
|
* along with stage0. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "cc.h"
|
|
|
|
#include <stdint.h>
|
|
|
|
|
|
|
|
struct token_list* emit(char *s, struct token_list* head);
|
|
|
|
int char2hex(int c);
|
|
|
|
|
|
|
|
char upcase(char a)
|
|
|
|
{
|
|
|
|
if(in_set(a, "abcdefghijklmnopqrstuvwxyz"))
|
|
|
|
{
|
|
|
|
a = a - 32;
|
|
|
|
}
|
|
|
|
|
|
|
|
return a;
|
|
|
|
}
|
|
|
|
|
|
|
|
int hexify(int c, int high)
|
|
|
|
{
|
|
|
|
int i = char2hex(c);
|
|
|
|
|
|
|
|
if(0 > i)
|
|
|
|
{
|
|
|
|
file_print("Tried to print non-hex number\n", stderr);
|
|
|
|
exit(EXIT_FAILURE);
|
|
|
|
}
|
|
|
|
|
|
|
|
if(high)
|
|
|
|
{
|
|
|
|
i = i << 4;
|
|
|
|
}
|
|
|
|
return i;
|
|
|
|
}
|
|
|
|
|
|
|
|
int escape_lookup(char* c);
|
|
|
|
int weird(char* string)
|
|
|
|
{
|
|
|
|
int c;
|
|
|
|
string = string + 1;
|
|
|
|
weird_reset:
|
|
|
|
c = string[0];
|
|
|
|
if(0 == c) return FALSE;
|
|
|
|
if('\\' == c)
|
|
|
|
{
|
|
|
|
c = escape_lookup(string);
|
|
|
|
if('x' == string[1]) string = string + 2;
|
|
|
|
string = string + 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(!in_set(c, "\t\n !#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~")) return TRUE;
|
|
|
|
if(in_set(c, " \t\n\r") && (':' == string[1])) return TRUE;
|
|
|
|
string = string + 1;
|
|
|
|
goto weird_reset;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Lookup escape values */
|
|
|
|
int escape_lookup(char* c)
|
|
|
|
{
|
|
|
|
if('\\' != c[0]) return c[0];
|
|
|
|
|
|
|
|
if(c[1] == 'x')
|
|
|
|
{
|
|
|
|
int t1 = hexify(c[2], TRUE);
|
|
|
|
int t2 = hexify(c[3], FALSE);
|
|
|
|
return t1 + t2;
|
|
|
|
}
|
|
|
|
else if(c[1] == 't') return 9;
|
2018-09-01 00:08:06 +01:00
|
|
|
else if(c[1] == 'n') return 10;
|
|
|
|
else if(c[1] == 'v') return 11;
|
|
|
|
else if(c[1] == 'f') return 12;
|
2018-08-26 17:12:30 +01:00
|
|
|
else if(c[1] == 'r') return 13;
|
2018-09-01 00:08:06 +01:00
|
|
|
else if(c[1] == 'e') return 27;
|
|
|
|
else if(c[1] == '"') return 34;
|
|
|
|
else if(c[1] == '\'') return 39;
|
|
|
|
else if(c[1] == '\\') return 92;
|
2018-08-26 17:12:30 +01:00
|
|
|
|
2019-10-23 19:46:52 +01:00
|
|
|
file_print("Unknown escape received: ", stderr);
|
2018-08-26 17:12:30 +01:00
|
|
|
file_print(c, stderr);
|
|
|
|
file_print(" Unable to process\n", stderr);
|
|
|
|
exit(EXIT_FAILURE);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Deal with human strings */
|
|
|
|
char* collect_regular_string(char* string)
|
|
|
|
{
|
|
|
|
string_index = 0;
|
|
|
|
|
|
|
|
collect_regular_string_reset:
|
|
|
|
if(string[0] == '\\')
|
|
|
|
{
|
|
|
|
hold_string[string_index] = escape_lookup(string);
|
|
|
|
if (string[1] == 'x') string = string + 2;
|
|
|
|
string = string + 2;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
hold_string[string_index] = string[0];
|
|
|
|
string = string + 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
string_index = string_index + 1;
|
|
|
|
if(string[0] != 0) goto collect_regular_string_reset;
|
|
|
|
|
|
|
|
hold_string[string_index] = '"';
|
|
|
|
hold_string[string_index + 1] = '\n';
|
|
|
|
char* message = calloc(string_index + 3, sizeof(char));
|
|
|
|
copy_string(message, hold_string);
|
|
|
|
reset_hold_string();
|
|
|
|
return message;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Deal with non-human strings */
|
|
|
|
char* collect_weird_string(char* string)
|
|
|
|
{
|
|
|
|
string_index = 1;
|
|
|
|
int temp;
|
|
|
|
char* table = "0123456789ABCDEF";
|
|
|
|
|
|
|
|
hold_string[0] = '\'';
|
|
|
|
collect_weird_string_reset:
|
|
|
|
string = string + 1;
|
|
|
|
hold_string[string_index] = ' ';
|
|
|
|
temp = escape_lookup(string);
|
|
|
|
hold_string[string_index + 1] = table[(temp >> 4)];
|
|
|
|
hold_string[string_index + 2] = table[(temp & 15)];
|
|
|
|
|
|
|
|
if(string[0] == '\\')
|
|
|
|
{
|
|
|
|
if(string[1] == 'x') string = string + 2;
|
|
|
|
string = string + 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
string_index = string_index + 3;
|
|
|
|
if(string[1] != 0) goto collect_weird_string_reset;
|
|
|
|
|
|
|
|
hold_string[string_index] = ' ';
|
|
|
|
hold_string[string_index + 1] = '0';
|
|
|
|
hold_string[string_index + 2] = '0';
|
|
|
|
hold_string[string_index + 3] = '\'';
|
|
|
|
hold_string[string_index + 4] = '\n';
|
|
|
|
|
|
|
|
char* hold = calloc(string_index + 6, sizeof(char));
|
|
|
|
copy_string(hold, hold_string);
|
|
|
|
reset_hold_string();
|
|
|
|
return hold;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Parse string to deal with hex characters*/
|
|
|
|
char* parse_string(char* string)
|
|
|
|
{
|
|
|
|
/* the string */
|
|
|
|
if(weird(string)) return collect_weird_string(string);
|
|
|
|
else return collect_regular_string(string);
|
|
|
|
}
|
|
|
|
/* Copyright (C) 2016 Jeremiah Orians
|
|
|
|
* This file is part of stage0.
|
|
|
|
*
|
|
|
|
* stage0 is free software: you can redistribute it and/or modify
|
|
|
|
* it under the terms of the GNU General Public License as published by
|
|
|
|
* the Free Software Foundation, either version 3 of the License, or
|
|
|
|
* (at your option) any later version.
|
|
|
|
*
|
|
|
|
* stage0 is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
* GNU General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU General Public License
|
|
|
|
* along with stage0. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "cc.h"
|
|
|
|
#include <stdint.h>
|
|
|
|
void line_error();
|
|
|
|
int numerate_string(char *a);
|
|
|
|
|
|
|
|
/* Initialize default types */
|
|
|
|
void initialize_types()
|
|
|
|
{
|
|
|
|
/* Define void */
|
|
|
|
global_types = calloc(1, sizeof(struct type));
|
|
|
|
global_types->name = "void";
|
|
|
|
global_types->size = 4;
|
|
|
|
global_types->type = global_types;
|
|
|
|
/* void* has the same properties as void */
|
|
|
|
global_types->indirect = global_types;
|
|
|
|
|
|
|
|
/* Define int */
|
|
|
|
struct type* a = calloc(1, sizeof(struct type));
|
|
|
|
a->name = "int";
|
|
|
|
a->size = 4;
|
|
|
|
/* int* has the same properties as int */
|
|
|
|
a->indirect = a;
|
|
|
|
a->type = a;
|
|
|
|
|
|
|
|
/* Define char* */
|
|
|
|
struct type* b = calloc(1, sizeof(struct type));
|
|
|
|
b->name = "char*";
|
|
|
|
b->size = 4;
|
|
|
|
b->type = b;
|
|
|
|
|
|
|
|
/* Define char */
|
|
|
|
struct type* c = calloc(1, sizeof(struct type));
|
|
|
|
c->name = "char";
|
|
|
|
c->size = 1;
|
|
|
|
c->type = c;
|
|
|
|
|
|
|
|
/* Define char** */
|
|
|
|
struct type* d = calloc(1, sizeof(struct type));
|
|
|
|
d->name = "char**";
|
|
|
|
d->size = 4;
|
2018-10-17 23:25:11 +01:00
|
|
|
d->type = b;
|
2018-08-26 17:12:30 +01:00
|
|
|
d->indirect = d;
|
|
|
|
|
|
|
|
/*fix up indrects for chars */
|
|
|
|
c->indirect = b;
|
|
|
|
b->indirect = d;
|
|
|
|
|
|
|
|
/* Define FILE */
|
|
|
|
struct type* e = calloc(1, sizeof(struct type));
|
|
|
|
e->name = "FILE";
|
|
|
|
e->size = 4;
|
|
|
|
e->type = e;
|
|
|
|
/* FILE* has the same properties as FILE */
|
|
|
|
e->indirect = e;
|
|
|
|
|
|
|
|
/* Define FUNCTION */
|
|
|
|
struct type* f = calloc(1, sizeof(struct type));
|
|
|
|
f->name = "FUNCTION";
|
|
|
|
f->size = 4;
|
|
|
|
f->type = f;
|
|
|
|
/* FUNCTION* has the same properties as FUNCTION */
|
|
|
|
f->indirect = f;
|
|
|
|
|
|
|
|
/* Define UNSIGNED */
|
|
|
|
struct type* g = calloc(1, sizeof(struct type));
|
|
|
|
g->name = "unsigned";
|
|
|
|
g->size = 4;
|
|
|
|
g->type = g;
|
|
|
|
/* unsigned* has the same properties as unsigned */
|
|
|
|
g->indirect = g;
|
|
|
|
|
|
|
|
/* Finalize type list */
|
|
|
|
f->next = g;
|
|
|
|
e->next = f;
|
|
|
|
d->next = e;
|
|
|
|
c->next = e;
|
|
|
|
a->next = c;
|
|
|
|
global_types->next = a;
|
|
|
|
prim_types = global_types;
|
|
|
|
}
|
|
|
|
|
|
|
|
struct type* lookup_type(char* s, struct type* start)
|
|
|
|
{
|
|
|
|
struct type* i;
|
|
|
|
for(i = start; NULL != i; i = i->next)
|
|
|
|
{
|
|
|
|
if(match(i->name, s))
|
|
|
|
{
|
|
|
|
return i;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
struct type* lookup_member(struct type* parent, char* name)
|
|
|
|
{
|
|
|
|
struct type* i;
|
|
|
|
for(i = parent->members; NULL != i; i = i->members)
|
|
|
|
{
|
|
|
|
if(match(i->name, name)) return i;
|
|
|
|
}
|
|
|
|
|
|
|
|
file_print("ERROR in lookup_member ", stderr);
|
|
|
|
file_print(parent->name, stderr);
|
|
|
|
file_print("->", stderr);
|
|
|
|
file_print(global_token->s, stderr);
|
|
|
|
file_print(" does not exist\n", stderr);
|
|
|
|
line_error();
|
|
|
|
file_print("\n", stderr);
|
|
|
|
exit(EXIT_FAILURE);
|
|
|
|
}
|
|
|
|
|
|
|
|
struct type* type_name();
|
|
|
|
void require_match(char* message, char* required);
|
|
|
|
|
|
|
|
int member_size;
|
|
|
|
struct type* build_member(struct type* last, int offset)
|
|
|
|
{
|
|
|
|
struct type* member_type = type_name();
|
|
|
|
struct type* i = calloc(1, sizeof(struct type));
|
|
|
|
i->name = global_token->s;
|
|
|
|
global_token = global_token->next;
|
|
|
|
i->members = last;
|
|
|
|
|
|
|
|
/* Check to see if array */
|
|
|
|
if(match( "[", global_token->s))
|
|
|
|
{
|
|
|
|
global_token = global_token->next;
|
|
|
|
i->size = member_type->type->size * numerate_string(global_token->s);
|
|
|
|
global_token = global_token->next;
|
|
|
|
require_match("Struct only supports [num] form\n", "]");
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
i->size = member_type->size;
|
|
|
|
}
|
|
|
|
member_size = i->size;
|
|
|
|
i->type = member_type;
|
|
|
|
i->offset = offset;
|
|
|
|
return i;
|
|
|
|
}
|
|
|
|
|
|
|
|
struct type* build_union(struct type* last, int offset)
|
|
|
|
{
|
|
|
|
int size = 0;
|
|
|
|
global_token = global_token->next;
|
|
|
|
require_match("ERROR in build_union\nMissing {\n", "{");
|
|
|
|
while('}' != global_token->s[0])
|
|
|
|
{
|
|
|
|
last = build_member(last, offset);
|
|
|
|
if(member_size > size)
|
|
|
|
{
|
|
|
|
size = member_size;
|
|
|
|
}
|
|
|
|
require_match("ERROR in build_union\nMissing ;\n", ";");
|
|
|
|
}
|
|
|
|
member_size = size;
|
|
|
|
global_token = global_token->next;
|
|
|
|
return last;
|
|
|
|
}
|
|
|
|
|
|
|
|
void create_struct()
|
|
|
|
{
|
|
|
|
int offset = 0;
|
|
|
|
member_size = 0;
|
|
|
|
struct type* head = calloc(1, sizeof(struct type));
|
|
|
|
struct type* i = calloc(1, sizeof(struct type));
|
|
|
|
head->name = global_token->s;
|
|
|
|
i->name = global_token->s;
|
|
|
|
head->indirect = i;
|
|
|
|
i->indirect = head;
|
|
|
|
head->next = global_types;
|
|
|
|
global_types = head;
|
|
|
|
global_token = global_token->next;
|
|
|
|
i->size = 4;
|
|
|
|
require_match("ERROR in create_struct\n Missing {\n", "{");
|
|
|
|
struct type* last = NULL;
|
|
|
|
while('}' != global_token->s[0])
|
|
|
|
{
|
|
|
|
if(match(global_token->s, "union"))
|
|
|
|
{
|
|
|
|
last = build_union(last, offset);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
last = build_member(last, offset);
|
|
|
|
}
|
|
|
|
offset = offset + member_size;
|
|
|
|
require_match("ERROR in create_struct\n Missing ;\n", ";");
|
|
|
|
}
|
|
|
|
|
|
|
|
global_token = global_token->next;
|
|
|
|
require_match("ERROR in create_struct\n Missing ;\n", ";");
|
|
|
|
|
|
|
|
head->size = offset;
|
|
|
|
head->members = last;
|
|
|
|
i->members = last;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* type-name:
|
|
|
|
* char *
|
|
|
|
* int
|
|
|
|
* struct
|
|
|
|
* FILE
|
|
|
|
* void
|
|
|
|
*/
|
|
|
|
struct type* type_name()
|
|
|
|
{
|
|
|
|
int structure = match("struct", global_token->s);
|
|
|
|
|
|
|
|
if(structure)
|
|
|
|
{
|
|
|
|
global_token = global_token->next;
|
|
|
|
}
|
|
|
|
|
|
|
|
struct type* ret = lookup_type(global_token->s, global_types);
|
|
|
|
|
|
|
|
if(NULL == ret && !structure)
|
|
|
|
{
|
|
|
|
file_print("Unknown type ", stderr);
|
|
|
|
file_print(global_token->s, stderr);
|
|
|
|
file_print("\n", stderr);
|
|
|
|
line_error();
|
|
|
|
exit(EXIT_FAILURE);
|
|
|
|
}
|
|
|
|
else if(NULL == ret)
|
|
|
|
{
|
|
|
|
create_struct();
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
global_token = global_token->next;
|
|
|
|
|
|
|
|
while(global_token->s[0] == '*')
|
|
|
|
{
|
|
|
|
ret = ret->indirect;
|
|
|
|
global_token = global_token->next;
|
|
|
|
}
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
/* Copyright (C) 2016 Jeremiah Orians
|
2018-09-01 00:08:06 +01:00
|
|
|
* Copyright (C) 2018 Jan (janneke) Nieuwenhuizen <janneke@gnu.org>
|
2018-08-26 17:12:30 +01:00
|
|
|
* This file is part of stage0.
|
|
|
|
*
|
|
|
|
* stage0 is free software: you can redistribute it and/or modify
|
|
|
|
* it under the terms of the GNU General Public License as published by
|
|
|
|
* the Free Software Foundation, either version 3 of the License, or
|
|
|
|
* (at your option) any later version.
|
|
|
|
*
|
|
|
|
* stage0 is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
* GNU General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU General Public License
|
|
|
|
* along with stage0. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "cc.h"
|
|
|
|
#include "gcc_req.h"
|
|
|
|
#include <stdint.h>
|
|
|
|
|
|
|
|
/* Global lists */
|
|
|
|
struct token_list* global_symbol_list;
|
|
|
|
struct token_list* global_function_list;
|
|
|
|
struct token_list* global_constant_list;
|
|
|
|
|
|
|
|
/* Core lists for this file */
|
|
|
|
struct token_list* function;
|
|
|
|
struct token_list* out;
|
|
|
|
|
|
|
|
/* What we are currently working on */
|
|
|
|
struct type* current_target;
|
|
|
|
char* break_target_head;
|
|
|
|
char* break_target_func;
|
|
|
|
char* break_target_num;
|
|
|
|
struct token_list* break_frame;
|
|
|
|
int current_count;
|
|
|
|
struct type* last_type;
|
2018-10-17 23:25:11 +01:00
|
|
|
int Address_of;
|
2018-08-26 17:12:30 +01:00
|
|
|
|
|
|
|
/* Imported functions */
|
|
|
|
char* parse_string(char* string);
|
|
|
|
int escape_lookup(char* c);
|
|
|
|
char* numerate_number(int a);
|
|
|
|
|
|
|
|
|
|
|
|
struct token_list* emit(char *s, struct token_list* head)
|
|
|
|
{
|
|
|
|
struct token_list* t = calloc(1, sizeof(struct token_list));
|
|
|
|
t->next = head;
|
|
|
|
t->s = s;
|
|
|
|
return t;
|
|
|
|
}
|
|
|
|
|
|
|
|
void emit_out(char* s)
|
|
|
|
{
|
|
|
|
out = emit(s, out);
|
|
|
|
}
|
|
|
|
|
|
|
|
struct token_list* uniqueID(char* s, struct token_list* l, char* num)
|
|
|
|
{
|
|
|
|
l = emit(s, l);
|
|
|
|
l = emit("_", l);
|
|
|
|
l = emit(num, l);
|
|
|
|
l = emit("\n", l);
|
|
|
|
return l;
|
|
|
|
}
|
|
|
|
|
|
|
|
void uniqueID_out(char* s, char* num)
|
|
|
|
{
|
|
|
|
out = uniqueID(s, out, num);
|
|
|
|
}
|
|
|
|
|
|
|
|
struct token_list* sym_declare(char *s, struct type* t, struct token_list* list)
|
|
|
|
{
|
|
|
|
struct token_list* a = calloc(1, sizeof(struct token_list));
|
|
|
|
a->next = list;
|
|
|
|
a->s = s;
|
|
|
|
a->type = t;
|
|
|
|
return a;
|
|
|
|
}
|
|
|
|
|
|
|
|
struct token_list* sym_lookup(char *s, struct token_list* symbol_list)
|
|
|
|
{
|
|
|
|
struct token_list* i;
|
|
|
|
for(i = symbol_list; NULL != i; i = i->next)
|
|
|
|
{
|
|
|
|
if(match(i->s, s)) return i;
|
|
|
|
}
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
void line_error()
|
|
|
|
{
|
|
|
|
file_print(global_token->filename, stderr);
|
2018-09-01 00:08:06 +01:00
|
|
|
file_print(":", stderr);
|
2018-08-26 17:12:30 +01:00
|
|
|
file_print(numerate_number(global_token->linenumber), stderr);
|
2018-09-01 00:08:06 +01:00
|
|
|
file_print(":", stderr);
|
2018-08-26 17:12:30 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
void require_match(char* message, char* required)
|
|
|
|
{
|
|
|
|
if(!match(global_token->s, required))
|
|
|
|
{
|
|
|
|
line_error();
|
2018-09-01 00:08:06 +01:00
|
|
|
file_print(message, stderr);
|
2018-08-26 17:12:30 +01:00
|
|
|
exit(EXIT_FAILURE);
|
|
|
|
}
|
|
|
|
global_token = global_token->next;
|
|
|
|
}
|
|
|
|
|
|
|
|
void expression();
|
|
|
|
void function_call(char* s, int bool)
|
|
|
|
{
|
|
|
|
require_match("ERROR in process_expression_list\nNo ( was found\n", "(");
|
|
|
|
int passed = 0;
|
|
|
|
emit_out("PUSH_edi\t# Prevent overwriting in recursion\n");
|
|
|
|
emit_out("PUSH_ebp\t# Protect the old base pointer\n");
|
|
|
|
emit_out("COPY_esp_to_edi\t# Copy new base pointer\n");
|
|
|
|
|
|
|
|
if(global_token->s[0] != ')')
|
|
|
|
{
|
|
|
|
expression();
|
|
|
|
emit_out("PUSH_eax\t#_process_expression1\n");
|
|
|
|
passed = 1;
|
|
|
|
|
|
|
|
while(global_token->s[0] == ',')
|
|
|
|
{
|
|
|
|
global_token = global_token->next;
|
|
|
|
expression();
|
|
|
|
emit_out("PUSH_eax\t#_process_expression2\n");
|
|
|
|
passed = passed + 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
require_match("ERROR in process_expression_list\nNo ) was found\n", ")");
|
|
|
|
|
|
|
|
if(TRUE == bool)
|
|
|
|
{
|
|
|
|
emit_out("LOAD_BASE_ADDRESS_eax %");
|
|
|
|
emit_out(s);
|
|
|
|
emit_out("\nLOAD_INTEGER\n");
|
|
|
|
emit_out("COPY_edi_to_ebp\n");
|
|
|
|
emit_out("CALL_eax\n");
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
emit_out("COPY_edi_to_ebp\n");
|
|
|
|
emit_out("CALL_IMMEDIATE %FUNCTION_");
|
|
|
|
emit_out(s);
|
|
|
|
emit_out("\n");
|
|
|
|
}
|
|
|
|
|
|
|
|
for(; passed > 0; passed = passed - 1)
|
|
|
|
{
|
|
|
|
emit_out("POP_ebx\t# _process_expression_locals\n");
|
|
|
|
}
|
|
|
|
emit_out("POP_ebp\t# Restore old base pointer\n");
|
|
|
|
emit_out("POP_edi\t# Prevent overwrite\n");
|
|
|
|
}
|
|
|
|
|
|
|
|
void constant_load(struct token_list* a)
|
|
|
|
{
|
|
|
|
emit_out("LOAD_IMMEDIATE_eax %");
|
|
|
|
emit_out(a->arguments->s);
|
|
|
|
emit_out("\n");
|
|
|
|
}
|
|
|
|
|
|
|
|
void variable_load(struct token_list* a)
|
|
|
|
{
|
|
|
|
if(match("FUNCTION", a->type->name) && match("(", global_token->s))
|
|
|
|
{
|
|
|
|
function_call(numerate_number(a->depth), TRUE);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
current_target = a->type;
|
|
|
|
emit_out("LOAD_BASE_ADDRESS_eax %");
|
|
|
|
emit_out(numerate_number(a->depth));
|
|
|
|
emit_out("\n");
|
2018-10-17 23:25:11 +01:00
|
|
|
if(TRUE == Address_of) return;
|
2018-08-26 17:12:30 +01:00
|
|
|
if(match("=", global_token->s)) return;
|
|
|
|
|
|
|
|
emit_out("LOAD_INTEGER\n");
|
|
|
|
}
|
|
|
|
|
|
|
|
void function_load(struct token_list* a)
|
|
|
|
{
|
|
|
|
if(match("(", global_token->s))
|
|
|
|
{
|
|
|
|
function_call(a->s, FALSE);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
emit_out("LOAD_IMMEDIATE_eax &FUNCTION_");
|
|
|
|
emit_out(a->s);
|
|
|
|
emit_out("\n");
|
|
|
|
}
|
|
|
|
|
|
|
|
void global_load(struct token_list* a)
|
|
|
|
{
|
|
|
|
current_target = a->type;
|
|
|
|
emit_out("LOAD_IMMEDIATE_eax &GLOBAL_");
|
|
|
|
emit_out(a->s);
|
|
|
|
emit_out("\n");
|
|
|
|
if(!match("=", global_token->s)) emit_out("LOAD_INTEGER\n");
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* primary-expr:
|
|
|
|
* FAILURE
|
|
|
|
* "String"
|
|
|
|
* 'Char'
|
|
|
|
* [0-9]*
|
|
|
|
* [a-z,A-Z]*
|
|
|
|
* ( expression )
|
|
|
|
*/
|
|
|
|
|
|
|
|
void primary_expr_failure()
|
|
|
|
{
|
2018-09-01 00:08:06 +01:00
|
|
|
line_error();
|
2019-10-23 19:46:52 +01:00
|
|
|
file_print("Received ", stderr);
|
2018-08-26 17:12:30 +01:00
|
|
|
file_print(global_token->s, stderr);
|
|
|
|
file_print(" in primary_expr\n", stderr);
|
|
|
|
exit(EXIT_FAILURE);
|
|
|
|
}
|
|
|
|
|
|
|
|
void primary_expr_string()
|
|
|
|
{
|
|
|
|
char* number_string = numerate_number(current_count);
|
|
|
|
current_count = current_count + 1;
|
|
|
|
emit_out("LOAD_IMMEDIATE_eax &STRING_");
|
|
|
|
uniqueID_out(function->s, number_string);
|
|
|
|
|
|
|
|
/* The target */
|
|
|
|
strings_list = emit(":STRING_", strings_list);
|
|
|
|
strings_list = uniqueID(function->s, strings_list, number_string);
|
|
|
|
|
|
|
|
/* Parse the string */
|
|
|
|
strings_list = emit(parse_string(global_token->s), strings_list);
|
|
|
|
global_token = global_token->next;
|
|
|
|
}
|
|
|
|
|
|
|
|
void primary_expr_char()
|
|
|
|
{
|
|
|
|
emit_out("LOAD_IMMEDIATE_eax %");
|
|
|
|
emit_out(numerate_number(escape_lookup(global_token->s + 1)));
|
|
|
|
emit_out("\n");
|
|
|
|
global_token = global_token->next;
|
|
|
|
}
|
|
|
|
|
|
|
|
void primary_expr_number()
|
|
|
|
{
|
|
|
|
emit_out("LOAD_IMMEDIATE_eax %");
|
|
|
|
emit_out(global_token->s);
|
|
|
|
emit_out("\n");
|
|
|
|
global_token = global_token->next;
|
|
|
|
}
|
|
|
|
|
|
|
|
void primary_expr_variable()
|
|
|
|
{
|
|
|
|
char* s = global_token->s;
|
|
|
|
global_token = global_token->next;
|
|
|
|
struct token_list* a = sym_lookup(s, global_constant_list);
|
|
|
|
if(NULL != a)
|
|
|
|
{
|
|
|
|
constant_load(a);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
a= sym_lookup(s, function->locals);
|
|
|
|
if(NULL != a)
|
|
|
|
{
|
|
|
|
variable_load(a);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
a = sym_lookup(s, function->arguments);
|
|
|
|
if(NULL != a)
|
|
|
|
{
|
|
|
|
variable_load(a);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
a= sym_lookup(s, global_function_list);
|
|
|
|
if(NULL != a)
|
|
|
|
{
|
|
|
|
function_load(a);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
a = sym_lookup(s, global_symbol_list);
|
|
|
|
if(NULL != a)
|
|
|
|
{
|
|
|
|
global_load(a);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2018-09-01 00:08:06 +01:00
|
|
|
line_error();
|
2018-08-26 17:12:30 +01:00
|
|
|
file_print(s ,stderr);
|
|
|
|
file_print(" is not a defined symbol\n", stderr);
|
|
|
|
exit(EXIT_FAILURE);
|
|
|
|
}
|
|
|
|
|
|
|
|
void primary_expr();
|
|
|
|
struct type* promote_type(struct type* a, struct type* b)
|
|
|
|
{
|
|
|
|
if(NULL == b)
|
|
|
|
{
|
|
|
|
return a;
|
|
|
|
}
|
|
|
|
if(NULL == a)
|
|
|
|
{
|
|
|
|
return b;
|
|
|
|
}
|
|
|
|
|
|
|
|
struct type* i;
|
|
|
|
for(i = global_types; NULL != i; i = i->next)
|
|
|
|
{
|
|
|
|
if(a->name == i->name) break;
|
|
|
|
if(b->name == i->name) break;
|
|
|
|
if(a->name == i->indirect->name) break;
|
|
|
|
if(b->name == i->indirect->name) break;
|
|
|
|
}
|
|
|
|
return i;
|
|
|
|
}
|
|
|
|
|
|
|
|
void common_recursion(FUNCTION f)
|
|
|
|
{
|
|
|
|
last_type = current_target;
|
|
|
|
global_token = global_token->next;
|
|
|
|
emit_out("PUSH_eax\t#_common_recursion\n");
|
|
|
|
f();
|
|
|
|
current_target = promote_type(current_target, last_type);
|
|
|
|
emit_out("POP_ebx\t# _common_recursion\n");
|
|
|
|
}
|
|
|
|
|
|
|
|
void general_recursion( FUNCTION f, char* s, char* name, FUNCTION iterate)
|
|
|
|
{
|
|
|
|
if(match(name, global_token->s))
|
|
|
|
{
|
|
|
|
common_recursion(f);
|
|
|
|
emit_out(s);
|
|
|
|
iterate();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
int ceil_log2(int a)
|
|
|
|
{
|
|
|
|
int result = 0;
|
|
|
|
if((a & (a - 1)) == 0)
|
|
|
|
{
|
|
|
|
result = -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
while(a > 0)
|
|
|
|
{
|
|
|
|
result = result + 1;
|
|
|
|
a = a >> 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* postfix-expr:
|
|
|
|
* primary-expr
|
|
|
|
* postfix-expr [ expression ]
|
|
|
|
* postfix-expr ( expression-list-opt )
|
|
|
|
* postfix-expr -> member
|
|
|
|
*/
|
|
|
|
struct type* lookup_member(struct type* parent, char* name);
|
|
|
|
void postfix_expr_arrow()
|
|
|
|
{
|
|
|
|
emit_out("# looking up offset\n");
|
|
|
|
global_token = global_token->next;
|
|
|
|
|
|
|
|
struct type* i = lookup_member(current_target, global_token->s);
|
|
|
|
current_target = i->type;
|
|
|
|
global_token = global_token->next;
|
|
|
|
|
|
|
|
if(0 != i->offset)
|
|
|
|
{
|
|
|
|
emit_out("# -> offset calculation\n");
|
|
|
|
emit_out("LOAD_IMMEDIATE_ebx %");
|
|
|
|
emit_out(numerate_number(i->offset));
|
|
|
|
emit_out("\nADD_ebx_to_eax\n");
|
|
|
|
}
|
|
|
|
|
2018-10-17 23:25:11 +01:00
|
|
|
if((!match("=", global_token->s) && (4 >= i->size)))
|
2018-08-26 17:12:30 +01:00
|
|
|
{
|
|
|
|
emit_out("LOAD_INTEGER\n");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void postfix_expr_array()
|
|
|
|
{
|
|
|
|
struct type* array = current_target;
|
|
|
|
common_recursion(expression);
|
|
|
|
current_target = array;
|
|
|
|
char* assign = "LOAD_INTEGER\n";
|
|
|
|
|
|
|
|
/* Add support for Ints */
|
|
|
|
if(match("char*", current_target->name))
|
|
|
|
{
|
|
|
|
assign = "LOAD_BYTE\n";
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
emit_out("SAL_eax_Immediate8 !");
|
|
|
|
emit_out(numerate_number(ceil_log2(current_target->indirect->size)));
|
|
|
|
emit_out("\n");
|
|
|
|
}
|
|
|
|
|
|
|
|
emit_out("ADD_ebx_to_eax\n");
|
|
|
|
require_match("ERROR in postfix_expr\nMissing ]\n", "]");
|
|
|
|
|
|
|
|
if(match("=", global_token->s))
|
|
|
|
{
|
|
|
|
assign = "";
|
|
|
|
}
|
|
|
|
|
|
|
|
emit_out(assign);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* unary-expr:
|
|
|
|
* postfix-expr
|
|
|
|
* - postfix-expr
|
|
|
|
* !postfix-expr
|
|
|
|
* sizeof ( type )
|
|
|
|
*/
|
|
|
|
struct type* type_name();
|
|
|
|
void unary_expr_sizeof()
|
|
|
|
{
|
|
|
|
global_token = global_token->next;
|
|
|
|
require_match("ERROR in unary_expr\nMissing (\n", "(");
|
|
|
|
struct type* a = type_name();
|
|
|
|
require_match("ERROR in unary_expr\nMissing )\n", ")");
|
|
|
|
|
|
|
|
emit_out("LOAD_IMMEDIATE_eax %");
|
|
|
|
emit_out(numerate_number(a->size));
|
|
|
|
emit_out("\n");
|
|
|
|
}
|
|
|
|
|
|
|
|
void postfix_expr_stub()
|
|
|
|
{
|
|
|
|
if(match("[", global_token->s))
|
|
|
|
{
|
|
|
|
postfix_expr_array();
|
|
|
|
postfix_expr_stub();
|
|
|
|
}
|
|
|
|
|
|
|
|
if(match("->", global_token->s))
|
|
|
|
{
|
|
|
|
postfix_expr_arrow();
|
|
|
|
postfix_expr_stub();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void postfix_expr()
|
|
|
|
{
|
|
|
|
primary_expr();
|
|
|
|
postfix_expr_stub();
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* additive-expr:
|
|
|
|
* postfix-expr
|
|
|
|
* additive-expr * postfix-expr
|
|
|
|
* additive-expr / postfix-expr
|
|
|
|
* additive-expr % postfix-expr
|
|
|
|
* additive-expr + postfix-expr
|
|
|
|
* additive-expr - postfix-expr
|
|
|
|
* additive-expr << postfix-expr
|
|
|
|
* additive-expr >> postfix-expr
|
|
|
|
*/
|
|
|
|
void additive_expr_stub()
|
|
|
|
{
|
|
|
|
general_recursion(postfix_expr, "ADD_ebx_to_eax\n", "+", additive_expr_stub);
|
|
|
|
general_recursion(postfix_expr, "SUBTRACT_eax_from_ebx_into_ebx\nMOVE_ebx_to_eax\n", "-", additive_expr_stub);
|
|
|
|
general_recursion(postfix_expr, "MULTIPLY_eax_by_ebx_into_eax\n", "*", additive_expr_stub);
|
|
|
|
general_recursion(postfix_expr, "XCHG_eax_ebx\nLOAD_IMMEDIATE_edx %0\nDIVIDE_eax_by_ebx_into_eax\n", "/", additive_expr_stub);
|
|
|
|
general_recursion(postfix_expr, "XCHG_eax_ebx\nLOAD_IMMEDIATE_edx %0\nMODULUS_eax_from_ebx_into_ebx\nMOVE_edx_to_eax\n", "%", additive_expr_stub);
|
|
|
|
general_recursion(postfix_expr, "COPY_eax_to_ecx\nCOPY_ebx_to_eax\nSAL_eax_cl\n", "<<", additive_expr_stub);
|
|
|
|
general_recursion(postfix_expr, "COPY_eax_to_ecx\nCOPY_ebx_to_eax\nSAR_eax_cl\n", ">>", additive_expr_stub);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void additive_expr()
|
|
|
|
{
|
|
|
|
postfix_expr();
|
|
|
|
additive_expr_stub();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* relational-expr:
|
|
|
|
* additive_expr
|
|
|
|
* relational-expr < additive_expr
|
|
|
|
* relational-expr <= additive_expr
|
|
|
|
* relational-expr >= additive_expr
|
|
|
|
* relational-expr > additive_expr
|
|
|
|
*/
|
|
|
|
|
|
|
|
void relational_expr_stub()
|
|
|
|
{
|
|
|
|
general_recursion(additive_expr, "CMP\nSETL\nMOVEZBL\n", "<", relational_expr_stub);
|
|
|
|
general_recursion(additive_expr, "CMP\nSETLE\nMOVEZBL\n", "<=", relational_expr_stub);
|
|
|
|
general_recursion(additive_expr, "CMP\nSETGE\nMOVEZBL\n", ">=", relational_expr_stub);
|
|
|
|
general_recursion(additive_expr, "CMP\nSETG\nMOVEZBL\n", ">", relational_expr_stub);
|
|
|
|
general_recursion(additive_expr, "CMP\nSETE\nMOVEZBL\n", "==", relational_expr_stub);
|
|
|
|
general_recursion(additive_expr, "CMP\nSETNE\nMOVEZBL\n", "!=", relational_expr_stub);
|
|
|
|
}
|
|
|
|
|
|
|
|
void relational_expr()
|
|
|
|
{
|
|
|
|
additive_expr();
|
|
|
|
relational_expr_stub();
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* bitwise-expr:
|
|
|
|
* relational-expr
|
|
|
|
* bitwise-expr & bitwise-expr
|
|
|
|
* bitwise-expr && bitwise-expr
|
|
|
|
* bitwise-expr | bitwise-expr
|
|
|
|
* bitwise-expr || bitwise-expr
|
|
|
|
* bitwise-expr ^ bitwise-expr
|
|
|
|
*/
|
|
|
|
void bitwise_expr_stub()
|
|
|
|
{
|
|
|
|
general_recursion(relational_expr, "AND_eax_ebx\n", "&", bitwise_expr_stub);
|
|
|
|
general_recursion(relational_expr, "AND_eax_ebx\n", "&&", bitwise_expr_stub);
|
|
|
|
general_recursion(relational_expr, "OR_eax_ebx\n", "|", bitwise_expr_stub);
|
|
|
|
general_recursion(relational_expr, "OR_eax_ebx\n", "||", bitwise_expr_stub);
|
|
|
|
general_recursion(relational_expr, "XOR_ebx_eax_into_eax\n", "^", bitwise_expr_stub);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void bitwise_expr()
|
|
|
|
{
|
|
|
|
relational_expr();
|
|
|
|
bitwise_expr_stub();
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* expression:
|
|
|
|
* bitwise-or-expr
|
|
|
|
* bitwise-or-expr = expression
|
|
|
|
*/
|
|
|
|
|
|
|
|
void primary_expr()
|
|
|
|
{
|
2018-10-17 23:25:11 +01:00
|
|
|
if(match("&", global_token->s))
|
|
|
|
{
|
|
|
|
Address_of = TRUE;
|
|
|
|
global_token = global_token->next;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
Address_of = FALSE;
|
|
|
|
}
|
|
|
|
|
2018-08-26 17:12:30 +01:00
|
|
|
if(match("sizeof", global_token->s)) unary_expr_sizeof();
|
|
|
|
else if('-' == global_token->s[0])
|
|
|
|
{
|
|
|
|
emit_out("LOAD_IMMEDIATE_eax %0\n");
|
|
|
|
common_recursion(primary_expr);
|
|
|
|
emit_out("SUBTRACT_eax_from_ebx_into_ebx\nMOVE_ebx_to_eax\n");
|
|
|
|
}
|
|
|
|
else if('!' == global_token->s[0])
|
|
|
|
{
|
|
|
|
emit_out("LOAD_IMMEDIATE_eax %1\n");
|
|
|
|
common_recursion(postfix_expr);
|
|
|
|
emit_out("XOR_ebx_eax_into_eax\n");
|
|
|
|
}
|
|
|
|
else if(global_token->s[0] == '(')
|
|
|
|
{
|
|
|
|
global_token = global_token->next;
|
|
|
|
expression();
|
|
|
|
require_match("Error in Primary expression\nDidn't get )\n", ")");
|
|
|
|
}
|
|
|
|
else if(global_token->s[0] == '\'') primary_expr_char();
|
|
|
|
else if(global_token->s[0] == '"') primary_expr_string();
|
|
|
|
else if(in_set(global_token->s[0], "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_")) primary_expr_variable();
|
|
|
|
else if(in_set(global_token->s[0], "0123456789")) primary_expr_number();
|
|
|
|
else primary_expr_failure();
|
|
|
|
}
|
|
|
|
|
|
|
|
void expression()
|
|
|
|
{
|
|
|
|
bitwise_expr();
|
|
|
|
if(match("=", global_token->s))
|
|
|
|
{
|
|
|
|
char* store;
|
|
|
|
if(!match("]", global_token->prev->s) || !match("char*", current_target->name))
|
|
|
|
{
|
|
|
|
store = "STORE_INTEGER\n";
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
store = "STORE_CHAR\n";
|
|
|
|
}
|
|
|
|
|
|
|
|
common_recursion(expression);
|
|
|
|
emit_out(store);
|
|
|
|
current_target = NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* Process local variable */
|
|
|
|
void collect_local()
|
|
|
|
{
|
|
|
|
struct type* type_size = type_name();
|
|
|
|
struct token_list* a = sym_declare(global_token->s, type_size, function->locals);
|
|
|
|
if(match("main", function->s) && (NULL == function->locals))
|
|
|
|
{
|
2018-10-17 23:25:11 +01:00
|
|
|
a->depth = -20;
|
2018-08-26 17:12:30 +01:00
|
|
|
}
|
|
|
|
else if((NULL == function->arguments) && (NULL == function->locals))
|
|
|
|
{
|
|
|
|
a->depth = -8;
|
|
|
|
}
|
|
|
|
else if(NULL == function->locals)
|
|
|
|
{
|
|
|
|
a->depth = function->arguments->depth - 8;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
a->depth = function->locals->depth - 4;
|
|
|
|
}
|
|
|
|
|
|
|
|
function->locals = a;
|
|
|
|
|
|
|
|
emit_out("# Defining local ");
|
|
|
|
emit_out(global_token->s);
|
|
|
|
emit_out("\n");
|
|
|
|
|
|
|
|
global_token = global_token->next;
|
|
|
|
|
|
|
|
if(match("=", global_token->s))
|
|
|
|
{
|
|
|
|
global_token = global_token->next;
|
|
|
|
expression();
|
|
|
|
}
|
|
|
|
|
|
|
|
require_match("ERROR in collect_local\nMissing ;\n", ";");
|
|
|
|
|
|
|
|
emit_out("PUSH_eax\t#");
|
|
|
|
emit_out(a->s);
|
|
|
|
emit_out("\n");
|
|
|
|
}
|
|
|
|
|
|
|
|
void statement();
|
|
|
|
|
|
|
|
/* Evaluate if statements */
|
|
|
|
void process_if()
|
|
|
|
{
|
|
|
|
char* number_string = numerate_number(current_count);
|
|
|
|
current_count = current_count + 1;
|
|
|
|
|
|
|
|
emit_out("# IF_");
|
|
|
|
uniqueID_out(function->s, number_string);
|
|
|
|
|
|
|
|
global_token = global_token->next;
|
|
|
|
require_match("ERROR in process_if\nMISSING (\n", "(");
|
|
|
|
expression();
|
|
|
|
|
|
|
|
emit_out("TEST\nJUMP_EQ %ELSE_");
|
|
|
|
uniqueID_out(function->s, number_string);
|
|
|
|
|
|
|
|
require_match("ERROR in process_if\nMISSING )\n", ")");
|
|
|
|
statement();
|
|
|
|
|
|
|
|
emit_out("JUMP %_END_IF_");
|
|
|
|
uniqueID_out(function->s, number_string);
|
|
|
|
emit_out(":ELSE_");
|
|
|
|
uniqueID_out(function->s, number_string);
|
|
|
|
|
|
|
|
if(match("else", global_token->s))
|
|
|
|
{
|
|
|
|
global_token = global_token->next;
|
|
|
|
statement();
|
|
|
|
}
|
|
|
|
emit_out(":_END_IF_");
|
|
|
|
uniqueID_out(function->s, number_string);
|
|
|
|
}
|
|
|
|
|
|
|
|
void process_for()
|
|
|
|
{
|
|
|
|
struct token_list* nested_locals = break_frame;
|
|
|
|
char* nested_break_head = break_target_head;
|
|
|
|
char* nested_break_func = break_target_func;
|
|
|
|
char* nested_break_num = break_target_num;
|
|
|
|
|
|
|
|
char* number_string = numerate_number(current_count);
|
|
|
|
current_count = current_count + 1;
|
|
|
|
|
|
|
|
break_target_head = "FOR_END_";
|
|
|
|
break_target_num = number_string;
|
|
|
|
break_frame = function->locals;
|
|
|
|
break_target_func = function->s;
|
|
|
|
|
|
|
|
emit_out("# FOR_initialization_");
|
|
|
|
uniqueID_out(function->s, number_string);
|
|
|
|
|
|
|
|
global_token = global_token->next;
|
|
|
|
|
|
|
|
require_match("ERROR in process_for\nMISSING (\n", "(");
|
|
|
|
if(!match(";",global_token->s))
|
|
|
|
{
|
|
|
|
expression();
|
|
|
|
}
|
|
|
|
|
|
|
|
emit_out(":FOR_");
|
|
|
|
uniqueID_out(function->s, number_string);
|
|
|
|
|
|
|
|
require_match("ERROR in process_for\nMISSING ;1\n", ";");
|
|
|
|
expression();
|
|
|
|
|
|
|
|
emit_out("TEST\nJUMP_EQ %FOR_END_");
|
|
|
|
uniqueID_out(function->s, number_string);
|
|
|
|
emit_out("JUMP %FOR_THEN_");
|
|
|
|
uniqueID_out(function->s, number_string);
|
|
|
|
emit_out(":FOR_ITER_");
|
|
|
|
uniqueID_out(function->s, number_string);
|
|
|
|
|
|
|
|
require_match("ERROR in process_for\nMISSING ;2\n", ";");
|
|
|
|
expression();
|
|
|
|
|
|
|
|
emit_out("JUMP %FOR_");
|
|
|
|
uniqueID_out(function->s, number_string);
|
|
|
|
emit_out(":FOR_THEN_");
|
|
|
|
uniqueID_out(function->s, number_string);
|
|
|
|
|
|
|
|
require_match("ERROR in process_for\nMISSING )\n", ")");
|
|
|
|
statement();
|
|
|
|
|
|
|
|
emit_out("JUMP %FOR_ITER_");
|
|
|
|
uniqueID_out(function->s, number_string);
|
|
|
|
emit_out(":FOR_END_");
|
|
|
|
uniqueID_out(function->s, number_string);
|
|
|
|
|
|
|
|
break_target_head = nested_break_head;
|
|
|
|
break_target_func = nested_break_func;
|
|
|
|
break_target_num = nested_break_num;
|
|
|
|
break_frame = nested_locals;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Process Assembly statements */
|
|
|
|
void process_asm()
|
|
|
|
{
|
|
|
|
global_token = global_token->next;
|
|
|
|
require_match("ERROR in process_asm\nMISSING (\n", "(");
|
|
|
|
while(34 == global_token->s[0])
|
|
|
|
{/* 34 == " */
|
|
|
|
emit_out((global_token->s + 1));
|
|
|
|
emit_out("\n");
|
|
|
|
global_token = global_token->next;
|
|
|
|
}
|
|
|
|
require_match("ERROR in process_asm\nMISSING )\n", ")");
|
|
|
|
require_match("ERROR in process_asm\nMISSING ;\n", ";");
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Process do while loops */
|
|
|
|
void process_do()
|
|
|
|
{
|
|
|
|
struct token_list* nested_locals = break_frame;
|
|
|
|
char* nested_break_head = break_target_head;
|
|
|
|
char* nested_break_func = break_target_func;
|
|
|
|
char* nested_break_num = break_target_num;
|
|
|
|
|
|
|
|
char* number_string = numerate_number(current_count);
|
|
|
|
current_count = current_count + 1;
|
|
|
|
|
|
|
|
break_target_head = "DO_END_";
|
|
|
|
break_target_num = number_string;
|
|
|
|
break_frame = function->locals;
|
|
|
|
break_target_func = function->s;
|
|
|
|
|
|
|
|
emit_out(":DO_");
|
|
|
|
uniqueID_out(function->s, number_string);
|
|
|
|
|
|
|
|
global_token = global_token->next;
|
|
|
|
statement();
|
|
|
|
|
|
|
|
require_match("ERROR in process_do\nMISSING while\n", "while");
|
|
|
|
require_match("ERROR in process_do\nMISSING (\n", "(");
|
|
|
|
expression();
|
|
|
|
require_match("ERROR in process_do\nMISSING )\n", ")");
|
|
|
|
require_match("ERROR in process_do\nMISSING ;\n", ";");
|
|
|
|
|
|
|
|
emit_out("TEST\nJUMP_NE %DO_");
|
|
|
|
uniqueID_out(function->s, number_string);
|
|
|
|
emit_out(":DO_END_");
|
|
|
|
uniqueID_out(function->s, number_string);
|
|
|
|
|
|
|
|
break_frame = nested_locals;
|
|
|
|
break_target_head = nested_break_head;
|
|
|
|
break_target_func = nested_break_func;
|
|
|
|
break_target_num = nested_break_num;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* Process while loops */
|
|
|
|
void process_while()
|
|
|
|
{
|
|
|
|
struct token_list* nested_locals = break_frame;
|
|
|
|
char* nested_break_head = break_target_head;
|
|
|
|
char* nested_break_func = break_target_func;
|
|
|
|
char* nested_break_num = break_target_num;
|
|
|
|
|
|
|
|
char* number_string = numerate_number(current_count);
|
|
|
|
current_count = current_count + 1;
|
|
|
|
|
|
|
|
break_target_head = "END_WHILE_";
|
|
|
|
break_target_num = number_string;
|
|
|
|
break_frame = function->locals;
|
|
|
|
break_target_func = function->s;
|
|
|
|
|
|
|
|
emit_out(":WHILE_");
|
|
|
|
uniqueID_out(function->s, number_string);
|
|
|
|
|
|
|
|
global_token = global_token->next;
|
|
|
|
require_match("ERROR in process_while\nMISSING (\n", "(");
|
|
|
|
expression();
|
|
|
|
|
|
|
|
emit_out("TEST\nJUMP_EQ %END_WHILE_");
|
|
|
|
uniqueID_out(function->s, number_string);
|
|
|
|
emit_out("# THEN_while_");
|
|
|
|
uniqueID_out(function->s, number_string);
|
|
|
|
|
|
|
|
require_match("ERROR in process_while\nMISSING )\n", ")");
|
|
|
|
statement();
|
|
|
|
|
|
|
|
emit_out("JUMP %WHILE_");
|
|
|
|
uniqueID_out(function->s, number_string);
|
|
|
|
emit_out(":END_WHILE_");
|
|
|
|
uniqueID_out(function->s, number_string);
|
|
|
|
|
|
|
|
break_target_head = nested_break_head;
|
|
|
|
break_target_func = nested_break_func;
|
|
|
|
break_target_num = nested_break_num;
|
|
|
|
break_frame = nested_locals;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Ensure that functions return */
|
|
|
|
void return_result()
|
|
|
|
{
|
|
|
|
global_token = global_token->next;
|
|
|
|
if(global_token->s[0] != ';') expression();
|
|
|
|
|
|
|
|
require_match("ERROR in return_result\nMISSING ;\n", ";");
|
|
|
|
|
|
|
|
struct token_list* i;
|
|
|
|
for(i = function->locals; NULL != i; i = i->next)
|
|
|
|
{
|
|
|
|
emit_out("POP_ebx\t# _return_result_locals\n");
|
|
|
|
}
|
|
|
|
emit_out("RETURN\n");
|
|
|
|
}
|
|
|
|
|
|
|
|
void process_break()
|
|
|
|
{
|
|
|
|
if(NULL == break_target_head)
|
|
|
|
{
|
|
|
|
line_error();
|
2018-09-01 00:08:06 +01:00
|
|
|
file_print("Not inside of a loop or case statement", stderr);
|
2018-08-26 17:12:30 +01:00
|
|
|
exit(EXIT_FAILURE);
|
|
|
|
}
|
|
|
|
struct token_list* i = function->locals;
|
|
|
|
while(i != break_frame)
|
|
|
|
{
|
|
|
|
if(NULL == i) break;
|
|
|
|
emit_out("POP_ebx\t# break_cleanup_locals\n");
|
|
|
|
i = i->next;
|
|
|
|
}
|
|
|
|
global_token = global_token->next;
|
|
|
|
emit_out("JUMP %");
|
|
|
|
emit_out(break_target_head);
|
|
|
|
emit_out(break_target_func);
|
|
|
|
emit_out("_");
|
|
|
|
emit_out(break_target_num);
|
|
|
|
emit_out("\n");
|
|
|
|
require_match("ERROR in break statement\nMissing ;\n", ";");
|
|
|
|
}
|
|
|
|
|
|
|
|
void recursive_statement()
|
|
|
|
{
|
|
|
|
global_token = global_token->next;
|
|
|
|
struct token_list* frame = function->locals;
|
|
|
|
|
|
|
|
while(!match("}", global_token->s))
|
|
|
|
{
|
|
|
|
statement();
|
|
|
|
}
|
|
|
|
global_token = global_token->next;
|
|
|
|
|
|
|
|
/* Clean up any locals added */
|
|
|
|
if(!match("RETURN\n", out->s))
|
|
|
|
{
|
|
|
|
struct token_list* i;
|
|
|
|
for(i = function->locals; frame != i; i = i->next)
|
|
|
|
{
|
|
|
|
emit_out( "POP_ebx\t# _recursive_statement_locals\n");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
function->locals = frame;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* statement:
|
|
|
|
* { statement-list-opt }
|
|
|
|
* type-name identifier ;
|
|
|
|
* type-name identifier = expression;
|
|
|
|
* if ( expression ) statement
|
|
|
|
* if ( expression ) statement else statement
|
|
|
|
* do statement while ( expression ) ;
|
|
|
|
* while ( expression ) statement
|
|
|
|
* for ( expression ; expression ; expression ) statement
|
|
|
|
* asm ( "assembly" ... "assembly" ) ;
|
|
|
|
* goto label ;
|
|
|
|
* label:
|
|
|
|
* return ;
|
|
|
|
* break ;
|
|
|
|
* expr ;
|
|
|
|
*/
|
|
|
|
|
|
|
|
struct type* lookup_type(char* s, struct type* start);
|
|
|
|
void statement()
|
|
|
|
{
|
|
|
|
if(global_token->s[0] == '{')
|
|
|
|
{
|
|
|
|
recursive_statement();
|
|
|
|
}
|
|
|
|
else if(':' == global_token->s[0])
|
|
|
|
{
|
|
|
|
emit_out(global_token->s);
|
|
|
|
emit_out("\t#C goto label\n");
|
|
|
|
global_token = global_token->next;
|
|
|
|
}
|
|
|
|
else if((NULL != lookup_type(global_token->s, prim_types)) ||
|
|
|
|
match("struct", global_token->s))
|
|
|
|
{
|
|
|
|
collect_local();
|
|
|
|
}
|
|
|
|
else if(match("if", global_token->s))
|
|
|
|
{
|
|
|
|
process_if();
|
|
|
|
}
|
|
|
|
else if(match("do", global_token->s))
|
|
|
|
{
|
|
|
|
process_do();
|
|
|
|
}
|
|
|
|
else if(match("while", global_token->s))
|
|
|
|
{
|
|
|
|
process_while();
|
|
|
|
}
|
|
|
|
else if(match("for", global_token->s))
|
|
|
|
{
|
|
|
|
process_for();
|
|
|
|
}
|
|
|
|
else if(match("asm", global_token->s))
|
|
|
|
{
|
|
|
|
process_asm();
|
|
|
|
}
|
|
|
|
else if(match("goto", global_token->s))
|
|
|
|
{
|
|
|
|
global_token = global_token->next;
|
|
|
|
emit_out("JUMP %");
|
|
|
|
emit_out(global_token->s);
|
|
|
|
emit_out("\n");
|
|
|
|
global_token = global_token->next;
|
|
|
|
require_match("ERROR in statement\nMissing ;\n", ";");
|
|
|
|
}
|
|
|
|
else if(match("return", global_token->s))
|
|
|
|
{
|
|
|
|
return_result();
|
|
|
|
}
|
|
|
|
else if(match("break", global_token->s))
|
|
|
|
{
|
|
|
|
process_break();
|
|
|
|
}
|
|
|
|
else if(match("continue", global_token->s))
|
|
|
|
{
|
|
|
|
global_token = global_token->next;
|
|
|
|
emit_out("\n#continue statement\n");
|
|
|
|
require_match("ERROR in statement\nMissing ;\n", ";");
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
expression();
|
|
|
|
require_match("ERROR in statement\nMISSING ;\n", ";");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Collect function arguments */
|
|
|
|
void collect_arguments()
|
|
|
|
{
|
|
|
|
global_token = global_token->next;
|
|
|
|
|
|
|
|
while(!match(")", global_token->s))
|
|
|
|
{
|
|
|
|
struct type* type_size = type_name();
|
|
|
|
if(global_token->s[0] == ')')
|
|
|
|
{
|
|
|
|
/* foo(int,char,void) doesn't need anything done */
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
else if(global_token->s[0] != ',')
|
|
|
|
{
|
|
|
|
/* deal with foo(int a, char b) */
|
|
|
|
struct token_list* a = sym_declare(global_token->s, type_size, function->arguments);
|
2018-10-17 23:25:11 +01:00
|
|
|
if(NULL == function->arguments)
|
2018-08-26 17:12:30 +01:00
|
|
|
{
|
|
|
|
a->depth = -4;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
a->depth = function->arguments->depth - 4;
|
|
|
|
}
|
|
|
|
|
|
|
|
global_token = global_token->next;
|
|
|
|
function->arguments = a;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* ignore trailing comma (needed for foo(bar(), 1); expressions*/
|
|
|
|
if(global_token->s[0] == ',') global_token = global_token->next;
|
|
|
|
}
|
|
|
|
global_token = global_token->next;
|
|
|
|
}
|
|
|
|
|
|
|
|
void declare_function()
|
|
|
|
{
|
|
|
|
current_count = 0;
|
|
|
|
function = sym_declare(global_token->prev->s, NULL, global_function_list);
|
|
|
|
|
|
|
|
/* allow previously defined functions to be looked up */
|
|
|
|
global_function_list = function;
|
|
|
|
collect_arguments();
|
|
|
|
|
|
|
|
/* If just a prototype don't waste time */
|
|
|
|
if(global_token->s[0] == ';') global_token = global_token->next;
|
|
|
|
else
|
|
|
|
{
|
|
|
|
emit_out("# Defining function ");
|
|
|
|
emit_out(function->s);
|
|
|
|
emit_out("\n");
|
|
|
|
emit_out(":FUNCTION_");
|
|
|
|
emit_out(function->s);
|
|
|
|
emit_out("\n");
|
|
|
|
statement();
|
|
|
|
|
|
|
|
/* Prevent duplicate RETURNS */
|
|
|
|
if(!match("RETURN\n", out->s))
|
|
|
|
{
|
|
|
|
emit_out("RETURN\n");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* program:
|
|
|
|
* declaration
|
|
|
|
* declaration program
|
|
|
|
*
|
|
|
|
* declaration:
|
|
|
|
* CONSTANT identifer value
|
|
|
|
* type-name identifier ;
|
|
|
|
* type-name identifier ( parameter-list ) ;
|
|
|
|
* type-name identifier ( parameter-list ) statement
|
|
|
|
*
|
|
|
|
* parameter-list:
|
|
|
|
* parameter-declaration
|
|
|
|
* parameter-list, parameter-declaration
|
|
|
|
*
|
|
|
|
* parameter-declaration:
|
|
|
|
* type-name identifier-opt
|
|
|
|
*/
|
|
|
|
struct token_list* program()
|
|
|
|
{
|
|
|
|
out = NULL;
|
|
|
|
function = NULL;
|
2018-10-17 23:25:11 +01:00
|
|
|
Address_of = FALSE;
|
2018-08-26 17:12:30 +01:00
|
|
|
struct type* type_size;
|
|
|
|
|
|
|
|
new_type:
|
|
|
|
if (NULL == global_token) return out;
|
|
|
|
if(match("CONSTANT", global_token->s))
|
|
|
|
{
|
|
|
|
global_token = global_token->next;
|
|
|
|
global_constant_list = sym_declare(global_token->s, NULL, global_constant_list);
|
|
|
|
global_constant_list->arguments = global_token->next;
|
|
|
|
global_token = global_token->next->next;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
type_size = type_name();
|
|
|
|
if(NULL == type_size)
|
|
|
|
{
|
|
|
|
goto new_type;
|
|
|
|
}
|
|
|
|
/* Add to global symbol table */
|
|
|
|
global_symbol_list = sym_declare(global_token->s, type_size, global_symbol_list);
|
|
|
|
global_token = global_token->next;
|
|
|
|
if(match(";", global_token->s))
|
|
|
|
{
|
|
|
|
/* Ensure 4 bytes are allocated for the global */
|
|
|
|
globals_list = emit(":GLOBAL_", globals_list);
|
|
|
|
globals_list = emit(global_token->prev->s, globals_list);
|
|
|
|
globals_list = emit("\nNOP\n", globals_list);
|
|
|
|
|
|
|
|
global_token = global_token->next;
|
|
|
|
}
|
|
|
|
else if(match("(", global_token->s)) declare_function();
|
|
|
|
else if(match("=",global_token->s))
|
|
|
|
{
|
|
|
|
/* Store the global's value*/
|
|
|
|
globals_list = emit(":GLOBAL_", globals_list);
|
|
|
|
globals_list = emit(global_token->prev->s, globals_list);
|
|
|
|
globals_list = emit("\n", globals_list);
|
|
|
|
global_token = global_token->next;
|
|
|
|
if(in_set(global_token->s[0], "0123456789"))
|
|
|
|
{ /* Assume Int */
|
|
|
|
globals_list = emit("%", globals_list);
|
|
|
|
globals_list = emit(global_token->s, globals_list);
|
|
|
|
globals_list = emit("\n", globals_list);
|
|
|
|
}
|
|
|
|
else if(('"' == global_token->s[0]))
|
|
|
|
{ /* Assume a string*/
|
|
|
|
globals_list = emit(parse_string(global_token->s), globals_list);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2018-09-01 00:08:06 +01:00
|
|
|
line_error();
|
2019-10-23 19:46:52 +01:00
|
|
|
file_print("Received ", stderr);
|
2018-08-26 17:12:30 +01:00
|
|
|
file_print(global_token->s, stderr);
|
|
|
|
file_print(" in program\n", stderr);
|
|
|
|
exit(EXIT_FAILURE);
|
|
|
|
}
|
|
|
|
|
|
|
|
global_token = global_token->next;
|
|
|
|
require_match("ERROR in Program\nMissing ;\n", ";");
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2018-09-01 00:08:06 +01:00
|
|
|
line_error();
|
2019-10-23 19:46:52 +01:00
|
|
|
file_print("Received ", stderr);
|
2018-08-26 17:12:30 +01:00
|
|
|
file_print(global_token->s, stderr);
|
|
|
|
file_print(" in program\n", stderr);
|
|
|
|
exit(EXIT_FAILURE);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
goto new_type;
|
|
|
|
}
|
|
|
|
|
|
|
|
void recursive_output(struct token_list* i, FILE* out)
|
|
|
|
{
|
|
|
|
if(NULL == i) return;
|
|
|
|
recursive_output(i->next, out);
|
|
|
|
file_print(i->s, out);
|
|
|
|
}
|
|
|
|
/* Copyright (C) 2016 Jeremiah Orians
|
|
|
|
* This file is part of stage0.
|
|
|
|
*
|
|
|
|
* stage0 is free software: you can redistribute it and/or modify
|
|
|
|
* it under the terms of the GNU General Public License as published by
|
|
|
|
* the Free Software Foundation, either version 3 of the License, or
|
|
|
|
* (at your option) any later version.
|
|
|
|
*
|
|
|
|
* stage0 is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
* GNU General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU General Public License
|
|
|
|
* along with stage0. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
*/
|
|
|
|
#include<stdlib.h>
|
|
|
|
#include<stdio.h>
|
|
|
|
#include<string.h>
|
|
|
|
#include"cc.h"
|
|
|
|
|
|
|
|
/* The core functions */
|
|
|
|
void initialize_types();
|
|
|
|
struct token_list* read_all_tokens(FILE* a, struct token_list* current, char* filename);
|
|
|
|
struct token_list* reverse_list(struct token_list* head);
|
|
|
|
struct token_list* program();
|
|
|
|
void recursive_output(struct token_list* i, FILE* out);
|
|
|
|
int match(char* a, char* b);
|
|
|
|
void file_print(char* s, FILE* f);
|
|
|
|
char* parse_string(char* string);
|
|
|
|
|
|
|
|
int main(int argc, char** argv)
|
|
|
|
{
|
|
|
|
hold_string = calloc(MAX_STRING, sizeof(char));
|
|
|
|
int DEBUG = FALSE;
|
|
|
|
FILE* in = stdin;
|
|
|
|
FILE* destination_file = stdout;
|
|
|
|
int i = 1;
|
|
|
|
while(i <= argc)
|
|
|
|
{
|
|
|
|
if(NULL == argv[i])
|
|
|
|
{
|
|
|
|
i = i + 1;
|
|
|
|
}
|
|
|
|
else if(match(argv[i], "-f") || match(argv[i], "--file"))
|
|
|
|
{
|
|
|
|
char* name = argv[i + 1];
|
|
|
|
in = fopen(name, "r");
|
|
|
|
if(NULL == in)
|
|
|
|
{
|
|
|
|
file_print("Unable to open for reading file: ", stderr);
|
|
|
|
file_print(name, stderr);
|
2018-09-01 00:08:06 +01:00
|
|
|
file_print("\n Aborting to avoid problems\n", stderr);
|
2018-08-26 17:12:30 +01:00
|
|
|
exit(EXIT_FAILURE);
|
|
|
|
}
|
|
|
|
global_token = read_all_tokens(in, global_token, name);
|
|
|
|
i = i + 2;
|
|
|
|
}
|
|
|
|
else if(match(argv[i], "-o") || match(argv[i], "--output"))
|
|
|
|
{
|
|
|
|
destination_file = fopen(argv[i + 1], "w");
|
|
|
|
if(NULL == destination_file)
|
|
|
|
{
|
|
|
|
file_print("Unable to open for writing file: ", stderr);
|
|
|
|
file_print(argv[i + 1], stderr);
|
2018-09-01 00:08:06 +01:00
|
|
|
file_print("\n Aborting to avoid problems\n", stderr);
|
2018-08-26 17:12:30 +01:00
|
|
|
exit(EXIT_FAILURE);
|
|
|
|
}
|
|
|
|
i = i + 2;
|
|
|
|
}
|
|
|
|
else if(match(argv[i], "-g") || match(argv[i], "--debug"))
|
|
|
|
{
|
|
|
|
DEBUG = TRUE;
|
|
|
|
i = i + 1;
|
|
|
|
}
|
|
|
|
else if(match(argv[i], "-h") || match(argv[i], "--help"))
|
|
|
|
{
|
2018-09-01 00:08:06 +01:00
|
|
|
file_print(" -f input file\n -o output file\n --help for this message\n --version for file version\n", stdout);
|
2018-08-26 17:12:30 +01:00
|
|
|
exit(EXIT_SUCCESS);
|
|
|
|
}
|
|
|
|
else if(match(argv[i], "-V") || match(argv[i], "--version"))
|
|
|
|
{
|
2018-09-01 00:08:06 +01:00
|
|
|
file_print("M2-Planet v1.0.0\n", stderr);
|
2018-08-26 17:12:30 +01:00
|
|
|
exit(EXIT_SUCCESS);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2018-09-01 00:08:06 +01:00
|
|
|
file_print("UNKNOWN ARGUMENT\n", stdout);
|
2018-08-26 17:12:30 +01:00
|
|
|
exit(EXIT_FAILURE);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Deal with special case of wanting to read from standard input */
|
|
|
|
if(stdin == in)
|
|
|
|
{
|
|
|
|
global_token = read_all_tokens(in, global_token, "STDIN");
|
|
|
|
}
|
|
|
|
|
|
|
|
if(NULL == global_token)
|
|
|
|
{
|
|
|
|
file_print("Either no input files were given or they were empty\n", stderr);
|
|
|
|
exit(EXIT_FAILURE);
|
|
|
|
}
|
|
|
|
global_token = reverse_list(global_token);
|
|
|
|
|
|
|
|
initialize_types();
|
|
|
|
reset_hold_string();
|
|
|
|
struct token_list* output_list = program();
|
|
|
|
|
|
|
|
/* Output the program we have compiled */
|
|
|
|
file_print("\n# Core program\n", destination_file);
|
|
|
|
recursive_output(output_list, destination_file);
|
|
|
|
if(DEBUG) file_print("\n:ELF_data\n", destination_file);
|
|
|
|
file_print("\n# Program global variables\n", destination_file);
|
|
|
|
recursive_output(globals_list, destination_file);
|
|
|
|
file_print("\n# Program strings\n", destination_file);
|
|
|
|
recursive_output(strings_list, destination_file);
|
|
|
|
if(!DEBUG) file_print("\n:ELF_end\n", destination_file);
|
|
|
|
return EXIT_SUCCESS;
|
|
|
|
}
|