Init commit
This commit is contained in:
commit
29ff4cf2d8
18
Makefile
Normal file
18
Makefile
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
.PHONY: all clean
|
||||||
|
all: deelang
|
||||||
|
|
||||||
|
lexer.o lexer.h: parser.h lexer.l
|
||||||
|
flex -o lexer.c --header-file=lexer.h lexer.l
|
||||||
|
$(CC) -c lexer.c
|
||||||
|
rm lexer.c
|
||||||
|
|
||||||
|
parser.h parser.o: parser.y
|
||||||
|
bison -o parser.c --header=parser.h parser.y
|
||||||
|
$(CC) -c parser.c
|
||||||
|
rm parser.c
|
||||||
|
|
||||||
|
deelang: deelang.c lexer.o parser.o
|
||||||
|
$(CC) -o $@ $^
|
||||||
|
|
||||||
|
clean:
|
||||||
|
rm -rf parser.o lexer.o parser.h lexer.h deelang
|
15
blockexample.dee
Normal file
15
blockexample.dee
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
fun <- ->
|
||||||
|
do-something()
|
||||||
|
do-something-else()
|
||||||
|
|
||||||
|
|
||||||
|
foo <- ->
|
||||||
|
bar <- ->
|
||||||
|
baz <- ->
|
||||||
|
print("Deep in here")
|
||||||
|
print ("Inside foo but not in baz or bar")
|
||||||
|
|
||||||
|
foo() ## Inside foo but not in baz or bar
|
||||||
|
|
||||||
|
add <- x -> y ->
|
||||||
|
return x + y
|
7
deelang.c
Normal file
7
deelang.c
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
#include "lexer.h"
|
||||||
|
#include "parser.h"
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
yydebug = 1;
|
||||||
|
yyparse();
|
||||||
|
}
|
57
example.dee
Normal file
57
example.dee
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
## By the end of the book I want to have an interpreter
|
||||||
|
## for this little language, maybe a compiler too
|
||||||
|
|
||||||
|
print(1 + 1) ## 2
|
||||||
|
print("Hello world!") ## Hello world
|
||||||
|
|
||||||
|
name <- read()
|
||||||
|
print("Hi there $name") ## Hi there <name>
|
||||||
|
|
||||||
|
have <- 10
|
||||||
|
want <- 11
|
||||||
|
need <- have - want ## This is subtraction
|
||||||
|
have-want <- 1 ## This is a variable named "have-want"
|
||||||
|
|
||||||
|
print HaVe-WAnt ## 1 (case doesn't matter)
|
||||||
|
%%option meaningful-casing
|
||||||
|
Apples <- 1
|
||||||
|
print apples ## <undef> (or maybe it does)
|
||||||
|
|
||||||
|
print("one fish"); print("two fish") ## Two variables on the same line
|
||||||
|
|
||||||
|
say-hi <- -> print("Hi from inside a function")
|
||||||
|
say-hi() ## Hi from inside a function
|
||||||
|
|
||||||
|
say-hi-again <- say-hi
|
||||||
|
say-hi-again() ## "Hi from inside a function" (First class functions!)
|
||||||
|
|
||||||
|
duck <- {
|
||||||
|
bills <- 1
|
||||||
|
talk <- -> print("Quack")
|
||||||
|
eats? <- food -> food = "bread"
|
||||||
|
} ## Objects created on the fly
|
||||||
|
|
||||||
|
print duck.eats?("bread") ## true
|
||||||
|
print duck.eats?("corn") ## false
|
||||||
|
|
||||||
|
cow <- {
|
||||||
|
talk <- print("Moo")
|
||||||
|
eats? <- food -> food oneof "grass", "corn"
|
||||||
|
}
|
||||||
|
|
||||||
|
human <- {
|
||||||
|
eats? <- _ -> true
|
||||||
|
}
|
||||||
|
|
||||||
|
print cow.eats?("grass") ## true
|
||||||
|
print cow.eats?("corn") ## true
|
||||||
|
|
||||||
|
talk-or-pass-wind <- character ->
|
||||||
|
if character has talk then
|
||||||
|
character.talk()
|
||||||
|
else
|
||||||
|
print("*Fart*")
|
||||||
|
|
||||||
|
talk-or-pass-wind(duck) ## "Quack"
|
||||||
|
talk-or-pass-wind(cow) ## "Moo"
|
||||||
|
talk-or-pass-wind(human) ## "*Fart*"
|
11
lexdemo.c
Normal file
11
lexdemo.c
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
#include "lexer.h"
|
||||||
|
#include "parser.h"
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
int t;
|
||||||
|
while ((t = yylex()) != 0) {
|
||||||
|
printf("yylex=0x%x\n", t);
|
||||||
|
printf("yylval=%s\n", yylval.sym);
|
||||||
|
}
|
||||||
|
printf("Byebye!");
|
||||||
|
}
|
66
lexer.l
Normal file
66
lexer.l
Normal file
@ -0,0 +1,66 @@
|
|||||||
|
%{
|
||||||
|
#include "parser.h"
|
||||||
|
int stack[100]; // Max indentation depth
|
||||||
|
int sp = -1;
|
||||||
|
int peek();
|
||||||
|
void push(int a);
|
||||||
|
void pop();
|
||||||
|
#define YY_USER_INIT push(0); BEGIN(freshline);
|
||||||
|
%}
|
||||||
|
|
||||||
|
%option noyywrap
|
||||||
|
|
||||||
|
%x freshline
|
||||||
|
|
||||||
|
digit [0-9]
|
||||||
|
letter [A-Za-z]
|
||||||
|
|
||||||
|
%%
|
||||||
|
<freshline>""/[^\t ] {
|
||||||
|
if (peek() == 0) {
|
||||||
|
BEGIN(0);
|
||||||
|
} else {
|
||||||
|
pop(); yyless(0); return DEDENT;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
<freshline>[ \t]+ {
|
||||||
|
if (peek() == yyleng) {
|
||||||
|
BEGIN(0); // Same indentation, continue
|
||||||
|
} else if (peek() > yyleng) {
|
||||||
|
pop(); yyless(0); return DEDENT;
|
||||||
|
// Same rule again until the stack is even
|
||||||
|
} else {
|
||||||
|
push(yyleng); BEGIN(0); return INDENT;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#[^\n]* // Eat comments
|
||||||
|
\"[^"]*\" yylval.sym = yytext; return STRING;
|
||||||
|
if return IF;
|
||||||
|
else return ELSE;
|
||||||
|
elif return ELIF;
|
||||||
|
{digit}+|{digit}*\.{digit}+ yylval.num = atof(yytext); return NUM;
|
||||||
|
{letter}({letter}|{digit}|[?-])* yylval.sym = yytext; return ID;
|
||||||
|
"<-" return GETS;
|
||||||
|
"->" return MAPS;
|
||||||
|
[().,*/+-] return yytext[0];
|
||||||
|
[\t ] // Eat whitespace not first on a line
|
||||||
|
"/"\n // Eat newlines ending in /
|
||||||
|
[\n;] BEGIN(freshline); return STOP;
|
||||||
|
. fprintf(stderr, "Scanning error!\nOffender: %s\n", yytext); exit(1);
|
||||||
|
%%
|
||||||
|
|
||||||
|
int peek() {
|
||||||
|
printf("Peek @ %d\n", stack[sp]);
|
||||||
|
return stack[sp];
|
||||||
|
}
|
||||||
|
|
||||||
|
void push(int a) {
|
||||||
|
printf("Push @ %d\n", a);
|
||||||
|
sp++;
|
||||||
|
stack[sp] = a;
|
||||||
|
}
|
||||||
|
|
||||||
|
void pop() {
|
||||||
|
printf("Pop! Sp @ %d\n", sp);
|
||||||
|
sp--;
|
||||||
|
}
|
52
parser.y
Normal file
52
parser.y
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
%{
|
||||||
|
#include <stdio.h>
|
||||||
|
int yylex();
|
||||||
|
int yyerror(const char* p) { fprintf(stderr, p); }
|
||||||
|
%}
|
||||||
|
|
||||||
|
%define parse.trace
|
||||||
|
|
||||||
|
%union {
|
||||||
|
char* sym;
|
||||||
|
float num;
|
||||||
|
}
|
||||||
|
|
||||||
|
%token <sym> ID
|
||||||
|
%token STOP
|
||||||
|
%token <num> NUM
|
||||||
|
%token STRING
|
||||||
|
%token INDENT DEDENT
|
||||||
|
%token IF ELIF ELSE
|
||||||
|
|
||||||
|
%right GETS
|
||||||
|
%left '+' '-'
|
||||||
|
%left '/' '*'
|
||||||
|
%left MAPS
|
||||||
|
|
||||||
|
%%
|
||||||
|
program: statements | statements statement;
|
||||||
|
statements: statements statement STOP
|
||||||
|
| statements STOP
|
||||||
|
| // null production ;
|
||||||
|
statement: assignment | funcall | conditional;
|
||||||
|
assignment: ID GETS expr;
|
||||||
|
expr: funcdef
|
||||||
|
| funcall
|
||||||
|
| expr '+' expr
|
||||||
|
| expr '-' expr
|
||||||
|
| expr '*' expr
|
||||||
|
| expr '/' expr
|
||||||
|
| '(' expr ')'
|
||||||
|
| ID | NUM | STRING;
|
||||||
|
|
||||||
|
funcdef: param MAPS expr | param MAPS block;
|
||||||
|
param: ID | '_' | // null production;
|
||||||
|
funcall: ID '(' exprlist ')'
|
||||||
|
exprlist: exprlist ',' expr | expr | // null production;
|
||||||
|
|
||||||
|
conditional: IF expr block elifs
|
||||||
|
| IF expr block elifs ELSE block;
|
||||||
|
elifs: ELIF expr block elifs| // null production;
|
||||||
|
|
||||||
|
block: STOP INDENT statement statements DEDENT
|
||||||
|
%%
|
Loading…
Reference in New Issue
Block a user