Compare commits

..

27 commits

Author SHA1 Message Date
Russell Joyce 4da276b88f
Increased maximum number of function parameters from 16 to 32 2020-06-24 19:17:01 +01:00
Russell Joyce 29ebc3114b
Increased default stack/heap size to 32MiB 2020-06-24 19:16:14 +01:00
Russell Joyce 31b08382db
Added command line option for enabling interpreter stats collection
'-d' or '-d0' to collect and print basic stats, '-d1' etc. for
alternative output formats.
2020-06-24 17:30:27 +01:00
Russell Joyce 97030639f1
Fixed for loop initialisers with variable declarations 2020-06-18 19:18:14 +01:00
Russell Joyce 9d2327b8be
Added support for commas in for loop initialiser statement 2020-06-18 18:41:27 +01:00
Russell Joyce 7b43483f68
Added handling of "short int" type specifier
Just consumes and discards the "int" token and treats as if it was only
a "short".
2020-06-18 17:20:02 +01:00
Russell Joyce 3979f563aa
Added support for commas in for loop update statement 2020-06-18 17:05:10 +01:00
Russell Joyce d04337125e
Added support for extern variable declarations
Effectively just ignores any declarations as global scope is shared
across files in PicoC anyway, so the ultimate definition should be
enough.
2020-06-17 19:57:10 +01:00
Russell Joyce 875a635648
Increased size of temporary variable creation buffer
Allows for larger arrays to be defined and passed around without hitting
the limit, but at a cost of higher stack memory usage in the
VariableAllocValueAndCopy() function.
2020-06-15 18:29:04 +01:00
Russell Joyce 5261facbd7
Fixed bug with typedef, introduced with extra type qualifier parsing
Caused by overwriting the value of the actual type token being parsed by
any following tokens that were examined or consumed, rather than just
ignoring their values.
2020-06-12 15:33:19 +01:00
Russell Joyce 62969cb0ee
Added handling of 'const' type qualifier keyword
There is currently no enforcement of a variable being constant, and the
actual type is the same as if 'const' wasn't present.
2020-06-11 11:30:51 +01:00
Russell Joyce 9fd31b6d37
Added handling of "long int" type specifier
Just consumes and discards the "int" token and treats as if it was only
a "long".
2020-06-10 18:24:12 +01:00
Russell Joyce b403e76600
Added handling of trailing type qualifiers/storage classes
Handles situations such as `int volatile x` rather than `volatile int x`
by consuming the keywords as part of the type specifier.
2020-06-10 18:21:35 +01:00
Russell Joyce 9abf00e2d3
Added basic pragma parsing
Actual contents of the pragma are currently just discarded. This
supports both #pragma and _Pragma() definitions, but the pragma must end
the line it is on and cannot be in the middle of a statement.
2020-06-09 19:21:00 +01:00
Russell Joyce a96902717c
Added stats code to Makefile
For when not using CMake, e.g. when running tests with 'make test'.
2020-06-09 12:52:35 +01:00
Russell Joyce 2597008035
Small modification to loop C test code 2020-06-09 12:31:20 +01:00
Russell Joyce 45d85111f0
Added parsing of volatile qualifier
This doesn't affect code execution, but is exposed through TypeParse().
2020-06-09 12:30:47 +01:00
Russell Joyce 409f520b61
Added functions to log and count parsing of statements and expressions
Currently prints all expressions and statements to stderr, then outputs
a total count of each token to stderr after program execution.
2020-05-13 18:44:09 +01:00
Russell Joyce 72dff522b3
Added some basic example C files for use with debugging/testing 2020-05-13 18:01:14 +01:00
Russell Joyce 4d3a9715ae
Fixed building on MacOS
'F_FULLSYNC' should be 'F_FULLFSYNC', and sbrk system call is deprecated.
2020-05-13 17:13:11 +01:00
Russell Joyce d57c0044b5
Added CMake/CLion project and associated files 2020-05-13 17:11:53 +01:00
Joseph Poirier a97d94fa3d
Merge pull request #21 from jpoirier/develop
Develop
2018-01-17 08:33:58 -06:00
Joseph Poirier bb3c5ef926
Merge pull request #20 from jpoirier/develop
add the last bits of the hack
2018-01-17 00:57:35 -06:00
Joseph Poirier 2e35505e26
Merge pull request #19 from jpoirier/develop
make the ugly hack uglier
2018-01-17 00:44:32 -06:00
Joseph Poirier 345b1defbd
Merge pull request #18 from jpoirier/develop
properly print large long values
2018-01-16 21:08:39 -06:00
Joseph Poirier 4930d786c8
Merge pull request #17 from jpoirier/develop
fix parsing typedef outside of declaration, don't decrement loop counter
2018-01-16 16:16:21 -06:00
Joseph Poirier 7008ce7f9e
Merge pull request #15 from jpoirier/develop
Develop
2018-01-11 23:06:56 -06:00
43 changed files with 1171 additions and 50 deletions

124
.gitignore vendored
View file

@ -9,7 +9,6 @@ picoc
build/* build/*
archives/ archives/
CMakeLists.txt
picoc.plist picoc.plist
picoc.config picoc.config
picoc.creator picoc.creator
@ -21,4 +20,125 @@ tests/fred.txt
analysis.txt analysis.txt
gmon.out gmon.out
tests/gmon.out tests/gmon.out
.idea/
# Created by https://www.gitignore.io/api/macos,clion
# Edit at https://www.gitignore.io/?templates=macos,clion
### CLion ###
# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and WebStorm
# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839
# User-specific stuff
.idea/**/workspace.xml
.idea/**/tasks.xml
.idea/**/usage.statistics.xml
.idea/**/dictionaries
.idea/**/shelf
# Generated files
.idea/**/contentModel.xml
# Sensitive or high-churn files
.idea/**/dataSources/
.idea/**/dataSources.ids
.idea/**/dataSources.local.xml
.idea/**/sqlDataSources.xml
.idea/**/dynamic.xml
.idea/**/uiDesigner.xml
.idea/**/dbnavigator.xml
# Gradle
.idea/**/gradle.xml
.idea/**/libraries
# Gradle and Maven with auto-import
# When using Gradle or Maven with auto-import, you should exclude module files,
# since they will be recreated, and may cause churn. Uncomment if using
# auto-import.
# .idea/modules.xml
# .idea/*.iml
# .idea/modules
# *.iml
# *.ipr
# CMake
cmake-build-*/
# Mongo Explorer plugin
.idea/**/mongoSettings.xml
# File-based project format
*.iws
# IntelliJ
out/
# mpeltonen/sbt-idea plugin
.idea_modules/
# JIRA plugin
atlassian-ide-plugin.xml
# Cursive Clojure plugin
.idea/replstate.xml
# Crashlytics plugin (for Android Studio and IntelliJ)
com_crashlytics_export_strings.xml
crashlytics.properties
crashlytics-build.properties
fabric.properties
# Editor-based Rest Client
.idea/httpRequests
# Android studio 3.1+ serialized cache file
.idea/caches/build_file_checksums.ser
### CLion Patch ###
# Comment Reason: https://github.com/joeblau/gitignore.io/issues/186#issuecomment-215987721
# *.iml
# modules.xml
# .idea/misc.xml
# *.ipr
# Sonarlint plugin
.idea/**/sonarlint/
# SonarQube Plugin
.idea/**/sonarIssues.xml
# Markdown Navigator plugin
.idea/**/markdown-navigator.xml
.idea/**/markdown-navigator/
### macOS ###
# General
.DS_Store
.AppleDouble
.LSOverride
# Icon must end with two \r
Icon
# Thumbnails
._*
# Files that might appear in the root of a volume
.DocumentRevisions-V100
.fseventsd
.Spotlight-V100
.TemporaryItems
.Trashes
.VolumeIcon.icns
.com.apple.timemachine.donotpresent
# Directories potentially created on remote AFP share
.AppleDB
.AppleDesktop
Network Trash Folder
Temporary Items
.apdisk
# End of https://www.gitignore.io/api/macos,clion

View file

@ -0,0 +1,5 @@
<component name="ProjectCodeStyleConfiguration">
<state>
<option name="USE_PER_PROJECT_SETTINGS" value="true" />
</state>
</component>

7
.idea/misc.xml Normal file
View file

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="CMakeWorkspace" PROJECT_DIR="$PROJECT_DIR$" />
<component name="JavaScriptSettings">
<option name="languageLevel" value="ES6" />
</component>
</project>

8
.idea/modules.xml Normal file
View file

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectModuleManager">
<modules>
<module fileurl="file://$PROJECT_DIR$/.idea/picoc.iml" filepath="$PROJECT_DIR$/.idea/picoc.iml" />
</modules>
</component>
</project>

2
.idea/picoc.iml Normal file
View file

@ -0,0 +1,2 @@
<?xml version="1.0" encoding="UTF-8"?>
<module classpath="CMake" type="CPP_MODULE" version="4" />

View file

@ -0,0 +1,7 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="picoc" type="CMakeRunConfiguration" factoryName="Application" REDIRECT_INPUT="false" PASS_PARENT_ENVS_2="true" PROJECT_NAME="picoc" TARGET_NAME="picoc" CONFIG_NAME="Debug" RUN_TARGET_PROJECT_NAME="picoc" RUN_TARGET_NAME="picoc">
<method v="2">
<option name="com.jetbrains.cidr.execution.CidrBuildBeforeRunTaskProvider$BuildBeforeRunTask" enabled="true" />
</method>
</configuration>
</component>

View file

@ -0,0 +1,7 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="picoc basic.c" type="CMakeRunConfiguration" factoryName="Application" PROGRAM_PARAMS="basic.c" REDIRECT_INPUT="false" WORKING_DIR="file://$ProjectFileDir$/c-tests" PASS_PARENT_ENVS_2="true" PROJECT_NAME="picoc" TARGET_NAME="picoc" CONFIG_NAME="Debug" RUN_TARGET_PROJECT_NAME="picoc" RUN_TARGET_NAME="picoc">
<method v="2">
<option name="com.jetbrains.cidr.execution.CidrBuildBeforeRunTaskProvider$BuildBeforeRunTask" enabled="true" />
</method>
</configuration>
</component>

