From 62af092d11745059232e0a3378374b090af05e29 Mon Sep 17 00:00:00 2001 From: "Mike D. Lowis" Date: Sun, 1 Apr 2012 09:00:55 -0400 Subject: [PATCH] Tweaked macro and map syntax to allow declaration of empty map literals --- LANGUAGE.md | 9 ++- example.dl | 52 ++++++++++--- source/dllexer/dllexer.cpp | 5 +- source/dlparser/dlparser.cpp | 125 +++++++++++++----------------- source/dlparser/macro/pattern.cpp | 5 +- source/main.cpp | 3 + source/options/options.c | 101 ++++++++++++++++++++++++ source/options/options.h | 7 ++ 8 files changed, 218 insertions(+), 89 deletions(-) create mode 100644 source/options/options.c create mode 100644 source/options/options.h diff --git a/LANGUAGE.md b/LANGUAGE.md index 58b5b91..584c8ff 100644 --- a/LANGUAGE.md +++ b/LANGUAGE.md @@ -63,14 +63,15 @@ Here are some examples for defining numbers: #### Lists () # An empty list - (1) # This is NOT a list. This evaluates to 1 - (1, 2) # A list with two numbers + (1,) # A list with one element (Note: the trailing comma + # distinguishes this from a grouping expression) + (1, 2) # A list with two elements ('a', 1) # A list with two elements of different types #### Vectors [] # An empty vector - [1] # A vector with on element + [1] # A vector with oni element [1, 2] # A vector with two number elements ['a', 1] # A vector with two elements of different types @@ -119,7 +120,7 @@ Anonymous functions and immediate execution A Work In Progress -### Streams +### Ports A Work In Progress diff --git a/example.dl b/example.dl index 6ae7a66..582542b 100644 --- a/example.dl +++ b/example.dl @@ -1,7 +1,6 @@ #------------------------------------------------------------------------------ # Literal Definition and Usage #------------------------------------------------------------------------------ -foo := Nil # Nums assert( 1 == 1, "Positive integer parses correctly") @@ -19,10 +18,9 @@ assert('\n', "Parse escape sequence for newline") assert('\r', "Parse escape sequence for return") assert('\t', "Parse escape sequence for tab") assert('\v', "Parse escape sequence for vertical tab") -#foo = '\xFF' # Hex Value # String -foo = "some string" +foo := "some string" foo = "foo \a \b \f \n \r \t \v \' \" \\ \xFF bar" foo = "12345"[2] @@ -30,7 +28,9 @@ foo = "12345"[2] foo = $some_symbol # Map -foo = { +foo = @{} +foo.stuff = "bar" +foo = @{ $foo : 1 + 1, "stuff" : 2 + 2, $stuff : 2 + 2, @@ -41,11 +41,6 @@ foo = { foo["stuff"] = 3 foo.stuff = 5 -# Accessing map elements -#print( foo[$bar] ) -#print( foo["stuff"] ) -#print( foo.stuff ) - # Vector foo = [] foo = [1] @@ -83,7 +78,7 @@ foo = ({|a,b| a + b })(1,2) #------------------------------------------------------------------------------ # Define a macro that represents a traditional if statement -@ if [ +% if [ (E B B) : exec_if($1, $2, $3), (E B) : exec_if($1, $2), ] @@ -125,15 +120,48 @@ assert( test_result, "Branch should not be taken when test condition is false" ) #------------------------------------------------------------------------------ # Define a macro that will delay the evaluation of the following expression -@ delay [ +% delay [ (E) : make_promise({ $1 }) ] # Define a macro that will force the evaluation of the following delayed statement -@ force [ +% force [ (E) : $1() ] foo = delay 1 + 1 foo = force foo +#------------------------------------------------------------------------------ +# Prototype Classes +#------------------------------------------------------------------------------ + +# Define a macro for creating new classes +#% new [ +# (I B) : ({ +# this := @{ $proto : $1 } +# $2() +# this +# })(), +# +# (B) : ({ +# this := @{} +# $2() +# this +# })() +#] + +#Duck := new foo { +# sound := "Quack" +# this.mating_call = { sound } +#} +# +#Cow := new foo { +# sound := "Moo" +# this.mating_call = { sound } +#} + +#print( Duck ) +#print( Duck[$mating_call] ) +#print( (Duck[$mating_call])() ) + diff --git a/source/dllexer/dllexer.cpp b/source/dllexer/dllexer.cpp index 235959a..52587be 100644 --- a/source/dllexer/dllexer.cpp +++ b/source/dllexer/dllexer.cpp @@ -4,7 +4,7 @@ using namespace std; -#define NUM_SINGLE_CHAR_MATCHES 11 +#define NUM_SINGLE_CHAR_MATCHES 12 SingleCharMatch_T Single_Character_Matches[ NUM_SINGLE_CHAR_MATCHES ] = { { '[', LBRACK }, { ']', RBRACK }, @@ -17,6 +17,7 @@ SingleCharMatch_T Single_Character_Matches[ NUM_SINGLE_CHAR_MATCHES ] = { { '*', MUL }, { '/', DIV }, { '.', MEMB }, + { '%', MACRO }, }; DLLexer::DLLexer(std::istream& in) : ILexer(in) @@ -402,7 +403,7 @@ void DLLexer::MultiCharOp(Token& tok) } else { - tok = Token(MACRO, line, column); + tok = Token(MAP, line, column); } } else diff --git a/source/dlparser/dlparser.cpp b/source/dlparser/dlparser.cpp index 69e2c58..c7d58b7 100644 --- a/source/dlparser/dlparser.cpp +++ b/source/dlparser/dlparser.cpp @@ -378,64 +378,61 @@ AST* DLParser::MemberExpr(void) AST* DLParser::Literal(void) { AST* node = NULL; - if(speculate_MapLiteral()) + switch(lookaheadType(1)) { - node = MapLiteral(); - } - else - { - switch(lookaheadType(1)) - { - // Literal = VectorLiteral - case LBRACK: - node = VectorLiteral(); - break; + // Literal = VectorLiteral + case LBRACK: + node = VectorLiteral(); + break; - // Literal = ListLiteral - case LPAR: - node = ListLiteral(); - break; + // Literal = ListLiteral + case LPAR: + node = ListLiteral(); + break; - // Literal = FuncLiteral - case LBRACE: - node = FuncLiteral(); - break; + // Literal = FuncLiteral + case LBRACE: + node = FuncLiteral(); + break; - // Literal = ID - case ID: - node = _new AST( ID, lookaheadToken(1).text() ); - consume(); - break; + case MAP: + node = MapLiteral(); + break; - // Literal = NUM - case NUM: - node = _new AST( NUM, lookaheadToken(1).text() ); - consume(); - break; + // Literal = ID + case ID: + node = _new AST( ID, lookaheadToken(1).text() ); + consume(); + break; - // Literal = CHAR - case CHAR: - node = _new AST( CHAR, lookaheadToken(1).text() ); - consume(); - break; + // Literal = NUM + case NUM: + node = _new AST( NUM, lookaheadToken(1).text() ); + consume(); + break; - // Literal = STRING - case STRING: - node = _new AST( STRING, lookaheadToken(1).text() ); - consume(); - break; + // Literal = CHAR + case CHAR: + node = _new AST( CHAR, lookaheadToken(1).text() ); + consume(); + break; - // Literal = SYMBOL - case SYMBOL: - node = _new AST( SYMBOL, lookaheadToken(1).text() ); - consume(); - break; + // Literal = STRING + case STRING: + node = _new AST( STRING, lookaheadToken(1).text() ); + consume(); + break; - default: - Exception ex( lookaheadToken(1) ); - ex << "Expected literal type, recieved type " << lookaheadToken(1).type() << "."; - throw ex; - } + // Literal = SYMBOL + case SYMBOL: + node = _new AST( SYMBOL, lookaheadToken(1).text() ); + consume(); + break; + + default: + Exception ex( lookaheadToken(1) ); + ex << "Expected literal type, recieved type " << lookaheadToken(1).type() << "."; + throw ex; } return node; } @@ -445,30 +442,18 @@ AST* DLParser::MapLiteral(void) { AST* ret = _new AST(MAP); AST* child = NULL; - try - { - match(LBRACE); - do - { - child = Literal(); - match(SEP); - child = _new AST(SEP, 2, child, LogicalExpr()); - ret->addChild(child); - - if( lookaheadType(1) == COMMA ) consume(); - } - while( lookaheadType(1) != RBRACE ); - match(RBRACE); - } - catch(Exception e) + match(MAP); + match(LBRACE); + while( lookaheadType(1) != RBRACE ) { - // Cleanup our mess so we dont leak memory - delete ret; - if(child != NULL) delete child; + child = Literal(); + match(SEP); + child = _new AST(SEP, 2, child, LogicalExpr()); + ret->addChild(child); - // Re throw the exception so higher-ups can handle it - throw e; + if( lookaheadType(1) == COMMA ) consume(); } + match(RBRACE); return ret; } diff --git a/source/dlparser/macro/pattern.cpp b/source/dlparser/macro/pattern.cpp index c4e5554..15dfce7 100644 --- a/source/dlparser/macro/pattern.cpp +++ b/source/dlparser/macro/pattern.cpp @@ -1,5 +1,6 @@ #include "pattern.h" #include "dllexer.h" +#include "exception.h" using namespace std; @@ -51,7 +52,9 @@ void Pattern::apply(AST* cur,std::vector& params) } else { - throw "Invalid parameter number"; + Exception ex; + ex << "Invalid parameter number"; + throw ex; } } else diff --git a/source/main.cpp b/source/main.cpp index 1c362e1..15e6842 100644 --- a/source/main.cpp +++ b/source/main.cpp @@ -6,6 +6,7 @@ #include "scheme.h" #include "common.h" #include "macro.h" +#include "options.h" using namespace std; @@ -16,6 +17,8 @@ int main(int argc, char** argv) { int ret = 0; + //opts_parse(argc,argv); + if( (argc == 2) && fileExists( argv[1] ) ) { // Setup input and output files diff --git a/source/options/options.c b/source/options/options.c new file mode 100644 index 0000000..7b6c698 --- /dev/null +++ b/source/options/options.c @@ -0,0 +1,101 @@ +#include "options.h" +#include +#include +#include +#include + +static int TempFlag; +static const char ShortOptions[] = "abc:d:f:"; +static struct option LongOptions[] = +{ + /* These options set a flag. */ + {"verbose", no_argument, &TempFlag, 1}, + {"brief", no_argument, &TempFlag, 0}, + + /* These options don't set a flag. + We distinguish them by their indices. */ + {"add", no_argument, 0, 'a'}, + {"append", no_argument, 0, 'b'}, + {"delete", required_argument, 0, 'd'}, + {"create", required_argument, 0, 'c'}, + {"file", required_argument, 0, 'f'}, + {0, 0, 0, 0} +}; + +static void opts_handle_opt(); + +void opts_parse(int argc, char** argv) +{ + int short_opt = 0; + + while(1) + { + int idx = 0; + short_opt = getopt_long(argc, argv, ShortOptions, LongOptions, &idx); + if(short_opt == -1) break; + opts_handle_opt(); + switch (short_opt) + { + case 0: + /* If this option set a flag, do nothing else now. */ + if (LongOptions[idx].flag != 0) + break; + printf ("option %s", LongOptions[idx].name); + if (optarg) + printf (" with arg %s", optarg); + printf ("\n"); + break; + + case 'a': + puts ("option -a\n"); + break; + + case 'b': + puts ("option -b\n"); + break; + + case 'c': + printf ("option -c with value `%s'\n", optarg); + break; + + case 'd': + printf ("option -d with value `%s'\n", optarg); + break; + + case 'f': + printf ("option -f with value `%s'\n", optarg); + break; + + case '?': + /* getopt_long already printed an error message. */ + break; + + default: + abort (); + } + } + + opts_print_usage(); +} + +static void opts_handle_opt() +{ +} + +void opts_print_usage() +{ + int idx = 0; + while(1) + { + const char* name = LongOptions[idx].name; + + // Breakout if we've reached the end of the list + if( name == 0) break; + + if(strlen(name) > 0) + printf("--%s\n", name); + + idx++; + } +} + diff --git a/source/options/options.h b/source/options/options.h new file mode 100644 index 0000000..3331087 --- /dev/null +++ b/source/options/options.h @@ -0,0 +1,7 @@ +#ifndef OPTIONS_H +#define OPTIONS_H + +void opts_parse(int argc, char** argv); +void opts_print_usage(); + +#endif -- 2.52.0