From 01bd481bce0d9e3865c2e093d86fd8eeab4bc7a3 Mon Sep 17 00:00:00 2001 From: josh Date: Sat, 28 Mar 2009 15:17:48 +0000 Subject: [PATCH] initial import git-svn-id: svn://anubis/jtlc/trunk@2 f5bc74b8-7b62-4e90-9214-7121d538519f --- Makefile | 30 ++++++++++ lib/lang/String.jtl | 24 ++++++++ lib/std/io.jtl | 6 ++ main/Makefile | 23 ++++++++ main/jtlc.cc | 8 +++ parser/Makefile | 37 ++++++++++++ parser/parser.lex | 85 +++++++++++++++++++++++++++ parser/parser.yy | 130 +++++++++++++++++++++++++++++++++++++++++ tests/HelloWorld.jtl | 12 ++++ tests/Interpolator.jtl | 37 ++++++++++++ tests/Regex.jtl | 40 +++++++++++++ 11 files changed, 432 insertions(+) create mode 100644 Makefile create mode 100644 lib/lang/String.jtl create mode 100644 lib/std/io.jtl create mode 100644 main/Makefile create mode 100644 main/jtlc.cc create mode 100644 parser/Makefile create mode 100644 parser/parser.lex create mode 100644 parser/parser.yy create mode 100644 tests/HelloWorld.jtl create mode 100644 tests/Interpolator.jtl create mode 100644 tests/Regex.jtl diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..840d0e6 --- /dev/null +++ b/Makefile @@ -0,0 +1,30 @@ + +SHELL := bash +TARGET := jtlc +ifdef WIN32 +export CPPFLAGS += -I"$(shell cd)" +else +export CPPFLAGS += -I"$(shell pwd)" +endif +export CXXFLAGS := -Wall -O2 + +LDFLAGS := -lfl + +SUBDIRS := main parser + +all: $(TARGET) + +.PHONY: $(TARGET) +$(TARGET): + @for d in $(SUBDIRS); \ + do $(MAKE) -C $$d; \ + ret=$$?; \ + if [[ $$ret != 0 ]]; then \ + exit $$ret; \ + fi; \ + done + $(CXX) -o $@ $(patsubst %,%/*.o,$(SUBDIRS)) $(CXXFLAGS) $(LDFLAGS) + +clean: + for d in $(SUBDIRS); do $(MAKE) -C $$d clean CLEAN=1; done + -rm -f $(TARGET) diff --git a/lib/lang/String.jtl b/lib/lang/String.jtl new file mode 100644 index 0000000..03450f6 --- /dev/null +++ b/lib/lang/String.jtl @@ -0,0 +1,24 @@ + +module String; + +private m_chars : char[]; + +String(chars : char[]) +{ + m_chars := chars; +} + +length() : int +{ + return m_chars.length; +} + +operator+(str1 : String, str2 : String) : String +{ + chars : char[] := new char[str1.length() + str2.length()]; +} + +operator=~(str1 : String, str2 : String) : bool +{ + return true; +} diff --git a/lib/std/io.jtl b/lib/std/io.jtl new file mode 100644 index 0000000..5d8cc1a --- /dev/null +++ b/lib/std/io.jtl @@ -0,0 +1,6 @@ + +module std.io; + +print(...) : void +{ +} diff --git a/main/Makefile b/main/Makefile new file mode 100644 index 0000000..a210eec --- /dev/null +++ b/main/Makefile @@ -0,0 +1,23 @@ + +OBJS := $(patsubst %.cc,%.o,$(wildcard *.cc)) +DEPS := $(OBJS:.o=.dep) + +all: $(DEPS) $(OBJS) + +%.o: %.cc + $(CXX) -c -o $@ $(CPPFLAGS) $(CXXFLAGS) $< + +# Make dependency files +%.dep: %.cc + @set -e; rm -f $@; \ + $(CXX) -MM $(CPPFLAGS) $< > $@.$$$$; \ + sed 's,\($*\)\.o[ :]*,\1.o $@ : ,g' < $@.$$$$ > $@; \ + rm -f $@.$$$$ + +clean: + -$(RM) -f *.o *.dep + +# Include dependency files +ifndef CLEAN +-include $(DEPS) +endif diff --git a/main/jtlc.cc b/main/jtlc.cc new file mode 100644 index 0000000..5f5a0a2 --- /dev/null +++ b/main/jtlc.cc @@ -0,0 +1,8 @@ + +#include + +int main(int argc, char * argv[]) +{ + printf("jtlc, version 0.00000001\n"); + return 0; +} diff --git a/parser/Makefile b/parser/Makefile new file mode 100644 index 0000000..d44b564 --- /dev/null +++ b/parser/Makefile @@ -0,0 +1,37 @@ + +FLEX := flex +BISON := bison + +PARSER := parser + +OBJS := lex.yy.o $(PARSER).tab.o $(patsubst %.cc,%.o,$(wildcard *.cc)) +DEPS := $(OBJS:.o=.dep) + +all: $(DEPS) $(OBJS) + +%.o: %.cc + $(CXX) -c -o $@ $(CPPFLAGS) $(CXXFLAGS) $< + +$(PARSER).tab.cc $(PARSER).tab.hh: $(PARSER).yy + $(BISON) -d $< + +lex.yy.o: lex.yy.cc + +lex.yy.cc: $(PARSER).tab.hh +lex.yy.cc: $(PARSER).lex + $(FLEX) -o $@ $< + +# Make dependency files +%.dep: %.cc + @set -e; rm -f $@; \ + $(CXX) -MM $(CPPFLAGS) $< > $@.$$$$; \ + sed 's,\($*\)\.o[ :]*,\1.o $@ : ,g' < $@.$$$$ > $@; \ + rm -f $@.$$$$ + +clean: + -rm -f lex.yy.cc $(PARSER).tab.cc $(PARSER).tab.hh *~ *.o *.dep + +# Include dependency files +ifndef CLEAN +-include $(DEPS) +endif diff --git a/parser/parser.lex b/parser/parser.lex new file mode 100644 index 0000000..685e8a0 --- /dev/null +++ b/parser/parser.lex @@ -0,0 +1,85 @@ + +%option nounput +%option bison-locations + +%{ + +#include "parser.tab.hh" + +%} + +%% + + /* operators */ +:= return ASSIGN; +== return DEQUALS; +\/ return DIVIDE; += return EQUALS; +\> return GREATER; +\< return LESS; +=~ return MATCH; +- return MINUS; +% return MOD; +\+ return PLUS; +\* return STAR; + + /* punctuation */ +: return COLON; +, return COMMA; +:: return DCOLON; +\$ return DOLLAR; +\. return DOT; +\<- return FROM; +\? return QUESTION; +; return SEMICOLON; + +\{ return LCURLY; +\} return RCURLY; +\[ return LBRACKET; +\] return RBRACKET; +\( return LPAREN; +\) return RPAREN; + + /* literals */ +-?[0-9]+ { + return INT_LITERAL; +} +-?0x[0-9]+ { + return INT_LITERAL; +} +-?0b[01]+ { + return INT_LITERAL; +} +-?[0-9]*\.[0-9]+([eE][0-9]+)? { + return REAL_LITERAL; +} + + /* primitive types */ +byte return BYTE; +ubyte return UBYTE; +char return CHAR; +wchar return WCHAR; +int return INT; +uint return UINT; +long return LONG; +ulong return ULONG; + + /* keywords */ +import return IMPORT; +module return MODULE; +return return RETURN; +struct return STRUCT; + + /* identifiers */ +[a-zA-Z_][a-zA-Z_0-9]* { + return IDENTIFIER; +} + + /* whitespace */ +\n yylloc->first_line++; yylloc->last_line++; +[ \t\v] /* ignore whitespace */ + + /* anything else */ +. return yytext[0]; + +%% diff --git a/parser/parser.yy b/parser/parser.yy new file mode 100644 index 0000000..49b3874 --- /dev/null +++ b/parser/parser.yy @@ -0,0 +1,130 @@ + +%{ + +#include +#include +#include "parser.tab.hh" /* bison-generated header with YY[SL]TYPE */ +using namespace std; + +#define yyerror(msg) errFunc(msg, &yylloc) + +int yylex(YYSTYPE *, YYLTYPE *); + +extern FILE * yyin; + +void errFunc(const char * str, YYLTYPE * yyllocp); + +int yywrap() +{ + return 1; +} + +%} + +%pure-parser +%locations +%error-verbose + + /* operators */ +%token ASSIGN; +%token DEQUALS; +%token DIVIDE; +%token EQUALS; +%token GREATER; +%token LESS; +%token MATCH; +%token MINUS; +%token MOD; +%token PLUS; +%token STAR; + + /* punctuation */ +%token COLON; +%token COMMA; +%token DCOLON; +%token DOLLAR; +%token DOT; +%token FROM; +%token QUESTION; +%token SEMICOLON; + +%token LCURLY; +%token RCURLY; +%token LBRACKET; +%token RBRACKET; +%token LPAREN; +%token RPAREN; + + /* literals */ +%token INT_LITERAL; +%token REAL_LITERAL; + + /* primitive types */ +%token BYTE; +%token UBYTE; +%token CHAR; +%token WCHAR; +%token INT; +%token UINT; +%token LONG; +%token ULONG; + + /* keywords */ +%token IMPORT; +%token MODULE; +%token RETURN; +%token STRUCT; + + /* identifiers */ +%token IDENTIFIER; + +%% + +program: INT_LITERAL + ; + +primitive_type: BYTE + | UBYTE + | CHAR + | WCHAR + | INT + | UINT + | LONG + | ULONG + ; + +struct_type: STRUCT + ; + +ptr_type: type STAR + ; + +type: primitive_type + | ptr_type + | struct_type + ; + +%% + +void parse(const char * fileName) +{ + yyin = fopen(fileName, "r"); + if (yyin == NULL) + { + cerr << "Failed to open file '" << fileName << "'" << endl; + return; + } + if (yyparse()) + { + cerr << "Aborting." << endl; + exit(1); + } +} + +void errFunc(const char * str, YYLTYPE * yyllocp) +{ + fprintf(stderr, "error: %s: line %d, column %d\n", + str, + yyllocp->first_line, + yyllocp->first_column); +} diff --git a/tests/HelloWorld.jtl b/tests/HelloWorld.jtl new file mode 100644 index 0000000..e679c7f --- /dev/null +++ b/tests/HelloWorld.jtl @@ -0,0 +1,12 @@ + +import std.io.*; + +int main(args : String[]) +{ + foreach (arg <- args) + println("arg: ", arg); + + println("Hello, World!\n"); + + return 0; +} diff --git a/tests/Interpolator.jtl b/tests/Interpolator.jtl new file mode 100644 index 0000000..902ff2b --- /dev/null +++ b/tests/Interpolator.jtl @@ -0,0 +1,37 @@ + +module Interpolator; + +import std.io.*; + +typedef function double (double) interpolator_t; + +int main(args : String[]) +{ + interpolator_t i1 = getInterpolator(1, 5, 4); + interpolator_t i2 = getInterpolator(10, 2, 5); + + assert( i1(0) =~ 1 ); + assert( i1(4) =~ 5 ); + assert( i1(3) =~ 4.0 ); + + assert( i2(0) =~ 10 ); + assert( i2(5) =~ 2 ); + assert( i2(1.0) =~ 8.4 ); + assert( i2(2.0) =~ 6.8 ); + + return 0; +} + +/* + * Create and return a linear interpolator functor which interpolates + * between (0.0, x1) and (sep, x2), returning the output y-value + */ +interpolator_t getInterpolator(x1 : double, x2 : double, sep : double) +{ + assert (sep > 0.0); + + return function double (x : double) + { + return x * (x2 - x1) / sep + x1; + } +} diff --git a/tests/Regex.jtl b/tests/Regex.jtl new file mode 100644 index 0000000..2158a14 --- /dev/null +++ b/tests/Regex.jtl @@ -0,0 +1,40 @@ + +module Regex; + +import std.io.*; + +int main(args : String[]) +{ + foreach (arg <- args) + { + /* operator=~(String, String) returns an array of String results for + * the matches. When there are no explicit parentheses in a pattern, + * the array returned contains just one string - the entire matched + * content. If the pattern does not match, an empty array is returned. + * An empty array evaluations in a boolean context to false, while an + * array with a nonzero number of arguments evaluations to true. + * Hence, the =~ operator can be used in an if() statement to see if + * the string matches a given pattern + */ + if (arg =~ "/^\d+$/") + { + println(arg, " is a number"); + } + else if (arg =~ "/^0x\d+$/i") + { + println(arg, " is a hexadecimal number"); + } + else + { + /* auto declaration of matches to be of type String[] */ + matches ::= arg =~ "/(.)(.)/"; + if (matches) + { + println("first character: ", matches[0], + "second character: ", matches[1]); + } + } + } + + return 0; +}