View file

@ -0,0 +1,7 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="picoc complete.c" type="CMakeRunConfiguration" factoryName="Application" PROGRAM_PARAMS="complete.c" REDIRECT_INPUT="false" WORKING_DIR="file://$ProjectFileDir$/c-tests" PASS_PARENT_ENVS_2="true" PROJECT_NAME="picoc" TARGET_NAME="picoc" CONFIG_NAME="Debug" RUN_TARGET_PROJECT_NAME="picoc" RUN_TARGET_NAME="picoc">
<method v="2">
<option name="com.jetbrains.cidr.execution.CidrBuildBeforeRunTaskProvider$BuildBeforeRunTask" enabled="true" />
</method>
</configuration>
</component>

View file

@ -0,0 +1,7 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="picoc expressions.c" type="CMakeRunConfiguration" factoryName="Application" PROGRAM_PARAMS="expressions.c" REDIRECT_INPUT="false" WORKING_DIR="file://$ProjectFileDir$/c-tests" PASS_PARENT_ENVS_2="true" PROJECT_NAME="picoc" TARGET_NAME="picoc" CONFIG_NAME="Debug" RUN_TARGET_PROJECT_NAME="picoc" RUN_TARGET_NAME="picoc">
<method v="2">
<option name="com.jetbrains.cidr.execution.CidrBuildBeforeRunTaskProvider$BuildBeforeRunTask" enabled="true" />
</method>
</configuration>
</component>

View file

@ -0,0 +1,7 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="picoc factorial.c" type="CMakeRunConfiguration" factoryName="Application" PROGRAM_PARAMS="factorial.c - 5" REDIRECT_INPUT="false" WORKING_DIR="file://$ProjectFileDir$/c-tests" PASS_PARENT_ENVS_2="true" PROJECT_NAME="picoc" TARGET_NAME="picoc" CONFIG_NAME="Debug" RUN_TARGET_PROJECT_NAME="picoc" RUN_TARGET_NAME="picoc">
<method v="2">
<option name="com.jetbrains.cidr.execution.CidrBuildBeforeRunTaskProvider$BuildBeforeRunTask" enabled="true" />
</method>
</configuration>
</component>

View file

@ -0,0 +1,7 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="picoc loop.c" type="CMakeRunConfiguration" factoryName="Application" PROGRAM_PARAMS="loop.c" REDIRECT_INPUT="false" WORKING_DIR="file://$ProjectFileDir$/c-tests" PASS_PARENT_ENVS_2="true" PROJECT_NAME="picoc" TARGET_NAME="picoc" CONFIG_NAME="Debug" RUN_TARGET_PROJECT_NAME="picoc" RUN_TARGET_NAME="picoc">
<method v="2">
<option name="com.jetbrains.cidr.execution.CidrBuildBeforeRunTaskProvider$BuildBeforeRunTask" enabled="true" />
</method>
</configuration>
</component>

View file

@ -0,0 +1,7 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="picoc md5.c" type="CMakeRunConfiguration" factoryName="Application" PROGRAM_PARAMS="md5.c - &quot;test&quot;" REDIRECT_INPUT="false" WORKING_DIR="file://$ProjectFileDir$/c-tests" PASS_PARENT_ENVS_2="true" PROJECT_NAME="picoc" TARGET_NAME="picoc" CONFIG_NAME="Debug" RUN_TARGET_PROJECT_NAME="picoc" RUN_TARGET_NAME="picoc">
<method v="2">
<option name="com.jetbrains.cidr.execution.CidrBuildBeforeRunTaskProvider$BuildBeforeRunTask" enabled="true" />
</method>
</configuration>
</component>

6
.idea/vcs.xml Normal file
View file

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="$PROJECT_DIR$" vcs="Git" />
</component>
</project>

47
CMakeLists.txt Normal file
View file

@ -0,0 +1,47 @@
cmake_minimum_required(VERSION 3.15)
project(picoc C)
execute_process(COMMAND git show-ref --abbrev=8 --head --hash head OUTPUT_VARIABLE hash OUTPUT_STRIP_TRAILING_WHITESPACE)
execute_process(COMMAND git describe --abbrev=0 --tags OUTPUT_VARIABLE tag OUTPUT_STRIP_TRAILING_WHITESPACE)
message("${tag} ${hash}")
set(CMAKE_C_STANDARD 11)
set(CMAKE_C_COMPILER gcc)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -pedantic")
set(CMAKE_REQUIRED_LIBRARIES m readline)
add_definitions(-DUNIX_HOST -DVER="${hash}" -DTAG="${tag}")
#add_definitions(-DDEBUG_EXPRESSIONS)
include_directories(.)
add_executable(picoc
cstdlib/ctype.c
cstdlib/errno.c
cstdlib/math.c
cstdlib/stdbool.c
cstdlib/stdio.c
cstdlib/stdlib.c
cstdlib/string.c
cstdlib/time.c
cstdlib/unistd.c
platform/library_unix.c
platform/platform_unix.c
clibrary.c
debug.c
expression.c
heap.c
include.c
interpreter.h
lex.c
parse.c
picoc.c
picoc.h
platform.c
platform.h
stats.c
stats.h
table.c
type.c
variable.c)
target_link_libraries(picoc -lm -lreadline)

View file

@ -12,7 +12,7 @@ LIBS=-lm -lreadline
TARGET = picoc TARGET = picoc
SRCS = picoc.c table.c lex.c parse.c expression.c heap.c type.c \ SRCS = picoc.c table.c lex.c parse.c expression.c heap.c type.c \
variable.c clibrary.c platform.c include.c debug.c \ variable.c clibrary.c platform.c include.c debug.c stats.c \
platform/platform_unix.c platform/library_unix.c \ platform/platform_unix.c platform/library_unix.c \
cstdlib/stdio.c cstdlib/math.c cstdlib/string.c cstdlib/stdlib.c \ cstdlib/stdio.c cstdlib/math.c cstdlib/string.c cstdlib/stdlib.c \
cstdlib/time.c cstdlib/errno.c cstdlib/ctype.c cstdlib/stdbool.c \ cstdlib/time.c cstdlib/errno.c cstdlib/ctype.c cstdlib/stdbool.c \
@ -34,7 +34,7 @@ clean:
count: count:
@echo "Core:" @echo "Core:"
@cat picoc.h interpreter.h picoc.c table.c lex.c parse.c expression.c platform.c heap.c type.c variable.c include.c debug.c | grep -v '^[ ]*/\*' | grep -v '^[ ]*$$' | wc @cat picoc.h interpreter.h picoc.c table.c lex.c parse.c expression.c platform.c heap.c type.c variable.c include.c debug.c stats.c | grep -v '^[ ]*/\*' | grep -v '^[ ]*$$' | wc
@echo "" @echo ""
@echo "Everything:" @echo "Everything:"
@cat $(SRCS) *.h */*.h | wc @cat $(SRCS) *.h */*.h | wc
@ -53,6 +53,7 @@ clibrary.o: clibrary.c picoc.h interpreter.h platform.h
platform.o: platform.c picoc.h interpreter.h platform.h platform.o: platform.c picoc.h interpreter.h platform.h
include.o: include.c picoc.h interpreter.h platform.h include.o: include.c picoc.h interpreter.h platform.h
debug.o: debug.c interpreter.h platform.h debug.o: debug.c interpreter.h platform.h
stats.o: stats.c stats.h interpreter.h platform.h
platform/platform_unix.o: platform/platform_unix.c picoc.h interpreter.h platform.h platform/platform_unix.o: platform/platform_unix.c picoc.h interpreter.h platform.h
platform/library_unix.o: platform/library_unix.c interpreter.h platform.h platform/library_unix.o: platform/library_unix.c interpreter.h platform.h
cstdlib/stdio.o: cstdlib/stdio.c interpreter.h platform.h cstdlib/stdio.o: cstdlib/stdio.c interpreter.h platform.h

View file

@ -327,7 +327,7 @@ void PlatformLibraryInit()
/* define an example structure */ /* define an example structure */
Tokens = LexAnalyse(IntrinsicName, StructDefinition, strlen(StructDefinition), NULL); Tokens = LexAnalyse(IntrinsicName, StructDefinition, strlen(StructDefinition), NULL);
LexInitParser(&Parser, StructDefinition, Tokens, IntrinsicName, true, false); LexInitParser(&Parser, StructDefinition, Tokens, IntrinsicName, true, false);
TypeParse(&Parser, &ParsedType, &Identifier, &IsStatic); TypeParse(&Parser, &ParsedType, &Identifier, &IsStatic, &IsExtern, &IsVolatile);
HeapFree(Tokens); HeapFree(Tokens);
} }
``` ```

2
c-tests/.gitignore vendored Normal file
View file

@ -0,0 +1,2 @@
*
!*.*

7
c-tests/basic.c Normal file
View file

@ -0,0 +1,7 @@
int a, b;
int main(void) {
a = 1 + 2;
b = a + 3;
return 0;
}

73
c-tests/complete.c Normal file
View file

@ -0,0 +1,73 @@
typedef int int_type;
struct a_struct {
int a;
int b;
};
union a_union {
int a;
int b;
};
#pragma a_pragma
int a;
unsigned long b = 0;
int *c;
char arr[5] = "test";
int dbl(int a, ...) {
return a * 2;
}
int main(void) {
a = 1 + 2;
b = dbl(a);
if (a < 1) {
return 1;
}
while (0) {
a++;
continue;
}
do {
a--;
} while (0);
for (int i = 0; i < 10; i++) {
a += 2;
}
lab: a = 1;
goto lab;
struct a_struct s;
struct a_struct *sp = &s;
s.a = 1;
sp->b = 2;
switch (a) {
case 1:
b = 1;
break;
case 2:
b = 2;
break;
default:
b = 0;
}
a = b ? 1 : 2;
a += (int)10;
for(;;);
int c = a, b;
return 0, 1;
}

