Как анализатор Lex & Yacc выводит значения? - PullRequest
0 голосов
/ 23 февраля 2012

Итак, для проекта, над которым я работаю, я использую Lex и Yacc для анализа файла конфигурации FTP.Файлы конфигурации выглядят примерно так:

global {
    num_daemons = 10
    etc = /etc/ftpd
};

host "ftp-1.foobar.com" {
    ftproot = /var/ftp/server1
    max_out_bandwidth = 20.7
};

host "ftp-2.foobar.com" {
    ftproot = /var/ftp/server2
    exclude = /var/ftp/server2/private
};

host "ftp-3.foobar.com" {
    ftproot = /var/ftp/server3
};

Теперь мой вопрос: как мне получить эту информацию удобным для использования способом?Допустим, я хотел поместить в структуру такие элементы, как адрес после токена хоста.Как бы я это сделал?Кроме того, как мне просто распечатать значения, которые я проанализировал в командной строке?Кроме того, чтобы запустить его, я просто катать файл конфигурации и канал в скомпилированной программе c?Заранее спасибо за любую помощь!

Вот мой код:

%{
// tokens.l
#include <stdio.h>
#include <stdlib.h>
#include "y.tab.h"

int yyparse();

%}

%option noyywrap

%x OPTION
%x OPTID

%%

<INITIAL>global             { return GLOBAL; }
<INITIAL>host               { return HOST; }
<INITIAL>"[a-zA-z1-9./-]+"  { return NAME; }
<INITIAL>\{                 { return CURLY_OPEN; BEGIN OPTION; }
<INITIAL>\n                 { return EOLN; }
<INITIAL><<EOF>>            { return EOFTOK; }


<OPTION>[a-zA-z1-9./-_]+    { return ID_NAME; BEGIN OPTID; }
<OPTION>[\t]                {}
<OPTION>[\};]               { return OPTION_CLOSE; BEGIN INITIAL;}

<OPTID>[a-zA-z1-9./-]+      { return ID_STRING; BEGIN OPTION; }
<OPTID>[0-9.]+              { return ID_NUM; BEGIN OPTION; }
<OPTID>[\n]                 { return EOLN; }

%%

int main(int argc, char **argv) {
    // Where I am confused..
}

и мой файл yacc:

%{
// parse.y
#include <stdio.h>
#include <stdlib.h>

int yyerror(char *);
int yylex(void);

%}

%token ERROR EOLN EOFTOK
%token OPTION_CLOSE GLOBAL HOST NAME ID_NAME ID_STRING ID_NUM CURLY_OPEN

%%

input
    : lines EOFTOK  { YYACCEPT; }
    ;
lines
    :
    | lines line
    ;
line
    : option
    | opident
    | OPTION_CLOSE
    ;
option
    : GLOBAL CURLY_OPEN
    | HOST NAME CURLY_OPEN
    ;
opident
    : ID_NAME '=' ID_STRING
    | ID_NAME '=' ID_NUM
    ;
%%

int yyerror(char *msg) {}

1 Ответ

1 голос
/ 23 февраля 2012

Обычно у вас есть переменные, которые были доступны и настроены перед вызовом парсера, например, связанный список пар ключ / значение:

typedef struct sNode {
    char *key;
    char *val;
    struct sNode *next;
} tNode;
tNode *lookupHead = NULL;

Затем в вашем коде Yacc что-то вроде:

opident
    : ID_NAME '=' ID_STRING { addLookupStr (lookupHead, $1, $3); }
    | ID_NAME '=' ID_NUM    { other function call here }
    ;

Это в основном выполняло бы этот код при обнаружении правил (замена переменных $ на элемент в правиле, $1 - это значение для ID_NAME токена, $2 - это= и т. Д.).

Функция будет выглядеть примерно так:

void addLookupStr (char *newkey, char *newval) {
    // Check for duplicate keys, then attempt to add. All premature returns
    // should also be logging errors and setting error flags as needed.

    tNode *curr = lookupHead;
    while (curr != NULL) {
        if (strcmp (curr->key, newkey) == 0)
            return;
        curr = curr->next;
    }

    if ((curr = malloc (sizeof (tNode))) == NULL)
        return;

    if ((curr->key = strdup (newkey)) == NULL) {
        free (curr);
        return;
    }

    if ((curr->val = strdup (newval)) == NULL) {
        free (curr->newkey);
        free (curr);
        return;
    }

    // All possibly-failing ops complete, insert at head of list.

    curr->next = lookupHead;
    lookupHead = curr;
}
...