Init commit

This commit is contained in:
Dane Johnson 2021-11-25 11:09:29 -06:00
commit 29ff4cf2d8
7 changed files with 226 additions and 0 deletions

18
Makefile Normal file
View 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
View 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
View File

@ -0,0 +1,7 @@
#include "lexer.h"
#include "parser.h"
void main() {
yydebug = 1;
yyparse();
}

57
example.dee Normal file
View 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
View 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
View 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
View 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
%%