18
c-tests/expressions.c Normal file
View file

@ -0,0 +1,18 @@
int b, c;
int d[2];
int main(int argc, char **argv)
{
int a = 1 + 2;
b = a + 3 + 4 + 5;
c = (a * b++ + 6 - 7) / 8;
a += 1;
b++;
a = b + c;
d[0] = 1;
// *(d + 1) = 2;
// return a = 1, b = 2;
return a = 1;
a = b++;
}

9
c-tests/extern.c Normal file
View file

@ -0,0 +1,9 @@
#include "extern.h"
int a;
int main(void) {
a = 1;
decrement();
return a + b;
}

4
c-tests/extern.h Normal file
View file

@ -0,0 +1,4 @@
extern int a;
extern long b;
//void decrement();

8
c-tests/extern2.c Normal file
View file

@ -0,0 +1,8 @@
#include "extern.h"
long b = 1;
void decrement() {
a--;
b--;
}

17
c-tests/factorial.c Normal file
View file

@ -0,0 +1,17 @@
#include <stdlib.h>
#include <stdio.h>
int main(int argc, char **argv)
{
int in = atoi(argv[1]);
int fact = 1;
for (int i = 1; i <= in; i++) {
fact *= i;
}
printf("%d factorial is %d", in, fact);
return 0;
}

202
c-tests/hash.c Normal file
View file

@ -0,0 +1,202 @@
/*
** C implementation of a hash table ADT
*/
//typedef enum tagReturnCode {SUCCESS, FAIL} ReturnCode;
#define SUCCESS 0
#define FAIL 1
typedef struct tagEntry
{
char* key;
char* value;
} Entry;
typedef struct tagNode
{
Entry* entry;
struct tagNode* next;
} Node;
typedef struct tagHash
{
unsigned int table_size;
Node** heads;
} Hash;
static unsigned int hash_func(char* str, unsigned int table_size)
{
unsigned int hash_value;
unsigned int a = 127;
for (hash_value = 0; *str != 0; ++str)
hash_value = (a*hash_value + *str) % table_size;
return hash_value;
}
int HashCreate(Hash** hash, unsigned int table_size)
{
unsigned int i;
if (table_size < 1)
return FAIL;
/*
* Allocate space for the Hash
*/
if (((*hash) = malloc(sizeof(**hash))) == NULL)
return FAIL;
/*
* Allocate space for the array of list heads
*/
if (((*hash)->heads = malloc(table_size*sizeof(*((*hash)->heads)))) == NULL)
return FAIL;
/*
* Initialize Hash info
*/
for (i = 0; i < table_size; ++i)
{
(*hash)->heads[i] = NULL;
}
(*hash)->table_size = table_size;
return SUCCESS;
}
int HashInsert(Hash* hash, Entry* entry)
{
unsigned int index = hash_func(entry->key, hash->table_size);
Node* temp = hash->heads[index];
HashRemove(hash, entry->key);
if ((hash->heads[index] = malloc(sizeof(Node))) == NULL)
return FAIL;
hash->heads[index]->entry = malloc(sizeof(Entry));
hash->heads[index]->entry->key = malloc(strlen(entry->key)+1);
hash->heads[index]->entry->value = malloc(strlen(entry->value)+1);
strcpy(hash->heads[index]->entry->key, entry->key);
strcpy(hash->heads[index]->entry->value, entry->value);
hash->heads[index]->next = temp;
return SUCCESS;
}
Entry* HashFind(Hash* hash, char* key)
{
unsigned int index = hash_func(key, hash->table_size);
Node* temp = hash->heads[index];
while (temp != NULL)
{
if (!strcmp(key, temp->entry->key))
return temp->entry;
temp = temp->next;
}
return NULL;
}
int HashRemove(Hash* hash, char* key)
{
unsigned int index = hash_func(key, hash->table_size);
Node* temp1 = hash->heads[index];
Node* temp2 = temp1;
while (temp1 != NULL)
{
if (!strcmp(key, temp1->entry->key))
{
if (temp1 == hash->heads[index])
hash->heads[index] = hash->heads[index]->next;
else
temp2->next = temp1->next;
free(temp1->entry->key);
free(temp1->entry->value);
free(temp1->entry);
free(temp1);
temp1 = NULL;
return SUCCESS;
}
temp2 = temp1;
temp1 = temp1->next;
}
return FAIL;
}
void HashPrint(Hash* hash, void (*PrintFunc)(char*, char*))
{
unsigned int i;
if (hash == NULL || hash->heads == NULL)
return;
for (i = 0; i < hash->table_size; ++i)
{
Node* temp = hash->heads[i];
while (temp != NULL)
{
PrintFunc(temp->entry->key, temp->entry->value);
temp = temp->next;
}
}
}
void HashDestroy(Hash* hash)
{
unsigned int i;
if (hash == NULL)
return;
for (i = 0; i < hash->table_size; ++i)
{
Node* temp = hash->heads[i];
while (temp != NULL)
{
Node* temp2 = temp;
free(temp->entry->key);
free(temp->entry->value);
free(temp->entry);
temp = temp->next;
free(temp2);
}
}
free(hash->heads);
hash->heads = NULL;
free(hash);
}

12
c-tests/loop-comma.c Normal file
View file

@ -0,0 +1,12 @@
int main(void)
{
int i = 123;
int j = 456;
int k = 0;
for (i = 0, j = 0; i < 2; i++, j++) {
k += 2;
}
return k - (j * 2);
}

10
c-tests/loop.c Normal file
View file

@ -0,0 +1,10 @@
int main(void)
{
int j = 999;
for (int i = 0; i < 4; i++) {
j = i - 3;
}
return j;
}

175
c-tests/md5.c Normal file
View file

