[find the source at indent_test.mdc]

This parser is primarily for testing indent and linebreak handling. It reads a very simple code fragment with if/else statements and simple assignments with expressions, and then prints out the same with complete bracketing and indenting.

File: indent_test.mk

myCFLAGS := -Wall -g -fplan9-extensions
CFLAGS := $(filter-out $(myCFLAGS),$(CFLAGS)) $(myCFLAGS)
LDLIBS:= libparser.o libscanner.o libmdcode.o -licuuc

all :: itest
itest.c itest.h : indent_test.mdc parsergen libparser.o libscanner.o libmdcode.o
    ./parsergen -o itest --LALR --tag indent indent_test.mdc
indent_test.mk: indent_test.mdc md2c
    ./md2c indent_test.mdc
itest: itest.c

tests:: itest itest.code
    ./itest itest.code

indent: header

./parsergen -o itest --LALR indent_test.cgm cc -o itest itest.c lib*.o -licuuc -lgmp ./itest itest.code

struct expression {
    struct text op;
    struct expression *left, *right;
};
struct statement {
    struct statement *next;
    struct expression *expr;
    struct statement *thenpart;
    struct statement *elsepart;
};

indent: code

#include <unistd.h>
#include <stdlib.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <stdio.h>
#include "mdcode.h"
#include "scanner.h"
#include "parser.h"
#include "itest.h"

static void free_expression(struct expression *e)
{
    if (!e)
        return;
    free_expression(e->left);
    free_expression(e->right);
    free(e);
}

static void free_statement(struct statement *s)
{
    if (!s)
        return;
    free_statement(s->next);
    free_expression(s->expr);
    free_statement(s->thenpart);
    free_statement(s->elsepart);
    free(s);
}

static void print_expression(struct expression *e)
{
    if (e->left && e->right) printf("(");
    if (e->left)
        print_expression(e->left);
    if (e->op.len)
        printf("%.*s", e->op.len, e->op.txt);
    if (e->right)
        print_expression(e->right);
    if (e->left && e->right) printf(")");
}

static void print_statement(struct statement *s, int depth)
{
    if (!s)
        return;
    if (!s->thenpart) {
        printf("%*.s", depth, "");
        print_expression(s->expr);
        printf(";\n");
    } else {
        printf("%*.sif ", depth, "");
        print_expression(s->expr);
        printf(":\n");
        print_statement(s->thenpart, depth+4);
        if (s->elsepart) {
            printf("%*.selse:\n", depth, "");
            print_statement(s->elsepart, depth+4);
        }
    }
    print_statement(s->next, depth);
}

int main(int argc, char *argv[])
{
    int fd = open(argv[1], O_RDONLY);
    int len = lseek(fd, 0, 2);
    char *file = mmap(NULL, len, PROT_READ, MAP_SHARED, fd, 0);
    struct section *s = code_extract(file, file+len, NULL);
    struct token_config config = {
        .ignored = (1 << TK_line_comment)
                 | (1 << TK_block_comment),
        .number_chars = ".,_+-",
        .word_start = "",
        .word_cont = "",
    };
    parse_itest(s->code, &config, argc > 2 ? stderr : NULL);
    while (s) {
        struct section *t = s->next;
        code_free(s->code);
        free(s);
        s = t;
    }
    exit(0);
}

indent: grammar

~~~~~~

Program -> Statementlist ${ print_statement($1, 0); }$

OptNL -> NEWLINE |

$*statement Statementlist -> Statements ${ $0 = $<1; }$

Statements -> Statements Statement ${
            {
                struct statement **s;
                $0 = $<1;
                s = &$0;
                while (*s)
                    s = &(*s)->next;
                *s = $<2;
            }
            }$
        | Statement ${ $0 = $<1; }$
        | ERROR ${ printf("statement ERROR\n"); $0 = NULL; }$

Open -> {
    | NEWLINE {
Close -> }
    | NEWLINE }
Block -> Open Statementlist Close ${ $0 = $<2; }$
    | Open SimpleStatements } ${ $0 = $<2; }$
    | : Statementlist ${ $0 = $2; $2 = NULL; }$

SimpleStatements -> SimpleStatements ; SimpleStatement ${
        {
            struct statement **s;
            $0 = $<1;
            s = &$0;
            while (*s)
                s = &(*s)->next;
            *s = $<3;
        }
        }$
    | SimpleStatement ${ $0 = $<1; }$
    | SimpleStatements ; ${ $0 = $<1; }$

SimpleStatement -> Factor = Expression ${
        $0 = calloc(1, sizeof(struct statement));
        $0->expr = calloc(1, sizeof(struct expression));
        $0->expr->left = $<1;
        $0->expr->op = $2.txt;
        $0->expr->right = $<3;
        }$
Statement -> SimpleStatements NEWLINE ${
        $0 = $<1;
        }$
    | IfStatement ${ $0 = $<1; }$
    | Statement NEWLINE ${ $0 = $<1; }$

IfStatement -> if Expression Block OptNL ${
            $0 = calloc(1, sizeof(struct statement));
            $0->expr = $<2;
            $0->thenpart = $<3;
            }$
    | if Expression : SimpleStatements ${
            $0 = calloc(1, sizeof(struct statement));
            $0->expr = $<2;
            $0->thenpart = $<4;
            }$
    | if Expression Block OptNL else Block ${
            $0 = calloc(1, sizeof(struct statement));
            $0->expr = $<2;
            $0->thenpart = $<3;
            $0->elsepart = $<6;
            }$
    | if Expression Block OptNL else : SimpleStatements ${
            $0 = calloc(1, sizeof(struct statement));
            $0->expr = $<2;
            $0->thenpart = $<3;
            $0->elsepart = $<7;
            }$
    | if Expression Block OptNL else IfStatement ${
            $0 = calloc(1, sizeof(struct statement));
            $0->expr = $<2;
            $0->thenpart = $<3;
            $0->elsepart = $<6;
            }$

$*expression Expression -> Expression + Term ${ $0 = calloc(1, sizeof(struct expression)); $0->op = $2.txt; $0->left = $<1; $0->right = $<3; }$ | Expression - Term ${ $0 = calloc(1, sizeof(struct expression)); $0->op = $2.txt; $0->left = $<1; $0->right = $<3; }$ | Term ${ $0 = $1; $1 = NULL; }$ Term -> Term * Factor ${ $0 = calloc(1, sizeof(struct expression)); $0->op = $2.txt; $0->left = $<1; $0->right = $<3; }$ | Term / Factor ${ $0 = calloc(1, sizeof(struct expression)); $0->op = $2.txt; $0->left = $<1; $0->right = $<3; }$ | Factor ${ $0 = $1; $1 = NULL; }$ Factor -> IDENTIFIER ${ $0 = calloc(1, sizeof(struct expression)); $0->op = $1.txt; }$ ~~~~~~

File: itest.code

# test code
~~~~~~
hello = yes; mister = no;
there = x;
all = y;
if cond + cond2 :
    hello = x;
    hello2 = x;

    sum = val +
     val;

    if condX:
     foo = x *
                x +
                y
                / two;
 else if cond2:
    there1 =x
    there1a=x
there2=x
there3=x;
all = y;
if true {yes=x;} else : no=x
if true: yes = no; no = yes;

if false {
    print = OK
} else {
    print = not_OK
}

if a:
    if b:
        c= d
x = y