Select Git revision
test_ExecClassif.py
json_parser.c 15.43 KiB
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include"json_parser.h"
/* --------------------------------------------------------------------------- */
/* quelques macros utiles */
/* --------------------------------------------------------------------------- */
#define is_num(c)(('0' <= (c)) && ((c) <= '9'))
#define is_maj(c)(('A' <= (c)) && ((c) <= 'Z'))
#define is_min(c)(('a' <= (c)) && ((c) <= 'z'))
#define is_alpha(c)(is_maj(c) || is_min(c) || (c) == '_' || (c) == '$')
#define is_alphanum(c)(is_num((c)) || is_alpha((c)))
void initialise_premiers(json_parser_ctx *ctx);
void initialise_suivants(json_parser_ctx *ctx);
int yylex(json_parser_ctx *ctx);
json_struct *json_parse(char *filename)
{
return json_parse_full(filename, 0);
}
json_struct *json_parse_full(char *filename, int trace_xml)
{
json_parser_ctx *ctx=json_parser_init_full(filename, trace_xml);
json_struct *root = structure(ctx);
fclose(ctx->yyin);
free(ctx);
return root;
}
json_parser_ctx *json_parser_init(char *filename)
{
return json_parser_init_full(filename, 0);
}
json_parser_ctx *json_parser_init_full(char *filename, int trace_xml)
{
json_parser_ctx *ctx = (json_parser_ctx *) malloc(sizeof(json_parser_ctx));
ctx->nb_ligne = 1;
ctx->trace_xml = trace_xml;
ctx->indent_xml = 0;
ctx->indent_step = 1;
initialise_premiers(ctx);
initialise_suivants(ctx);
ctx->tableMotsClefs[0] = (char *) "true";
ctx->tableMotsClefs[1] = (char *) "false";
ctx->tableMotsClefs[2] = (char *) "null";
ctx->codeMotClefs[0] = CONSTANT;
ctx->codeMotClefs[1] = CONSTANT;
ctx->codeMotClefs[2] = CONSTANT;
ctx->yyin = fopen(filename, "r");
if(ctx->yyin == NULL){
fprintf(stderr, "cannot open file %s\n", filename);
exit(1);
}
ctx->uc = yylex(ctx);
return ctx;
}
/*-------------------------------------------------------------------------*/
/* Affiche le message d'erreur donné en paramètre, avec le numéro de ligne */
/*-------------------------------------------------------------------------*/
void erreur(json_parser_ctx *ctx, char *message) {
fprintf (stderr, "ERREUR ligne %d : ", ctx->nb_ligne);
fprintf (stderr, "%s\n", message);
exit(1);
}
/*******************************************************************************
* Fonction qui ignore les espaces et commentaires.
* Renvoie -1 si arrivé à la fin du fichier, 0 si tout va bien
******************************************************************************/
int mangeEspaces(json_parser_ctx *ctx)
{
char c = fgetc(ctx->yyin);
int comment = 0;
while( comment || (c == ' ') || (c == '\n') || (c == '\t') || (c == '#' ) || (c == '\r') ) {
if( c == '#' ) {
comment = 1;
}
if( (c == '\n') || (c == '\r')) {
ctx->nb_ligne++;
comment = 0;
}
c = fgetc(ctx->yyin);
}
if ( feof(ctx->yyin) ) {
return -1;
}
ungetc(c, ctx->yyin);
return 0;
}
/*******************************************************************************
* Lit un caractère et le stocke dans le buffer yytext
******************************************************************************/
char lireCar(json_parser_ctx *ctx)
{
ctx->yytext[ctx->yyleng++] = fgetc(ctx->yyin);
ctx->yytext[ctx->yyleng] = '\0';
return ctx->yytext[ctx->yyleng - 1];
}
/*******************************************************************************
* Remet le dernier caractère lu au buffer clavier et enlève du buffer yytext
******************************************************************************/
void delireCar(json_parser_ctx *ctx)
{
char c;
c = ctx->yytext[ctx->yyleng - 1];
ctx->yytext[--ctx->yyleng] = '\0';
ungetc(c, ctx->yyin);
}
/*******************************************************************************
* Fonction principale de l'analyseur lexical, lit les caractères de yyin et
* renvoie les tokens sous forme d'entier. Pour les tokens de
* type NUMBER et STRING la valeur du token est dans yytext, visible
* dans l'analyseur syntaxique.
******************************************************************************/
int yylex(json_parser_ctx *ctx)
{
char c;
int i;
ctx->yytext[ctx->yyleng = 0] = '\0';
/* Si j'ai trouvé la fin du fichier en lisant des espaces ... */
if( mangeEspaces(ctx) == -1 ) {
return FIN; /* Renvoie le marqueur de fin d'entrée */
}
c = lireCar(ctx);
/* Caractères uniques non-ambigus */
if(c == ',') return VIRGULE;
if(c == ':') return COLON;
if(c == '{') return ACCOLADE_OUVRANTE;
if(c == '}') return ACCOLADE_FERMANTE;
if(c == '[') return CROCHET_OUVRANT;
if(c == ']') return CROCHET_FERMANT;
if(is_num(c) || (c == '-')){
do{
c = lireCar(ctx);
} while(is_num(c) || (c == '.'));
delireCar(ctx);
return NUMBER;
}
if(c == '"') {
ctx->yyleng = 0;
c = lireCar(ctx);
while(c != '"'){
if(ctx->yyleng >= YYTEXT_MAX){
erreur(ctx, (char *) "constante trop longue");
}
c = lireCar(ctx);
}
ctx->yytext[--ctx->yyleng] = '\0';
// printf("c = %c yytext = %s\n", c, ctx->yytext);
return STRING;
}
while( is_alphanum(c) ) {
c = lireCar(ctx);
}
delireCar(ctx);
for(i=0; i < NB_MOTS_CLEFS; i++){
if(!strcmp(ctx->yytext, ctx->tableMotsClefs[i])){
return ctx->codeMotClefs[i];
}
}
if( feof( ctx->yyin ) ) {
return '.';
}
if(ctx->yyleng == 0) {
fprintf( stderr, "Ligne %d: caractère invalide: %c\n", ctx->nb_ligne, c );
exit(-1);
}
return -1;
}
/*-------------------------------------------------------------------------*/
void indent(json_parser_ctx *ctx) {
int i;
for( i = 0; i < ctx->indent_xml; i++ ) {
printf( " " );
}
}
/*-------------------------------------------------------------------------*/
void consommer(json_parser_ctx *ctx, int c ) {
if( ctx->uc == c ){
// affiche_feuille(ctx);
ctx->uc = yylex(ctx); /* consommer le caractère */
}
else
erreur(ctx, (char *) "erreure lexicale" );
}
/*-------------------------------------------------------------------------*/
void affiche_balise_ouvrante(json_parser_ctx *ctx, const char *fct_)
{
if(ctx->trace_xml ) {
indent(ctx);
ctx->indent_xml += ctx->indent_step ;
fprintf (stdout, "<%s>\n", fct_);
}
}
/*-------------------------------------------------------------------------*/
void affiche_balise_fermante(json_parser_ctx *ctx, const char *fct_) {
if(ctx->trace_xml) {
ctx->indent_xml -= ctx->indent_step ;
indent(ctx);
fprintf (stdout, "</%s>\n", fct_);
}
}
/*-------------------------------------------------------------------------*/
void affiche_texte(json_parser_ctx *ctx, char *texte_) {
if(ctx->trace_xml) {
indent(ctx);
fprintf (stdout, "%s\n", texte_);
}
}
/*-------------------------------------------------------------------------*/
void affiche_xml_texte(json_parser_ctx *ctx, char *texte_ ) {
int i = 0;
while( texte_[ i ] != '\0' ) {
if( texte_[ i ] == '<' ) {
fprintf( stdout, "<" );
}
else if( texte_[ i ] == '>' ) {
fprintf( stdout, ">" );
}
else if( texte_[ i ] == '&' ) {
fprintf( stdout, "&" );
}
else {
putchar( texte_[i] );
}
i++;
}
}
/*-------------------------------------------------------------------------*/
void affiche_element(json_parser_ctx *ctx, char *fct_, char *texte_, int trace_xml) {
if(trace_xml) {
indent(ctx);
fprintf (stdout, "<%s>", fct_ );
affiche_xml_texte(ctx, texte_ );
fprintf (stdout, "</%s>\n", fct_ );
}
}
/* --------------------------------------------------------------------------- */
int est_suivant(json_parser_ctx *ctx, int terminal, int non_terminal)
{
return ctx->suivants[non_terminal][terminal];
}
int est_premier(json_parser_ctx *ctx, int terminal, int non_terminal)
{
return ctx->premiers[non_terminal][terminal];
}
/* ################################################################
First(structure) = NUMBER CONSTANT '{' '[' STRING
First(list) = '['
First(list_structure) = ε CONSTANT STRING NUMBER '{' '['
First(list_structure2) = ε ','
First(object) = '{'
First(list_attr_val) = ε STRING
First(list_attr_val2) = ε ','
First(attr_val) = STRING
################################################################ */
void initialise_premiers(json_parser_ctx *ctx){
int i,j;
for(i=0; i <= NB_NON_TERMINAUX; i++)
for(j=0; j <= NB_TERMINAUX; j++)
ctx->premiers[i][j] = 0;
ctx->premiers[_structure_][NUMBER] = 1;
ctx->premiers[_structure_][CONSTANT] = 1;
ctx->premiers[_structure_][STRING] = 1;
ctx->premiers[_structure_][CROCHET_OUVRANT] = 1;
ctx->premiers[_structure_][ACCOLADE_OUVRANTE] = 1;
ctx->premiers[_list_structure_][EPSILON] = 1;
ctx->premiers[_list_structure_][CONSTANT] = 1;
ctx->premiers[_list_structure_][STRING] = 1;
ctx->premiers[_list_structure_][NUMBER] = 1;
ctx->premiers[_list_structure_][ACCOLADE_OUVRANTE] = 1;
ctx->premiers[_list_structure_][CROCHET_OUVRANT] = 1;
ctx->premiers[_list_structure2_][EPSILON] = 1;
ctx->premiers[_list_structure2_][VIRGULE] = 1;
ctx->premiers[_list_attr_val_][EPSILON] = 1;
ctx->premiers[_list_attr_val_][STRING] = 1;
ctx->premiers[_list_attr_val2_][EPSILON] = 1;
ctx->premiers[_list_attr_val2_][VIRGULE] = 1;
ctx->premiers[_attr_val_][STRING] = 1;
}
/* ################################################################
Follow(structure) = '}' ']' '.' ','
Follow(list_structure) = ']'
Follow(list_structure2) = ']'
Follow(list_attr_val) = '}'
Follow(list_attr_val2) = '}'
Follow(attr_val) = '}' ','
################################################################*/
void initialise_suivants(json_parser_ctx *ctx){
int i,j;
for(i=0; i <= NB_NON_TERMINAUX; i++)
for(j=0; j <= NB_TERMINAUX; j++)
ctx->suivants[i][j] = 0;
ctx->suivants[_structure_][ACCOLADE_FERMANTE] = 1;
ctx->suivants[_structure_][CROCHET_FERMANT] = 1;
ctx->suivants[_structure_][VIRGULE] = 1;
ctx->suivants[_list_structure_][CROCHET_FERMANT] = 1;
ctx->suivants[_list_structure2_][CROCHET_FERMANT] = 1;
ctx->suivants[_list_attr_val_][ACCOLADE_FERMANTE] = 1;
ctx->suivants[_list_attr_val2_][ACCOLADE_FERMANTE] = 1;
ctx->suivants[_attr_val_][ACCOLADE_FERMANTE] = 1;
ctx->suivants[_attr_val_][VIRGULE] = 1;
}
json_struct *structure(json_parser_ctx *ctx);
json_struct *list (json_parser_ctx *ctx);
json_struct *list_structure(json_parser_ctx *ctx);
json_struct *list_structure2(json_parser_ctx *ctx);
json_attr_val *list_attr_val(json_parser_ctx *ctx);
json_attr_val *list_attr_val2(json_parser_ctx *ctx);
json_attr_val *attr_val(json_parser_ctx *ctx);
/*---------------------------------------------------------*/
/* structure -> '[' list_structure ']' | '{' list_attr_val '}' | STRING | NUMBER | CONSTANT */
/*---------------------------------------------------------*/
json_struct *structure(json_parser_ctx *ctx)
{
float num;
char *string;
int constant;
affiche_balise_ouvrante(ctx, __FUNCTION__);
if(ctx->uc == CROCHET_OUVRANT){
consommer(ctx, CROCHET_OUVRANT);
json_struct *s = list_structure(ctx);
consommer(ctx, CROCHET_FERMANT);
affiche_balise_fermante(ctx, __FUNCTION__);
return json_new_list(s);
}
if(ctx->uc == ACCOLADE_OUVRANTE){
consommer(ctx, ACCOLADE_OUVRANTE);
json_attr_val *l = list_attr_val(ctx);
consommer(ctx, ACCOLADE_FERMANTE);
affiche_balise_fermante(ctx, __FUNCTION__);
return json_new_avl(l);
}
if(ctx->uc == STRING){
string = (ctx->yyleng == 0)? NULL : strdup(ctx->yytext);
consommer(ctx, STRING);
affiche_balise_fermante(ctx, __FUNCTION__);
return json_new_string(string);
}
if(ctx->uc == NUMBER){
num = atof(ctx->yytext);
consommer(ctx, NUMBER);
affiche_balise_fermante(ctx, __FUNCTION__);
return json_new_number(num);
}
if(ctx->uc == CONSTANT){
if(!strcmp(ctx->yytext, "true")) constant = JSON_CONST_TRUE;
else if(!strcmp(ctx->yytext, "false")) constant = JSON_CONST_FALSE;
else if(!strcmp(ctx->yytext, "null")) constant = JSON_CONST_NULL;
else constant = -1;
consommer(ctx, CONSTANT);
affiche_balise_fermante(ctx, __FUNCTION__);
return json_new_constant(constant);
}
erreur(ctx, (char *) "" );
return NULL;
}
/*---------------------------------------------------------*/
/* list_structure -> structure list_structure2 | epsilon */
/*---------------------------------------------------------*/
json_struct *list_structure(json_parser_ctx *ctx)
{
affiche_balise_ouvrante(ctx, __FUNCTION__);
if(est_premier(ctx, ctx->uc, _structure_)) {
json_struct *head = structure(ctx);
json_struct *tail = list_structure2(ctx);
head->next = tail;
affiche_balise_fermante(ctx, __FUNCTION__);
return head;
}
if(est_suivant(ctx, ctx->uc, _list_structure_)) {
affiche_balise_fermante(ctx, __FUNCTION__);
return NULL;
}
erreur(ctx, (char *)"");
return NULL;
}
/*---------------------------------------------------------*/
/* list_structure2 -> ',' structure list_structure2 | epsilon */
/*---------------------------------------------------------*/
json_struct *list_structure2(json_parser_ctx *ctx)
{
affiche_balise_ouvrante(ctx, __FUNCTION__);
if(ctx->uc == VIRGULE){
consommer(ctx, VIRGULE);
json_struct *head = structure(ctx);
json_struct *tail = list_structure2(ctx);
head->next = tail;
affiche_balise_fermante(ctx, __FUNCTION__);
return head;
}
if(est_suivant(ctx, ctx->uc, _list_structure2_)) {
affiche_balise_fermante(ctx, __FUNCTION__);
return NULL;
}
erreur(ctx, (char *)"");
return NULL;
}
/*---------------------------------------------------------*/
/* list_attr_val -> attr_val list_attr_val2 | epsilon */
/*---------------------------------------------------------*/
json_attr_val *list_attr_val(json_parser_ctx *ctx)
{
affiche_balise_ouvrante(ctx, __FUNCTION__);
if(est_premier(ctx, ctx->uc, _attr_val_)){
json_attr_val *head = attr_val(ctx);
json_attr_val *tail = list_attr_val2(ctx);
head->next = tail;
affiche_balise_fermante(ctx, __FUNCTION__);
return head;
}
if(est_suivant(ctx, ctx->uc, _list_attr_val_)) {
affiche_balise_fermante(ctx, __FUNCTION__);
return NULL;
}
erreur(ctx, (char *)"");
return NULL;
}
/*---------------------------------------------------------*/
/* list_attr_val2 -> ',' attr_val list_attr_val2 | epsilon */
/*---------------------------------------------------------*/
json_attr_val *list_attr_val2(json_parser_ctx *ctx)
{
affiche_balise_ouvrante(ctx, __FUNCTION__);
if(ctx->uc == VIRGULE){
consommer(ctx, VIRGULE);
json_attr_val *head = attr_val(ctx);
json_attr_val *tail = list_attr_val2(ctx);
head->next = tail;
affiche_balise_fermante(ctx, __FUNCTION__);
return head;
}
if(est_suivant(ctx, ctx->uc, _list_attr_val2_)) {
affiche_balise_fermante(ctx, __FUNCTION__);
return NULL;
}
erreur(ctx, (char *)"");
return NULL;
}
/*---------------------------------------------------------*/
/* attr_val -> STRING ':' structure */
/*---------------------------------------------------------*/
json_attr_val *attr_val(json_parser_ctx *ctx)
{
char *attr;
affiche_balise_ouvrante(ctx, __FUNCTION__);
if(ctx->uc == STRING)
{attr = strdup(ctx->yytext);}
consommer(ctx, STRING);
consommer(ctx, COLON);
json_struct *val = structure(ctx);
affiche_balise_fermante(ctx, __FUNCTION__);
return json_new_attr_val(attr, val, NULL);
}
/*int main(int arc, char *argv[])
{
json_parser_ctx *ctx = json_parser_init(argv[1]);
json_struct *s = structure(ctx);
json_print_struct(stdout, s);
json_free_struct(s);
}*/