@ -0,0 +1,175 @@
/*
* Simple MD5 implementation
*
* Compile with: gcc -o md5 md5.c
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
// #include <stdint.h>
// Mostly ok, but not as a function return type for some reason
typedef unsigned char uint8_t;
typedef unsigned int uint32_t;
typedef unsigned int size_t;
// Constants are the integer part of the sines of integers (in radians) * 2^32.
uint32_t k[64] = {
0xd76aa478, 0xe8c7b756, 0x242070db, 0xc1bdceee ,
0xf57c0faf, 0x4787c62a, 0xa8304613, 0xfd469501 ,
0x698098d8, 0x8b44f7af, 0xffff5bb1, 0x895cd7be ,
0x6b901122, 0xfd987193, 0xa679438e, 0x49b40821 ,
0xf61e2562, 0xc040b340, 0x265e5a51, 0xe9b6c7aa ,
0xd62f105d, 0x02441453, 0xd8a1e681, 0xe7d3fbc8 ,
0x21e1cde6, 0xc33707d6, 0xf4d50d87, 0x455a14ed ,
0xa9e3e905, 0xfcefa3f8, 0x676f02d9, 0x8d2a4c8a ,
0xfffa3942, 0x8771f681, 0x6d9d6122, 0xfde5380c ,
0xa4beea44, 0x4bdecfa9, 0xf6bb4b60, 0xbebfbc70 ,
0x289b7ec6, 0xeaa127fa, 0xd4ef3085, 0x04881d05 ,
0xd9d4d039, 0xe6db99e5, 0x1fa27cf8, 0xc4ac5665 ,
0xf4292244, 0x432aff97, 0xab9423a7, 0xfc93a039 ,
0x655b59c3, 0x8f0ccc92, 0xffeff47d, 0x85845dd1 ,
0x6fa87e4f, 0xfe2ce6e0, 0xa3014314, 0x4e0811a1 ,
0xf7537e82, 0xbd3af235, 0x2ad7d2bb, 0xeb86d391 };
// r specifies the per-round shift amounts
uint32_t r[] = {7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22,
5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20,
4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23,
6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21};
unsigned int left_rotate(uint32_t x, uint32_t c) {
return (x << c) | (x >> (32 - c));
}
void to_bytes(uint32_t val, uint8_t *bytes)
{
bytes[0] = (uint8_t) val;
bytes[1] = (uint8_t) (val >> 8);
bytes[2] = (uint8_t) (val >> 16);
bytes[3] = (uint8_t) (val >> 24);
}
unsigned int to_int32(uint8_t *bytes)
{
return (uint32_t) bytes[0]
| ((uint32_t) bytes[1] << 8)
| ((uint32_t) bytes[2] << 16)
| ((uint32_t) bytes[3] << 24);
}
void md5(uint8_t *initial_msg, size_t initial_len, uint8_t *digest) {
// These vars will contain the hash
uint32_t h0, h1, h2, h3;
// Message (to prepare)
uint8_t *msg = NULL;
size_t new_len, offset;
uint32_t w[16];
uint32_t a, b, c, d, i, f, g, temp;
// Initialize variables - simple count in nibbles:
h0 = 0x67452301;
h1 = 0xefcdab89;
h2 = 0x98badcfe;
h3 = 0x10325476;
//Pre-processing:
//append "1" bit to message
//append "0" bits until message length in bits ≡ 448 (mod 512)
//append length mod (2^64) to message
for (new_len = initial_len + 1; new_len % (512/8) != 448/8; new_len++);
msg = malloc(new_len + 8);
memcpy(msg, initial_msg, initial_len);
msg[initial_len] = 0x80; // append the "1" bit; most significant bit is "first"
for (offset = initial_len + 1; offset < new_len; offset++)
msg[offset] = 0; // append "0" bits
// append the len in bits at the end of the buffer.
to_bytes(initial_len*8, msg + new_len);
// initial_len>>29 == initial_len*8>>32, but avoids overflow.
to_bytes(initial_len>>29, msg + new_len + 4);
// Process the message in successive 512-bit chunks:
//for each 512-bit chunk of message:
for(offset=0; offset<new_len; offset += (512/8)) {
// break chunk into sixteen 32-bit words w[j], 0 ≤ j ≤ 15
for (i = 0; i < 16; i++)
w[i] = to_int32(msg + offset + i*4);
// Initialize hash value for this chunk:
a = h0;
b = h1;
c = h2;
d = h3;
// Main loop:
for(i = 0; i<64; i++) {
if (i < 16) {
f = (b & c) | ((~b) & d);
g = i;
} else if (i < 32) {
f = (d & b) | ((~d) & c);
g = (5*i + 1) % 16;
} else if (i < 48) {
f = b ^ c ^ d;
g = (3*i + 5) % 16;
} else {
f = c ^ (b | (~d));
g = (7*i) % 16;
}
temp = d;
d = c;
c = b;
b = b + left_rotate((a + f + k[i] + w[g]), r[i]);
a = temp;
}
// Add this chunk's hash to result so far:
h0 += a;
h1 += b;
h2 += c;
h3 += d;
}
// cleanup
free(msg);
//var char digest[16] := h0 append h1 append h2 append h3 //(Output is in little-endian)
to_bytes(h0, digest);
to_bytes(h1, digest + 4);
to_bytes(h2, digest + 8);
to_bytes(h3, digest + 12);
}
int main(int argc, char **argv) {
char *msg = argv[1];
size_t len;
int i;
uint8_t result[16];
if (argc < 2) {
printf("usage: %s 'string'\n", argv[0]);
return 1;
}
len = strlen(msg);
md5((uint8_t*)msg, len, result);
// display result
for (i = 0; i < 16; i++)
printf("%2.2x", result[i]);
puts("");
return 0;
}

19
c-tests/pragma.c Normal file
View file

@ -0,0 +1,19 @@
int a;
#pragma test1
int b;
_Pragma( "test2" )
int main(void) {
a = 0;
#pragma test3
b = 1;
_Pragma("test4")
return a;
}

5
c-tests/test.c Normal file
View file

@ -0,0 +1,5 @@
int a = 1;
int b = 2;
int c = a + b;
printf("%d\n", c);

27
c-tests/types.c Normal file
View file

@ -0,0 +1,27 @@
int a;
unsigned b;
unsigned int c;
long d;
long int e;
unsigned long f;
unsigned long int g;
short h;
short int i;
unsigned short j;
unsigned short int k;
volatile int l;
int volatile static m;
const int x;
long const y;
typedef int MyInt;
MyInt z = 1;
int main(void) {
return 0;
}

View file

@ -46,7 +46,7 @@ void LibraryAdd(Picoc *pc, struct LibraryFunction *FuncList)
strlen((char*)FuncList[Count].Prototype), NULL); strlen((char*)FuncList[Count].Prototype), NULL);
LexInitParser(&Parser, pc, FuncList[Count].Prototype, Tokens, LexInitParser(&Parser, pc, FuncList[Count].Prototype, Tokens,
IntrinsicName, true, false); IntrinsicName, true, false);
TypeParse(&Parser, &ReturnType, &Identifier, NULL); TypeParse(&Parser, &ReturnType, &Identifier, NULL, NULL, NULL);
NewValue = ParseFunctionDefinition(&Parser, ReturnType, Identifier); NewValue = ParseFunctionDefinition(&Parser, ReturnType, Identifier);
NewValue->Val->FuncDef.Intrinsic = FuncList[Count].Func; NewValue->Val->FuncDef.Intrinsic = FuncList[Count].Func;
HeapFreeMem(pc, Tokens); HeapFreeMem(pc, Tokens);

View file

@ -100,7 +100,7 @@ void UnistdFchdir(struct ParseState *Parser, struct Value *ReturnValue,
void UnistdFdatasync(struct ParseState *Parser, struct Value *ReturnValue, void UnistdFdatasync(struct ParseState *Parser, struct Value *ReturnValue,
struct Value **Param, int NumArgs) struct Value **Param, int NumArgs)
{ {
#ifdef F_FULLSYNC #ifdef F_FULLFSYNC
/* Mac OS X equivalent */ /* Mac OS X equivalent */
ReturnValue->Val->Integer = fcntl(Param[0]->Val->Integer, F_FULLFSYNC); ReturnValue->Val->Integer = fcntl(Param[0]->Val->Integer, F_FULLFSYNC);
#else #else
@ -331,11 +331,13 @@ void UnistdRmdir(struct ParseState *Parser, struct Value *ReturnValue,
ReturnValue->Val->Integer = rmdir(Param[0]->Val->Pointer); ReturnValue->Val->Integer = rmdir(Param[0]->Val->Pointer);
} }
#if 0
void UnistdSbrk(struct ParseState *Parser, struct Value *ReturnValue, void UnistdSbrk(struct ParseState *Parser, struct Value *ReturnValue,
struct Value **Param, int NumArgs) struct Value **Param, int NumArgs)
{ {
ReturnValue->Val->Pointer = sbrk(Param[0]->Val->Integer); ReturnValue->Val->Pointer = sbrk(Param[0]->Val->Integer);
} }
#endif
void UnistdSetgid(struct ParseState *Parser, struct Value *ReturnValue, void UnistdSetgid(struct ParseState *Parser, struct Value *ReturnValue,
struct Value **Param, int NumArgs) struct Value **Param, int NumArgs)
@ -558,7 +560,7 @@ struct LibraryFunction UnistdFunctions[] =
{UnistdRead, "ssize_t read(int, void*, size_t);"}, {UnistdRead, "ssize_t read(int, void*, size_t);"},
{UnistdReadlink, "int readlink(char*, char*, size_t);"}, {UnistdReadlink, "int readlink(char*, char*, size_t);"},
{UnistdRmdir, "int rmdir(char*);"}, {UnistdRmdir, "int rmdir(char*);"},
{UnistdSbrk, "void *sbrk(intptr_t);"}, /* {UnistdSbrk, "void *sbrk(intptr_t);"}, */
{UnistdSetgid, "int setgid(gid_t);"}, {UnistdSetgid, "int setgid(gid_t);"},
{UnistdSetpgid, "int setpgid(pid_t, pid_t);"}, {UnistdSetpgid, "int setpgid(pid_t, pid_t);"},
{UnistdSetpgrp, "pid_t setpgrp(void);"}, {UnistdSetpgrp, "pid_t setpgrp(void);"},

View file

