The list might be interested to see a C version of what is writen in perl
using the Thin interface.
This is the first test that is in t/thin_eq.t, doing this ambiguous grammar:
:start ::= S
S ::= E
E ::= E op E
E ::= number
applied on tokens "2", "-", "0", "*", "3", "+", "1".
Result is:
Expected result (((2-0)*3)+1) == 7, value 7
Expected result ((2-(0*3))+1) == 3, value 3
Expected result (2-((0*3)+1)) == 1, value 1
Expected result (2-(0*(3+1))) == 2, value 2
Expected result ((2-0)*(3+1)) == 8, value 8
Source files in attachment.
May I ask somebody to review it, because I plan to submit it to git for
inclusion in debian packages -;
valgrind on it is happy v.s. eventual lekage btw.
Thanks, Jean-Damien.
--
You received this message because you are subscribed to the Google Groups
"marpa parser" group.
To unsubscribe from this group and stop receiving emails from it, send an email
to [email protected].
For more options, visit https://groups.google.com/d/optout.
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <string.h>
#include <marpa.h>
#include "thin_macros.h"
/*
C version of first example in file t/thin_eq.t
from Marpa::R2 CPAN distribution
Grammar is:
:start ::= S
S ::= E
E ::= E op E
E ::= number
Expected values:
(2-(0*(3+1))) == 2 => 1
(((2-0)*3)+1) == 7 => 1
((2-(0*3))+1) == 3 => 1
((2-0)*(3+1)) == 8 => 1
(2-((0*3)+1)) == 1 => 1
Compilation: cc -g -o ./thin ./thin.c -lmarpa
Execution : ./thin
*/
/* A stack here is composed of two elements, the string and a corresponding int */
typedef struct s_stack {
char *string;
int value;
} s_stack_;
static char *_make_str (const char *fmt, ...);
static void _check (Marpa_Error_Code errorCode, const char *call, int forcedCondition);
static void _push_to_stack(s_stack_ **stackpp, int *stacksizep, int index, char *string, int value);
struct marpa_error_description_s {
Marpa_Error_Code error_code;
const char*name;
const char*suggested;
};
extern const struct marpa_error_description_s marpa_error_description[];
int main() {
Marpa_Config marpa_configuration;
Marpa_Grammar g;
Marpa_Symbol_ID S, E, op, number;
Marpa_Rule_ID start_rule_id, op_rule_id, number_rule_id;
Marpa_Recognizer r;
char *token_values[] = { "0", "1", "2", "3", "0", "-", "+", "*" };
s_stack_ expected_results[5] = {
{"(2-(0*(3+1))) == 2", 2},
{"(((2-0)*3)+1) == 7", 7},
{"((2-(0*3))+1) == 3", 3},
{"((2-0)*(3+1)) == 8", 8},
{"(2-((0*3)+1)) == 1", 1}
};
int ivalue = 0;
Marpa_Earley_Set_ID latest_earley_set_ID;
Marpa_Bocage bocage;
Marpa_Order order;
Marpa_Tree tree;
s_stack_ *stackp = NULL;
size_t stacksize = -1;
int zero = 4; /* Indice 4 in token_values */
int minus_token_value = 5; /* Indice 5 in token_values */
int plus_token_value = 6; /* Indice 6 in token_values */
int multiply_token_value = 7; /* Indice 7 in token_values */
/* Configuration initialisation */
marpa_c_init(&marpa_configuration); /* never fails as per the doc */
/* Grammar creation */
g = marpa_g_new(&marpa_configuration);
_check(marpa_c_error(&marpa_configuration, NULL), "marpa_g_new()", g == NULL);
/* Symbols creation */
CREATE_SYMBOL(S, g);
CREATE_SYMBOL(E, g);
CREATE_SYMBOL(op, g);
CREATE_SYMBOL(number, g);
/* ::start ::= S */
SET_START_SYMBOL(S, g);
/* Rules creation */
{Marpa_Symbol_ID rhs[] = { E }; CREATE_RULE(start_rule_id, g, S, rhs, ARRAY_LENGTH(rhs));}
{Marpa_Symbol_ID rhs[] = { E, op, E }; CREATE_RULE(op_rule_id, g, E, rhs, ARRAY_LENGTH(rhs));};
{Marpa_Symbol_ID rhs[] = { number }; CREATE_RULE(number_rule_id, g, E, rhs, ARRAY_LENGTH(rhs));}
PRECOMPUTE(g);
r = marpa_r_new(g);
if (r == NULL) {
fprintf(stderr, "marpa_r_new() failure\n");
exit(EXIT_FAILURE);
}
if (marpa_r_start_input(r) < 0) {
fprintf(stderr, "marpa_r_start_input() failure\n");
exit(EXIT_FAILURE);
}
/*
The numbers from 1 to 3 are themselves --
that is, they index their own token value.
Important: zero cannot be itself!
*/
ALTERNATIVE(r, number, 2, 1);
EARLEME_COMPLETE(r);
ALTERNATIVE(r, op, minus_token_value, 1);
EARLEME_COMPLETE(r);
ALTERNATIVE(r, number, zero, 1);
EARLEME_COMPLETE(r);
ALTERNATIVE(r, op, multiply_token_value, 1);
EARLEME_COMPLETE(r);
ALTERNATIVE(r, number, 3, 1);
EARLEME_COMPLETE(r);
ALTERNATIVE(r, op, plus_token_value, 1);
EARLEME_COMPLETE(r);
ALTERNATIVE(r, number, 1, 1);
EARLEME_COMPLETE(r);
latest_earley_set_ID = marpa_r_latest_earley_set(r);
bocage = marpa_b_new(r, latest_earley_set_ID);
if (bocage == NULL) {
fprintf(stderr, "marpa_b_new() failure\n");
exit(EXIT_FAILURE);
}
order = marpa_o_new(bocage);
if (order == NULL) {
fprintf(stderr, "marpa_o_new() failure\n");
exit(EXIT_FAILURE);
}
tree = marpa_t_new(order);
if (tree == NULL) {
fprintf(stderr, "marpa_t_new() failure\n");
exit(EXIT_FAILURE);
}
while (1) {
int itree = marpa_t_next(tree);
int nextok = 1;
Marpa_Value valuator;
if (itree < 0) {
break;
}
if ((valuator = marpa_v_new(tree)) == NULL) {
fprintf(stderr, "marpa_v_new() failure\n");
exit(EXIT_FAILURE);
}
marpa_v_symbol_is_valued_set(valuator, op_rule_id, 1);
marpa_v_symbol_is_valued_set(valuator, start_rule_id, 1);
marpa_v_symbol_is_valued_set(valuator, number_rule_id, 1);
while (nextok) {
Marpa_Step_Type type = marpa_v_step(valuator);
Marpa_Rule_ID rule_id;
switch (type) {
case MARPA_STEP_TOKEN:
{
Marpa_Symbol_ID token_id = marpa_v_token(valuator);
int token_value_ix = marpa_v_token_value(valuator);
int arg_n = marpa_v_result(valuator);
PUSH_TO_STACK(arg_n, strdup(token_values[token_value_ix]), atoi(token_values[token_value_ix]));
break;
}
case MARPA_STEP_RULE:
{
Marpa_Rule_ID rule_id = marpa_v_rule(valuator);
int arg_0 = marpa_v_arg_0(valuator);
int arg_n = marpa_v_arg_n(valuator);
if (rule_id == start_rule_id) {
PUSH_TO_STACK(arg_0, _make_str("%s == %d", stackp[arg_n].string, stackp[arg_n].value), stackp[arg_n].value);
}
else if (rule_id == number_rule_id) {
PUSH_TO_STACK(arg_0, _make_str("%d", stackp[arg_0].value), stackp[arg_0].value);
}
else if (rule_id == op_rule_id) {
char *left_string = stackp[arg_0].string;
int left_value = stackp[arg_0].value;
char *op = stackp[arg_0 + 1].string;
char *right_string = stackp[arg_n].string;
int right_value = stackp[arg_n].value;
int value;
char *text = _make_str("(%s%s%s)", left_string, op, right_string);
switch (*op) {
case '+':
PUSH_TO_STACK(arg_0, text, left_value + right_value);
break;
case '-':
PUSH_TO_STACK(arg_0, text, left_value - right_value);
break;
case '*':
PUSH_TO_STACK(arg_0, text, left_value * right_value);
break;
default:
fprintf(stderr, "Unknown op %s\n", op);
exit(EXIT_FAILURE);
}
} else {
fprintf(stderr, "Unknown rule %d\n", rule_id);
exit(EXIT_FAILURE);
}
break;
}
case MARPA_STEP_INACTIVE:
nextok = 0;
break;
default:
fprintf(stderr, "Unexpected type %d\n", type);
exit(EXIT_FAILURE);
}
}
/* Check result and free the stack */
if (stacksize < 0) {
fprintf(stderr, "No result !?\n");
} else {
int i;
s_stack_ *expected_resultp = NULL;
for (i = 0; i <= ARRAY_LENGTH(expected_results); i++) {
if (strcmp(expected_results[i].string, stackp[0].string) == 0) {
expected_resultp = &(expected_results[i]);
}
}
if (expected_resultp == NULL) {
fprintf(stderr, "Totally unexpected result %s, value %d\n", stackp[0].string, stackp[0].value);
} else {
if (expected_resultp->value == stackp[0].value) {
fprintf(stderr, "Expected result %s, value %d\n", expected_resultp->string, expected_resultp->value);
} else {
fprintf(stderr, "Unexpected result %s, value %d instead of %d\n", stackp[0].string, stackp[0].value, expected_resultp->value);
}
}
for (i = 0; i <= stacksize; i++) {
free(stackp[i].string);
stackp[i].string = NULL;
}
free(stackp);
stackp = NULL;
stacksize = -1;
}
/* Free valuator */
marpa_v_unref(valuator);
}
/* Free marpa */
marpa_t_unref(tree);
marpa_o_unref(order);
marpa_b_unref(bocage);
marpa_r_unref(r);
marpa_g_unref(g);
exit(EXIT_SUCCESS);
}
/* Copied almost verbatim from snprintf man page on Linux */
static char *_make_str(const char *fmt, ...) {
int n;
int size = 100; /* Guess we need no more than 100 bytes */
char *p, *np;
va_list ap;
p = malloc(size);
if (p == NULL) {
fprintf(stderr, "malloc() failure\n");
exit(EXIT_FAILURE);
}
while (1) {
/* Try to print in the allocated space */
va_start(ap, fmt);
n = vsnprintf(p, size, fmt, ap);
va_end(ap);
/* Check error code */
if (n < 0) {
free(p);
fprintf(stderr, "vsnprintf() failure\n");
exit(EXIT_FAILURE);
}
/* If that worked, return the string */
if (n < size) {
return p;
}
/* Else try again with more space */
size = n + 1; /* Precisely what is needed */
np = realloc(p, size);
if (np == NULL) {
free(p);
fprintf(stderr, "realloc() failure\n");
exit(EXIT_FAILURE);
} else {
p = np;
}
}
}
static void _check(Marpa_Error_Code errorCode, const char *call, int forcedCondition) {
if (forcedCondition != 0 || errorCode != MARPA_ERR_NONE) {
const char *function = (call != NULL) ? call : "<unknown>";
const char *msg = (errorCode >= 0 && errorCode < MARPA_ERROR_COUNT) ? marpa_error_description[errorCode].name : "Generic error";
fprintf(stderr,"%s: %s", function, msg);
exit(EXIT_FAILURE);
}
}
static void _push_to_stack(s_stack_ **stackpp, int *stacksizep, int index, char *string, int value) {
s_stack_ *stackp = *stackpp;
int stacksize = *stacksizep;
if (stacksize < index) {
if (stacksize < 0) {
stackp = malloc(sizeof(s_stack_));
} else {
stackp = realloc(stackp, sizeof(s_stack_) * (index + 1));
}
stacksize = index;
}
if (stackp == NULL) {
exit(EXIT_FAILURE);
}
if (stackp[index].string != NULL) {
free(stackp[index].string);
}
stackp[index].string = string;
stackp[index].value = value;
*stacksizep = stacksize;
*stackpp = stackp;
}
#ifndef THIN_MACROS_H
#define THIN_MACROS_H
#define ARRAY_LENGTH(array) (sizeof((array))/sizeof((array)[0]))
#define CREATE_SYMBOL(symbolId, grammar) { \
marpa_g_error_clear(grammar); \
symbolId = marpa_g_symbol_new(grammar); \
_check(marpa_g_error(grammar, NULL), "marpa_g_symbol_new()", symbolId < 0); \
}
#define CREATE_RULE(ruleId, grammar, ...) { \
marpa_g_error_clear(grammar); \
ruleId = marpa_g_rule_new(grammar, __VA_ARGS__); \
_check(marpa_g_error(grammar, NULL), "marpa_g_rule_new()", ruleId < 0); \
}
#define SET_START_SYMBOL(symbolId, grammar) { \
marpa_g_error_clear(grammar); \
int result = marpa_g_start_symbol_set(grammar, symbolId); \
_check(marpa_g_error(grammar, NULL), "marpa_g_start_symbol_set()", result < 0); \
}
#define PRECOMPUTE(grammar) { \
int result; \
marpa_g_error_clear(grammar); \
result = marpa_g_precompute(grammar); \
_check(marpa_g_error(grammar, NULL), "marpa_g_precompute()", result < 0); \
}
#define ALTERNATIVE(r, token_id, value, length) { \
int result = marpa_r_alternative (r, token_id, value, length); \
if (result != MARPA_ERR_NONE) { \
fprintf(stderr, "marpa_r_alternative() failure, error code %d", result); \
} \
}
#define EARLEME_COMPLETE(r) { \
Marpa_Earleme result = marpa_r_earleme_complete(r); \
if (result < 0) { \
fprintf(stderr, "marpa_r_earleme_complete() failure, error code %d", result); \
} \
}
#define PUSH_TO_STACK(index, str, val) { \
_push_to_stack(&stackp, &stacksize, (index), (str), (val)); \
}
#endif /* THIN_MACROS_H */