@ -1,6 +1,7 @@
/* picoc expression evaluator - a stack-based expression evaluation system /* picoc expression evaluator - a stack-based expression evaluation system
* which handles operator precedence */ * which handles operator precedence */
#include "interpreter.h" #include "interpreter.h"
#include "stats.h"
/* whether evaluation is left to right for a given precedence level */ /* whether evaluation is left to right for a given precedence level */
@ -1443,6 +1444,9 @@ int ExpressionParse(struct ParseState *Parser, struct Value **Result)
ParserCopy(&PreState, Parser); ParserCopy(&PreState, Parser);
Token = LexGetToken(Parser, &LexValue, true); Token = LexGetToken(Parser, &LexValue, true);
stats_log_expression(Token, Parser);
if ((((int)Token > TokenComma && (int)Token <= (int)TokenOpenBracket) || if ((((int)Token > TokenComma && (int)Token <= (int)TokenOpenBracket) ||
(Token == TokenCloseBracket && BracketPrecedence != 0)) && (Token == TokenCloseBracket && BracketPrecedence != 0)) &&
(Token != TokenColon || TernaryDepth > 0)) { (Token != TokenColon || TernaryDepth > 0)) {
@ -1465,7 +1469,7 @@ int ExpressionParse(struct ParseState *Parser, struct Value **Result)
char *CastIdentifier; char *CastIdentifier;
struct Value *CastTypeValue; struct Value *CastTypeValue;
TypeParse(Parser, &CastType, &CastIdentifier, NULL); TypeParse(Parser, &CastType, &CastIdentifier, NULL, NULL, NULL);
if (LexGetToken(Parser, &LexValue, true) != TokenCloseBracket) if (LexGetToken(Parser, &LexValue, true) != TokenCloseBracket)
ProgramFail(Parser, "brackets not closed"); ProgramFail(Parser, "brackets not closed");
@ -1664,7 +1668,7 @@ int ExpressionParse(struct ParseState *Parser, struct Value **Result)
PrefixState = false; PrefixState = false;
ParserCopy(Parser, &PreState); ParserCopy(Parser, &PreState);
TypeParse(Parser, &Typ, &Identifier, NULL); TypeParse(Parser, &Typ, &Identifier, NULL, NULL, NULL);
TypeValue = VariableAllocValueFromType(Parser->pc, Parser, TypeValue = VariableAllocValueFromType(Parser->pc, Parser,
&Parser->pc->TypeType, false, NULL, false); &Parser->pc->TypeType, false, NULL, false);
TypeValue->Val->Typ = Typ; TypeValue->Val->Typ = Typ;
@ -1888,7 +1892,7 @@ void ExpressionParseFunctionCall(struct ParseState *Parser,
Parser->ScopeID = OldScopeID; Parser->ScopeID = OldScopeID;
if (ParseStatement(&FuncParser, true) != ParseResultOk) if (ParseStatement(&FuncParser, true, false) != ParseResultOk)
ProgramFail(&FuncParser, "function body expected"); ProgramFail(&FuncParser, "function body expected");
if (RunIt) { if (RunIt) {

View file

@ -174,7 +174,11 @@ enum LexToken {
/* 0x5c */ TokenEOF, /* 0x5c */ TokenEOF,
TokenEndOfLine, TokenEndOfLine,
TokenEndOfFunction, TokenEndOfFunction,
TokenBackSlash TokenBackSlash,
TokenVolatileType,
TokenHashPragma,
TokenUnderscorePragma,
TokenConstType
}; };
/* used in dynamic memory allocation */ /* used in dynamic memory allocation */
@ -508,6 +512,9 @@ struct Picoc_Struct {
struct Table StringTable; struct Table StringTable;
struct TableEntry *StringHashTable[STRING_TABLE_SIZE]; struct TableEntry *StringHashTable[STRING_TABLE_SIZE];
char *StrEmpty; char *StrEmpty;
/* stats */
int CollectStats;
}; };
/* table.c */ /* table.c */
@ -547,7 +554,7 @@ extern void LexInteractiveStatementPrompt(Picoc *pc);
* void PicocParseInteractive(); */ * void PicocParseInteractive(); */
extern void PicocParseInteractiveNoStartPrompt(Picoc *pc, int EnableDebugger); extern void PicocParseInteractiveNoStartPrompt(Picoc *pc, int EnableDebugger);
extern enum ParseResult ParseStatement(struct ParseState *Parser, extern enum ParseResult ParseStatement(struct ParseState *Parser,
int CheckTrailingSemicolon); int CheckTrailingSemicolon, int DoNotConsumeTrailingSemicolon);
extern struct Value *ParseFunctionDefinition(struct ParseState *Parser, extern struct Value *ParseFunctionDefinition(struct ParseState *Parser,
struct ValueType *ReturnType, char *Identifier); struct ValueType *ReturnType, char *Identifier);
extern void ParseCleanup(Picoc *pc); extern void ParseCleanup(Picoc *pc);
@ -571,11 +578,11 @@ extern int TypeSizeValue(struct Value *Val, int Compact);
extern int TypeStackSizeValue(struct Value *Val); extern int TypeStackSizeValue(struct Value *Val);
extern int TypeLastAccessibleOffset(Picoc *pc, struct Value *Val); extern int TypeLastAccessibleOffset(Picoc *pc, struct Value *Val);
extern int TypeParseFront(struct ParseState *Parser, struct ValueType **Typ, extern int TypeParseFront(struct ParseState *Parser, struct ValueType **Typ,
int *IsStatic); int *IsStatic, int *IsExtern, int *IsVolatile);
extern void TypeParseIdentPart(struct ParseState *Parser, extern void TypeParseIdentPart(struct ParseState *Parser,
struct ValueType *BasicTyp, struct ValueType **Typ, char **Identifier); struct ValueType *BasicTyp, struct ValueType **Typ, char **Identifier);
extern void TypeParse(struct ParseState *Parser, struct ValueType **Typ, extern void TypeParse(struct ParseState *Parser, struct ValueType **Typ,
char **Identifier, int *IsStatic); char **Identifier, int *IsStatic, int *IsExtern, int *IsVolatile);
extern struct ValueType *TypeGetMatching(Picoc *pc, struct ParseState *Parser, extern struct ValueType *TypeGetMatching(Picoc *pc, struct ParseState *Parser,
struct ValueType *ParentType, enum BaseType Base, int ArraySize, const char *Identifier, int AllowDuplicates); struct ValueType *ParentType, enum BaseType Base, int ArraySize, const char *Identifier, int AllowDuplicates);
extern struct ValueType *TypeCreateOpaqueStruct(Picoc *pc, struct ParseState *Parser, extern struct ValueType *TypeCreateOpaqueStruct(Picoc *pc, struct ParseState *Parser,

8
lex.c
View file

@ -93,7 +93,11 @@ static struct ReservedWord ReservedWords[] = {
{"union", TokenUnionType}, {"union", TokenUnionType},
{"unsigned", TokenUnsignedType}, {"unsigned", TokenUnsignedType},
{"void", TokenVoidType}, {"void", TokenVoidType},
{"while", TokenWhile} {"while", TokenWhile},
{"volatile", TokenVolatileType},
{"#pragma", TokenHashPragma},
{"_Pragma", TokenUnderscorePragma},
{"const", TokenConstType}
}; };
@ -848,7 +852,7 @@ enum LexToken LexGetRawToken(struct ParseState *Parser, struct Value **Value,
#ifdef DEBUG_LEXER #ifdef DEBUG_LEXER
printf("Got token=%02x inc=%d pos=%d\n", Token, IncPos, Parser->CharacterPos); printf("Got token=%02x inc=%d pos=%d\n", Token, IncPos, Parser->CharacterPos);
#endif #endif
assert(Token >= TokenNone && Token <= TokenEndOfFunction); assert(Token >= TokenNone && Token <= TokenConstType);
return Token; return Token;
} }

72
parse.c
View file

@ -1,6 +1,7 @@
/* picoc parser - parses source and executes statements */ /* picoc parser - parses source and executes statements */
#include "picoc.h" #include "picoc.h"
#include "interpreter.h" #include "interpreter.h"
#include "stats.h"
static enum ParseResult ParseStatementMaybeRun(struct ParseState *Parser, static enum ParseResult ParseStatementMaybeRun(struct ParseState *Parser,
int Condition, int CheckTrailingSemicolon); int Condition, int CheckTrailingSemicolon);
@ -11,6 +12,7 @@ static void ParseDeclarationAssignment(struct ParseState *Parser,
struct Value *NewVariable, int DoAssignment); struct Value *NewVariable, int DoAssignment);
static int ParseDeclaration(struct ParseState *Parser, enum LexToken Token); static int ParseDeclaration(struct ParseState *Parser, enum LexToken Token);
static void ParseMacroDefinition(struct ParseState *Parser); static void ParseMacroDefinition(struct ParseState *Parser);
static void ParsePragma(struct ParseState *Parser);
static void ParseFor(struct ParseState *Parser); static void ParseFor(struct ParseState *Parser);
static enum RunMode ParseBlock(struct ParseState *Parser, int AbsorbOpenBrace, static enum RunMode ParseBlock(struct ParseState *Parser, int AbsorbOpenBrace,
int Condition); int Condition);
@ -47,11 +49,11 @@ enum ParseResult ParseStatementMaybeRun(struct ParseState *Parser,
enum RunMode OldMode = Parser->Mode; enum RunMode OldMode = Parser->Mode;
int Result; int Result;
Parser->Mode = RunModeSkip; Parser->Mode = RunModeSkip;
Result = ParseStatement(Parser, CheckTrailingSemicolon); Result = ParseStatement(Parser, CheckTrailingSemicolon, false);
Parser->Mode = OldMode; Parser->Mode = OldMode;
return (enum ParseResult)Result; return (enum ParseResult)Result;
} else } else
return ParseStatement(Parser, CheckTrailingSemicolon); return ParseStatement(Parser, CheckTrailingSemicolon, false);
} }
/* count the number of parameters to a function or macro */ /* count the number of parameters to a function or macro */
@ -120,7 +122,7 @@ struct Value *ParseFunctionDefinition(struct ParseState *Parser,
break; break;
} else { } else {
/* add a parameter */ /* add a parameter */
TypeParse(&ParamParser, &ParamType, &ParamIdentifier, NULL); TypeParse(&ParamParser, &ParamType, &ParamIdentifier, NULL, NULL, NULL);
if (ParamType->Base == TypeVoid) { if (ParamType->Base == TypeVoid) {
/* this isn't a real parameter at all - delete it */ /* this isn't a real parameter at all - delete it */
//ParamCount--; //ParamCount--;
@ -337,6 +339,8 @@ void ParseDeclarationAssignment(struct ParseState *Parser,
int ParseDeclaration(struct ParseState *Parser, enum LexToken Token) int ParseDeclaration(struct ParseState *Parser, enum LexToken Token)
{ {
int IsStatic = false; int IsStatic = false;
int IsExtern = false;
int IsVolatile = false;
int FirstVisit = false; int FirstVisit = false;
char *Identifier; char *Identifier;
struct ValueType *BasicType; struct ValueType *BasicType;
@ -344,7 +348,7 @@ int ParseDeclaration(struct ParseState *Parser, enum LexToken Token)
struct Value *NewVariable = NULL; struct Value *NewVariable = NULL;
Picoc *pc = Parser->pc; Picoc *pc = Parser->pc;
TypeParseFront(Parser, &BasicType, &IsStatic); TypeParseFront(Parser, &BasicType, &IsStatic, &IsExtern, &IsVolatile);
do { do {
TypeParseIdentPart(Parser, BasicType, &Typ, &Identifier); TypeParseIdentPart(Parser, BasicType, &Typ, &Identifier);
if ((Token != TokenVoidType && Token != TokenStructType && if ((Token != TokenVoidType && Token != TokenStructType &&
@ -358,7 +362,8 @@ int ParseDeclaration(struct ParseState *Parser, enum LexToken Token)
{ {
ParseFunctionDefinition(Parser, Typ, Identifier); ParseFunctionDefinition(Parser, Typ, Identifier);
return false; return false;
} else { } else if (!IsExtern) {
/* extern means declaration rather than definition, so ignore */
if (Typ == &pc->VoidType && Identifier != pc->StrEmpty) if (Typ == &pc->VoidType && Identifier != pc->StrEmpty)
ProgramFail(Parser, "can't define a void variable"); ProgramFail(Parser, "can't define a void variable");
@ -449,6 +454,14 @@ void ParseMacroDefinition(struct ParseState *Parser)
ProgramFail(Parser, "'%s' is already defined", MacroNameStr); ProgramFail(Parser, "'%s' is already defined", MacroNameStr);
} }
/* parse a pragma */
void ParsePragma(struct ParseState *Parser)
{
/* consume tokens until we hit the end of a line */
/* (not ideal for _Pragma() but it'll do for now) */
LexToEndOfMacro(Parser);
}
/* copy the entire parser state */ /* copy the entire parser state */
void ParserCopy(struct ParseState *To, struct ParseState *From) void ParserCopy(struct ParseState *To, struct ParseState *From)
{ {
@ -482,8 +495,18 @@ void ParseFor(struct ParseState *Parser)
if (LexGetToken(Parser, NULL, true) != TokenOpenBracket) if (LexGetToken(Parser, NULL, true) != TokenOpenBracket)
ProgramFail(Parser, "'(' expected"); ProgramFail(Parser, "'(' expected");
if (ParseStatement(Parser, true) != ParseResultOk) if (LexGetToken(Parser, NULL, false) != TokenSemicolon) {
if (ParseStatement(Parser, false, true) != ParseResultOk)
ProgramFail(Parser, "statement expected"); ProgramFail(Parser, "statement expected");
while (LexGetToken(Parser, NULL, false) == TokenComma) {
LexGetToken(Parser, NULL, true);
if (ParseStatement(Parser, false, true) != ParseResultOk)
ProgramFail(Parser, "statement expected");
}
}
if (LexGetToken(Parser, NULL, true) != TokenSemicolon)
ProgramFail(Parser, "';' expected");
ParserCopyPos(&PreConditional, Parser); ParserCopyPos(&PreConditional, Parser);
if (LexGetToken(Parser, NULL, false) == TokenSemicolon) if (LexGetToken(Parser, NULL, false) == TokenSemicolon)
@ -496,6 +519,10 @@ void ParseFor(struct ParseState *Parser)
ParserCopyPos(&PreIncrement, Parser); ParserCopyPos(&PreIncrement, Parser);
ParseStatementMaybeRun(Parser, false, false); ParseStatementMaybeRun(Parser, false, false);
while (LexGetToken(Parser, NULL, false) == TokenComma) {
LexGetToken(Parser, NULL, true);
ParseStatementMaybeRun(Parser, false, false);
}
if (LexGetToken(Parser, NULL, true) != TokenCloseBracket) if (LexGetToken(Parser, NULL, true) != TokenCloseBracket)
ProgramFail(Parser, "')' expected"); ProgramFail(Parser, "')' expected");
@ -511,7 +538,11 @@ void ParseFor(struct ParseState *Parser)
while (Condition && Parser->Mode == RunModeRun) { while (Condition && Parser->Mode == RunModeRun) {
ParserCopyPos(Parser, &PreIncrement); ParserCopyPos(Parser, &PreIncrement);
ParseStatement(Parser, false); ParseStatement(Parser, false, false);
while (LexGetToken(Parser, NULL, false) == TokenComma) {
LexGetToken(Parser, NULL, true);
ParseStatement(Parser, false, false);
}
ParserCopyPos(Parser, &PreConditional); ParserCopyPos(Parser, &PreConditional);
if (LexGetToken(Parser, NULL, false) == TokenSemicolon) if (LexGetToken(Parser, NULL, false) == TokenSemicolon)
@ -521,7 +552,7 @@ void ParseFor(struct ParseState *Parser)
if (Condition) { if (Condition) {
ParserCopyPos(Parser, &PreStatement); ParserCopyPos(Parser, &PreStatement);
ParseStatement(Parser, true); ParseStatement(Parser, true, false);
if (Parser->Mode == RunModeContinue) if (Parser->Mode == RunModeContinue)
Parser->Mode = RunModeRun; Parser->Mode = RunModeRun;
@ -550,12 +581,12 @@ enum RunMode ParseBlock(struct ParseState *Parser, int AbsorbOpenBrace,
/* condition failed - skip this block instead */ /* condition failed - skip this block instead */
enum RunMode OldMode = Parser->Mode; enum RunMode OldMode = Parser->Mode;
Parser->Mode = RunModeSkip; Parser->Mode = RunModeSkip;
while (ParseStatement(Parser, true) == ParseResultOk) { while (ParseStatement(Parser, true, false) == ParseResultOk) {
} }
Parser->Mode = OldMode; Parser->Mode = OldMode;
} else { } else {
/* just run it in its current mode */ /* just run it in its current mode */
while (ParseStatement(Parser, true) == ParseResultOk) { while (ParseStatement(Parser, true, false) == ParseResultOk) {
} }
} }
@ -575,7 +606,7 @@ void ParseTypedef(struct ParseState *Parser)
struct ValueType **TypPtr; struct ValueType **TypPtr;
struct Value InitValue; struct Value InitValue;
TypeParse(Parser, &Typ, &TypeName, NULL); TypeParse(Parser, &Typ, &TypeName, NULL, NULL, NULL);
if (Parser->Mode == RunModeRun) { if (Parser->Mode == RunModeRun) {
TypPtr = &Typ; TypPtr = &Typ;
@ -587,7 +618,7 @@ void ParseTypedef(struct ParseState *Parser)
/* parse a statement */ /* parse a statement */
enum ParseResult ParseStatement(struct ParseState *Parser, enum ParseResult ParseStatement(struct ParseState *Parser,
int CheckTrailingSemicolon) int CheckTrailingSemicolon, int DoNotConsumeTrailingSemicolon)
{ {
int Condition; int Condition;
enum LexToken Token; enum LexToken Token;
@ -607,6 +638,8 @@ enum ParseResult ParseStatement(struct ParseState *Parser,
ParserCopy(&PreState, Parser); ParserCopy(&PreState, Parser);
Token = LexGetToken(Parser, &LexerValue, true); Token = LexGetToken(Parser, &LexerValue, true);
stats_log_statement(Token, Parser);
switch (Token) { switch (Token) {
case TokenEOF: case TokenEOF:
return ParseResultEOF; return ParseResultEOF;
@ -695,7 +728,7 @@ enum ParseResult ParseStatement(struct ParseState *Parser,
ParserCopyPos(&PreStatement, Parser); ParserCopyPos(&PreStatement, Parser);
do { do {
ParserCopyPos(Parser, &PreStatement); ParserCopyPos(Parser, &PreStatement);
if (ParseStatement(Parser, true) != ParseResultOk) if (ParseStatement(Parser, true, false) != ParseResultOk)
ProgramFail(Parser, "statement expected"); ProgramFail(Parser, "statement expected");
if (Parser->Mode == RunModeContinue) if (Parser->Mode == RunModeContinue)
Parser->Mode = PreMode; Parser->Mode = PreMode;
@ -734,6 +767,8 @@ enum ParseResult ParseStatement(struct ParseState *Parser,
case TokenAutoType: case TokenAutoType:
case TokenRegisterType: case TokenRegisterType:
case TokenExternType: case TokenExternType:
case TokenVolatileType:
case TokenConstType:
*Parser = PreState; *Parser = PreState;
CheckTrailingSemicolon = ParseDeclaration(Parser, Token); CheckTrailingSemicolon = ParseDeclaration(Parser, Token);
break; break;
@ -848,13 +883,18 @@ enum ParseResult ParseStatement(struct ParseState *Parser,
} }
break; break;
} }
case TokenHashPragma:
case TokenUnderscorePragma:
ParsePragma(Parser);
CheckTrailingSemicolon = false;
break;
default: default:
*Parser = PreState; *Parser = PreState;
return ParseResultError; return ParseResultError;
} }
if (CheckTrailingSemicolon) { if (CheckTrailingSemicolon) {
if (LexGetToken(Parser, NULL, true) != TokenSemicolon) if (LexGetToken(Parser, NULL, !DoNotConsumeTrailingSemicolon) != TokenSemicolon)
ProgramFail(Parser, "';' expected"); ProgramFail(Parser, "';' expected");
} }
@ -894,7 +934,7 @@ void PicocParse(Picoc *pc, const char *FileName, const char *Source,
EnableDebugger); EnableDebugger);
do { do {
Ok = ParseStatement(&Parser, true); Ok = ParseStatement(&Parser, true, false);
} while (Ok == ParseResultOk); } while (Ok == ParseResultOk);
if (Ok == ParseResultError) if (Ok == ParseResultError)
@ -917,7 +957,7 @@ void PicocParseInteractiveNoStartPrompt(Picoc *pc, int EnableDebugger)
do { do {
LexInteractiveStatementPrompt(pc); LexInteractiveStatementPrompt(pc);
Ok = ParseStatement(&Parser, true); Ok = ParseStatement(&Parser, true, false);
LexInteractiveCompleted(pc, &Parser); LexInteractiveCompleted(pc, &Parser);
} while (Ok == ParseResultOk); } while (Ok == ParseResultOk);

18
picoc.c
View file

@ -10,18 +10,21 @@
/* include only picoc.h here - should be able to use it with only the /* include only picoc.h here - should be able to use it with only the
external interfaces, no internals from interpreter.h */ external interfaces, no internals from interpreter.h */
#include "picoc.h" #include "picoc.h"
#include "stats.h"
#if defined(UNIX_HOST) || defined(WIN32) #if defined(UNIX_HOST) || defined(WIN32)
#include "LICENSE.h" #include "LICENSE.h"
/* Override via STACKSIZE environment variable */ /* Override via STACKSIZE environment variable */
#define PICOC_STACK_SIZE (128000*4) #define PICOC_STACK_SIZE (32*1024*1024)
int main(int argc, char **argv) int main(int argc, char **argv)
{ {
int ParamCount = 1; int ParamCount = 1;
int DontRunMain = false; int DontRunMain = false;
int CollectStats = false;
int StatsType = 0;
int StackSize = getenv("STACKSIZE") ? atoi(getenv("STACKSIZE")) : PICOC_STACK_SIZE; int StackSize = getenv("STACKSIZE") ? atoi(getenv("STACKSIZE")) : PICOC_STACK_SIZE;
Picoc pc; Picoc pc;
@ -30,6 +33,7 @@ int main(int argc, char **argv)
"Format:\n\n" "Format:\n\n"
"> picoc <file1.c>... [- <arg1>...] : run a program, calls main() as the entry point\n" "> picoc <file1.c>... [- <arg1>...] : run a program, calls main() as the entry point\n"
"> picoc -s <file1.c>... [- <arg1>...] : run a script, runs the program without calling main()\n" "> picoc -s <file1.c>... [- <arg1>...] : run a script, runs the program without calling main()\n"
"> picoc -d[type] <file1.c>... [- <arg1>...] : run a program, outputting debugging stats\n"
"> picoc -i : interactive mode, Ctrl+d to exit\n" "> picoc -i : interactive mode, Ctrl+d to exit\n"
"> picoc -c : copyright info\n" "> picoc -c : copyright info\n"
"> picoc -h : this help message\n"); "> picoc -h : this help message\n");
@ -47,6 +51,13 @@ int main(int argc, char **argv)
DontRunMain = true; DontRunMain = true;
PicocIncludeAllSystemHeaders(&pc); PicocIncludeAllSystemHeaders(&pc);
ParamCount++; ParamCount++;
} else if (strncmp(argv[ParamCount], "-d", 2) == 0) {
if (strlen(argv[ParamCount]) > 2) {
StatsType = atoi(&argv[ParamCount][2]);
}
CollectStats = true;
pc.CollectStats = true;
ParamCount++;
} }
if (argc > ParamCount && strcmp(argv[ParamCount], "-i") == 0) { if (argc > ParamCount && strcmp(argv[ParamCount], "-i") == 0) {
@ -66,6 +77,11 @@ int main(int argc, char **argv)
} }
PicocCleanup(&pc); PicocCleanup(&pc);
if (CollectStats) {
stats_print_tokens(StatsType == 1);
}
return pc.PicocExitValue; return pc.PicocExitValue;
} }
#endif #endif

View file

@ -57,7 +57,7 @@
#define STRING_TABLE_SIZE (97) /* shared string table size */ #define STRING_TABLE_SIZE (97) /* shared string table size */
#define STRING_LITERAL_TABLE_SIZE (97) /* string literal table size */ #define STRING_LITERAL_TABLE_SIZE (97) /* string literal table size */
#define RESERVED_WORD_TABLE_SIZE (97) /* reserved word table size */ #define RESERVED_WORD_TABLE_SIZE (97) /* reserved word table size */
#define PARAMETER_MAX (16) /* maximum number of parameters to a function */ #define PARAMETER_MAX (32) /* maximum number of parameters to a function */
#define LINEBUFFER_MAX (256) /* maximum number of characters on a line */ #define LINEBUFFER_MAX (256) /* maximum number of characters on a line */
#define LOCAL_TABLE_SIZE (11) /* size of local variable table (can expand) */ #define LOCAL_TABLE_SIZE (11) /* size of local variable table (can expand) */
#define STRUCT_TABLE_SIZE (11) /* size of struct/union member table (can expand) */ #define STRUCT_TABLE_SIZE (11) /* size of struct/union member table (can expand) */

153
stats.c Normal file
View file

@ -0,0 +1,153 @@
//
// Created by Russell Joyce on 12/05/2020.
//
#include "stats.h"
const char *RunModeNames[NO_RUN_MODES] = {
"RunModeRun",
"RunModeSkip",
"RunModeReturn",
"RunModeCaseSearch",
"RunModeBreak",
"RunModeContinue",
"RunModeGoto"
};
struct LexTokenStat LexTokenStats[NO_TOKENS] = {
{"TokenNone", {0, 0, 0, 0, 0, 0, 0}},
{"TokenComma", {0, 0, 0, 0, 0, 0, 0}},
{"TokenAssign", {0, 0, 0, 0, 0, 0, 0}},
{"TokenAddAssign", {0, 0, 0, 0, 0, 0, 0}},
{"TokenSubtractAssign", {0, 0, 0, 0, 0, 0, 0}},
{"TokenMultiplyAssign", {0, 0, 0, 0, 0, 0, 0}},
{"TokenDivideAssign", {0, 0, 0, 0, 0, 0, 0}},
{"TokenModulusAssign", {0, 0, 0, 0, 0, 0, 0}},
{"TokenShiftLeftAssign", {0, 0, 0, 0, 0, 0, 0}},
{"TokenShiftRightAssign", {0, 0, 0, 0, 0, 0, 0}},
{"TokenArithmeticAndAssign", {0, 0, 0, 0, 0, 0, 0}},
{"TokenArithmeticOrAssign", {0, 0, 0, 0, 0, 0, 0}},
{"TokenArithmeticExorAssign", {0, 0, 0, 0, 0, 0, 0}},
{"TokenQuestionMark", {0, 0, 0, 0, 0, 0, 0}},
{"TokenColon", {0, 0, 0, 0, 0, 0, 0}},
{"TokenLogicalOr", {0, 0, 0, 0, 0, 0, 0}},
{"TokenLogicalAnd", {0, 0, 0, 0, 0, 0, 0}},
{"TokenArithmeticOr", {0, 0, 0, 0, 0, 0, 0}},
{"TokenArithmeticExor", {0, 0, 0, 0, 0, 0, 0}},
{"TokenAmpersand", {0, 0, 0, 0, 0, 0, 0}},
{"TokenEqual", {0, 0, 0, 0, 0, 0, 0}},
{"TokenNotEqual", {0, 0, 0, 0, 0, 0, 0}},
{"TokenLessThan", {0, 0, 0, 0, 0, 0, 0}},
{"TokenGreaterThan", {0, 0, 0, 0, 0, 0, 0}},
{"TokenLessEqual", {0, 0, 0, 0, 0, 0, 0}},
{"TokenGreaterEqual", {0, 0, 0, 0, 0, 0, 0}},
{"TokenShiftLeft", {0, 0, 0, 0, 0, 0, 0}},
{"TokenShiftRight", {0, 0, 0, 0, 0, 0, 0}},
{"TokenPlus", {0, 0, 0, 0, 0, 0, 0}},
{"TokenMinus", {0, 0, 0, 0, 0, 0, 0}},
{"TokenAsterisk", {0, 0, 0, 0, 0, 0, 0}},
{"TokenSlash", {0, 0, 0, 0, 0, 0, 0}},
{"TokenModulus", {0, 0, 0, 0, 0, 0, 0}},
{"TokenIncrement", {0, 0, 0, 0, 0, 0, 0}},
{"TokenDecrement", {0, 0, 0, 0, 0, 0, 0}},
{"TokenUnaryNot", {0, 0, 0, 0, 0, 0, 0}},
{"TokenUnaryExor", {0, 0, 0, 0, 0, 0, 0}},
{"TokenSizeof", {0, 0, 0, 0, 0, 0, 0}},
{"TokenCast", {0, 0, 0, 0, 0, 0, 0}},
{"TokenLeftSquareBracket", {0, 0, 0, 0, 0, 0, 0}},
{"TokenRightSquareBracket", {0, 0, 0, 0, 0, 0, 0}},
{"TokenDot", {0, 0, 0, 0, 0, 0, 0}},
{"TokenArrow", {0, 0, 0, 0, 0, 0, 0}},
{"TokenOpenBracket", {0, 0, 0, 0, 0, 0, 0}},
{"TokenCloseBracket", {0, 0, 0, 0, 0, 0, 0}},
{"TokenIdentifier", {0, 0, 0, 0, 0, 0, 0}},
{"TokenIntegerConstant", {0, 0, 0, 0, 0, 0, 0}},
{"TokenFPConstant", {0, 0, 0, 0, 0, 0, 0}},
{"TokenStringConstant", {0, 0, 0, 0, 0, 0, 0}},
{"TokenCharacterConstant", {0, 0, 0, 0, 0, 0, 0}},
{"TokenSemicolon", {0, 0, 0, 0, 0, 0, 0}},
{"TokenEllipsis", {0, 0, 0, 0, 0, 0, 0}},
{"TokenLeftBrace", {0, 0, 0, 0, 0, 0, 0}},
{"TokenRightBrace", {0, 0, 0, 0, 0, 0, 0}},
{"TokenIntType", {0, 0, 0, 0, 0, 0, 0}},
{"TokenCharType", {0, 0, 0, 0, 0, 0, 0}},
{"TokenFloatType", {0, 0, 0, 0, 0, 0, 0}},
{"TokenDoubleType", {0, 0, 0, 0, 0, 0, 0}},
{"TokenVoidType", {0, 0, 0, 0, 0, 0, 0}},
{"TokenEnumType", {0, 0, 0, 0, 0, 0, 0}},
{"TokenLongType", {0, 0, 0, 0, 0, 0, 0}},
{"TokenSignedType", {0, 0, 0, 0, 0, 0, 0}},
{"TokenShortType", {0, 0, 0, 0, 0, 0, 0}},
{"TokenStaticType", {0, 0, 0, 0, 0, 0, 0}},
{"TokenAutoType", {0, 0, 0, 0, 0, 0, 0}},
{"TokenRegisterType", {0, 0, 0, 0, 0, 0, 0}},
{"TokenExternType", {0, 0, 0, 0, 0, 0, 0}},
{"TokenStructType", {0, 0, 0, 0, 0, 0, 0}},
{"TokenUnionType", {0, 0, 0, 0, 0, 0, 0}},
{"TokenUnsignedType", {0, 0, 0, 0, 0, 0, 0}},
{"TokenTypedef", {0, 0, 0, 0, 0, 0, 0}},
{"TokenContinue", {0, 0, 0, 0, 0, 0, 0}},
{"TokenDo", {0, 0, 0, 0, 0, 0, 0}},
{"TokenElse", {0, 0, 0, 0, 0, 0, 0}},
{"TokenFor", {0, 0, 0, 0, 0, 0, 0}},
{"TokenGoto", {0, 0, 0, 0, 0, 0, 0}},
{"TokenIf", {0, 0, 0, 0, 0, 0, 0}},
{"TokenWhile", {0, 0, 0, 0, 0, 0, 0}},
{"TokenBreak", {0, 0, 0, 0, 0, 0, 0}},
{"TokenSwitch", {0, 0, 0, 0, 0, 0, 0}},
{"TokenCase", {0, 0, 0, 0, 0, 0, 0}},
{"TokenDefault", {0, 0, 0, 0, 0, 0, 0}},
{"TokenReturn", {0, 0, 0, 0, 0, 0, 0}},
{"TokenHashDefine", {0, 0, 0, 0, 0, 0, 0}},
{"TokenHashInclude", {0, 0, 0, 0, 0, 0, 0}},
{"TokenHashIf", {0, 0, 0, 0, 0, 0, 0}},
{"TokenHashIfdef", {0, 0, 0, 0, 0, 0, 0}},
{"TokenHashIfndef", {0, 0, 0, 0, 0, 0, 0}},
{"TokenHashElse", {0, 0, 0, 0, 0, 0, 0}},
{"TokenHashEndif", {0, 0, 0, 0, 0, 0, 0}},
{"TokenNew", {0, 0, 0, 0, 0, 0, 0}},
{"TokenDelete", {0, 0, 0, 0, 0, 0, 0}},
{"TokenOpenMacroBracket", {0, 0, 0, 0, 0, 0, 0}},
{"TokenEOF", {0, 0, 0, 0, 0, 0, 0}},
{"TokenEndOfLine", {0, 0, 0, 0, 0, 0, 0}},
{"TokenEndOfFunction", {0, 0, 0, 0, 0, 0, 0}},
{"TokenBackSlash", {0, 0, 0, 0, 0, 0, 0}},
{"TokenVolatileType", {0, 0, 0, 0, 0, 0, 0}},
{"TokenHashPragma", {0, 0, 0, 0, 0, 0, 0}},
{"TokenUnderscorePragma", {0, 0, 0, 0, 0, 0, 0}},
{"TokenConstType", {0, 0, 0, 0, 0, 0, 0}}
};
void stats_log_statement(enum LexToken token, struct ParseState *parser) {
if (parser->pc->CollectStats) {
fprintf(stderr, "Parsing Statement %s (%d) in %s (%d) at %s:%d:%d\n", LexTokenStats[token].name, token,
RunModeNames[parser->Mode], parser->Mode, parser->FileName, parser->Line, parser->CharacterPos);
LexTokenStats[token].count[parser->Mode]++;
}
}
void stats_log_expression(enum LexToken token, struct ParseState *parser) {
if (parser->pc->CollectStats) {
fprintf(stderr, "Parsing Expression %s (%d) in %s (%d) at %s:%d:%d\n", LexTokenStats[token].name, token,
RunModeNames[parser->Mode], parser->Mode, parser->FileName, parser->Line, parser->CharacterPos);
LexTokenStats[token].count[parser->Mode]++;
}
}
void stats_print_tokens(int all) {
fprintf(stderr, "\n*********\nToken stats:\n");
for (int i = 0; i < NO_RUN_MODES; i++) {
fprintf(stderr, "***\n");
fprintf(stderr, "%s\n", RunModeNames[i]);
for (int j = 0; j < NO_TOKENS; j++) {
if (all || LexTokenStats[j].count[i] > 0) {
fprintf(stderr, "%5d %s\n", LexTokenStats[j].count[i],
LexTokenStats[j].name);
}
}
}
fprintf(stderr, "*********\n");
}

26
stats.h Normal file
View file

@ -0,0 +1,26 @@
//
// Created by Russell Joyce on 12/05/2020.
//
#ifndef PICOC_STATS_H
#define PICOC_STATS_H
#include "interpreter.h"
#define NO_RUN_MODES 7
#define NO_TOKENS 101
extern const char *RunModeNames[NO_RUN_MODES];
struct LexTokenStat {
const char* name;
int count[NO_RUN_MODES];
};
extern struct LexTokenStat LexTokenStats[NO_TOKENS];
void stats_log_statement(enum LexToken token, struct ParseState *parser);
void stats_log_expression(enum LexToken token, struct ParseState *parser);
void stats_print_tokens(int all);
#endif //PICOC_STATS_H

52
type.c
View file

@ -265,7 +265,7 @@ void TypeParseStruct(struct ParseState *Parser, struct ValueType **Typ,
STRUCT_TABLE_SIZE, true); STRUCT_TABLE_SIZE, true);
do { do {
TypeParse(Parser, &MemberType, &MemberIdentifier, NULL); TypeParse(Parser, &MemberType, &MemberIdentifier, NULL, NULL, NULL);
if (MemberType == NULL || MemberIdentifier == NULL) if (MemberType == NULL || MemberIdentifier == NULL)
ProgramFail(Parser, "invalid type in struct"); ProgramFail(Parser, "invalid type in struct");
@ -393,10 +393,12 @@ void TypeParseEnum(struct ParseState *Parser, struct ValueType **Typ)
/* parse a type - just the basic type */ /* parse a type - just the basic type */
int TypeParseFront(struct ParseState *Parser, struct ValueType **Typ, int TypeParseFront(struct ParseState *Parser, struct ValueType **Typ,
int *IsStatic) int *IsStatic, int *IsExtern, int *IsVolatile)
{ {
int Unsigned = false; int Unsigned = false;
int StaticQualifier = false; int StaticQualifier = false;
int ExternQualifier = false;
int VolatileQualifier = false;
enum LexToken Token; enum LexToken Token;
struct ParseState Before; struct ParseState Before;
struct Value *LexerValue; struct Value *LexerValue;
@ -404,23 +406,49 @@ int TypeParseFront(struct ParseState *Parser, struct ValueType **Typ,
Picoc *pc = Parser->pc; Picoc *pc = Parser->pc;
*Typ = NULL; *Typ = NULL;
/* ignore leading type qualifiers */
ParserCopy(&Before, Parser); ParserCopy(&Before, Parser);
Token = LexGetToken(Parser, &LexerValue, true); Token = LexGetToken(Parser, &LexerValue, true);
/* handle any leading type qualifiers/storage classes */
while (Token == TokenStaticType || Token == TokenAutoType || while (Token == TokenStaticType || Token == TokenAutoType ||
Token == TokenRegisterType || Token == TokenExternType) { Token == TokenRegisterType || Token == TokenExternType ||
Token == TokenVolatileType || Token == TokenConstType) {
if (Token == TokenStaticType) if (Token == TokenStaticType)
StaticQualifier = true; StaticQualifier = true;
else if (Token == TokenExternType)
ExternQualifier = true;
else if (Token == TokenVolatileType)
VolatileQualifier = true;
Token = LexGetToken(Parser, &LexerValue, true); Token = LexGetToken(Parser, &LexerValue, true);
} }
/* handle any trailing type qualifiers/storage classes */
enum LexToken FollowToken = LexGetToken(Parser, NULL, false);
while (FollowToken == TokenStaticType || FollowToken == TokenAutoType ||
FollowToken == TokenRegisterType || FollowToken == TokenExternType ||
FollowToken == TokenVolatileType || FollowToken == TokenConstType) {
if (FollowToken == TokenStaticType)
StaticQualifier = true;
else if (FollowToken == TokenExternType)
ExternQualifier = true;
else if (FollowToken == TokenVolatileType)
VolatileQualifier = true;
LexGetToken(Parser, NULL, true);
FollowToken = LexGetToken(Parser, NULL, false);
}
if (IsStatic != NULL) if (IsStatic != NULL)
*IsStatic = StaticQualifier; *IsStatic = StaticQualifier;
if (IsExtern != NULL)
*IsExtern = ExternQualifier;
if (IsVolatile != NULL)
*IsVolatile = VolatileQualifier;
/* handle signed/unsigned with no trailing type */ /* handle signed/unsigned with no trailing type */
if (Token == TokenSignedType || Token == TokenUnsignedType) { if (Token == TokenSignedType || Token == TokenUnsignedType) {
enum LexToken FollowToken = LexGetToken(Parser, &LexerValue, false); enum LexToken FollowToken = LexGetToken(Parser, NULL, false);
Unsigned = (Token == TokenUnsignedType); Unsigned = (Token == TokenUnsignedType);
if (FollowToken != TokenIntType && FollowToken != TokenLongType && if (FollowToken != TokenIntType && FollowToken != TokenLongType &&
@ -436,6 +464,14 @@ int TypeParseFront(struct ParseState *Parser, struct ValueType **Typ,
Token = LexGetToken(Parser, &LexerValue, true); Token = LexGetToken(Parser, &LexerValue, true);
} }
/* handle long or short with trailing int by consuming and ignoring the int */
if (Token == TokenLongType || Token == TokenShortType) {
enum LexToken FollowToken = LexGetToken(Parser, NULL, false);
if (FollowToken == TokenIntType) {
LexGetToken(Parser, NULL, true);
}
}
switch (Token) { switch (Token) {
case TokenIntType: case TokenIntType:
*Typ = Unsigned ? &pc->UnsignedIntType : &pc->IntType; *Typ = Unsigned ? &pc->UnsignedIntType : &pc->IntType;
@ -541,7 +577,7 @@ void TypeParseIdentPart(struct ParseState *Parser, struct ValueType *BasicTyp,
if (*Typ != NULL) if (*Typ != NULL)
ProgramFail(Parser, "bad type declaration"); ProgramFail(Parser, "bad type declaration");
TypeParse(Parser, Typ, Identifier, NULL); TypeParse(Parser, Typ, Identifier, NULL, NULL, NULL);
if (LexGetToken(Parser, NULL, true) != TokenCloseBracket) if (LexGetToken(Parser, NULL, true) != TokenCloseBracket)
ProgramFail(Parser, "')' expected"); ProgramFail(Parser, "')' expected");
break; break;
@ -577,11 +613,11 @@ void TypeParseIdentPart(struct ParseState *Parser, struct ValueType *BasicTyp,
/* parse a type - a complete declaration including identifier */ /* parse a type - a complete declaration including identifier */
void TypeParse(struct ParseState *Parser, struct ValueType **Typ, void TypeParse(struct ParseState *Parser, struct ValueType **Typ,
char **Identifier, int *IsStatic) char **Identifier, int *IsStatic, int *IsExtern, int *IsVolatile)
{ {
struct ValueType *BasicType; struct ValueType *BasicType;
TypeParseFront(Parser, &BasicType, IsStatic); TypeParseFront(Parser, &BasicType, IsStatic, IsExtern, IsVolatile);
TypeParseIdentPart(Parser, BasicType, Typ, Identifier); TypeParseIdentPart(Parser, BasicType, Typ, Identifier);
} }

View file

@ -4,7 +4,7 @@
#include "interpreter.h" #include "interpreter.h"
/* maximum size of a value to temporarily copy while we create a variable */ /* maximum size of a value to temporarily copy while we create a variable */
#define MAX_TMP_COPY_BUF (256) #define MAX_TMP_COPY_BUF (2048)
/* initialize the variable system */ /* initialize the variable system */