In buona sostanza flex viene usato per l'analisi lessicale e si usa spesso insieme a bison che effettua l'analisi sintattica.

Quello che segue è un esempio di un piccolo interprete per un piccolo linguaggio di programmazione:

symtab.h:
codice:
#ifndef SYMTAB_H
#define SYMTAB_H

#define HT_SIZE 251
#define SCOPE_SIZE 4096

typedef enum
{
    T_INTEGER,
    T_REAL,
    T_STRING,
    T_BOOLEAN
} enumTipo1;

typedef enum
{
    T_CONST,
    T_VAR
} enumTipo2;

typedef union
{
    int iVal;
    double dblVal;
    char *strVal;
    enum {FALSE, TRUE} bVal;
} Valore;

typedef struct tagHashTable
{
    char *Key;
    enumTipo1 Tipo1;
    enumTipo2 Tipo2;
    Valore Value;
    char bInizializzato;
    struct tagHashTable *next;
} HashTable;

typedef struct tagScope
{
    int top;
    HashTable **stack[SCOPE_SIZE];
} Scope;

HashTable* htNewNode(char *Key, enumTipo1 t1, enumTipo2 t2, Valore v, char bInizializzato);
int htFind(HashTable **pHashTable, char *Key, HashTable *pDati);
void htInsert(HashTable **pHashTable, char *Key, enumTipo1 t1, enumTipo2 t2, Valore v, char bInizializzato);
void htFree(HashTable* first);

void scopeInit(Scope *pScope);
void scopePush(Scope *pScope);
int  scopePop(Scope *pScope);
void scopeFree(Scope *pScope);
int  scopeFind(Scope* pScope, char *Key, HashTable *pDati);
int  scopeInsert(Scope *pScope, char *Key, enumTipo1 t1, enumTipo2 t2, Valore v, char bInizializzato);
int scopeUpdateValue(Scope *pScope, char *Key, enumTipo1 t1, enumTipo2 t2, Valore v, char bInizializzato);


#endif // SYMTAB_H
symtab.c:
codice:
#include <stdio.h>
#include <string.h>
#include <malloc.h>

#include "symtab.h"

HashTable* htNewNode(char *Key, enumTipo1 t1, enumTipo2 t2, Valore v, char bInizializzato)
{
    HashTable *n;

    n = (HashTable*)malloc(sizeof(HashTable));

    if( n == NULL )
        return NULL;

    n->Key = (char*)malloc(strlen(Key)+1);
    if ( n->Key == NULL )
    {
        free(n);
        return NULL;
    }
    strcpy(n->Key, Key);
    n->Tipo1 = t1;
    n->Tipo2 = t2;
    n->Value = v;
    n->bInizializzato = bInizializzato;
    n->next = NULL;

    if ( !bInizializzato )
    {
        switch(t1)
        {
        case T_INTEGER:
            n->Value.iVal = 0;
            break;
        case T_REAL:
            n->Value.dblVal = 0.0;
            break;
        case T_STRING:
            //n->Value.strVal = NULL;
            n->Value.strVal = (char*)malloc(sizeof(char)*1);
            strcpy(n->Value.strVal, "");
            break;
        case T_BOOLEAN:
            n->Value.bVal = FALSE;
            break;
        }
    }

    return n;
}

int htFind(HashTable **pHashTable, char *Key, HashTable *pDati)
{
    int index = 0;
    HashTable *t;
    int a = 31415;
    int b = 27183;
    char *s = Key;

    for(; *s != '\0'; s++)
        index = (a*index + *s) % HT_SIZE;
    if ( index < 0 )
        index *= -1;

    t = pHashTable[index];
    while ( t != NULL )
    {
        if ( strcmp(t->Key, Key) == 0 )
        {
            pDati->Key = t->Key;
            pDati->Tipo1 = t->Tipo1;
            pDati->Tipo2 = t->Tipo2;
            pDati->Value = t->Value;
            pDati->bInizializzato = t->bInizializzato;
            return index;
        }
        t = t->next;
    }

    return -1;
}

void htInsert(HashTable **pHashTable, char *Key, enumTipo1 t1, enumTipo2 t2, Valore v, char bInizializzato)
{
    int index = 0;
    HashTable *t = NULL;
    int a = 31415;
    int b = 27183;
    char *s = Key;

    for(; *s != '\0'; s++)
        index = (a*index + *s) % HT_SIZE;
    if ( index < 0 )
        index *= -1;

    t = pHashTable[index];
    if ( t == NULL )
    {
        pHashTable[index] = htNewNode(Key, t1, t2, v, bInizializzato);
        return;
    }

    while ( t != NULL )
    {
        if ( strcmp(t->Key, Key) == 0 )
        {
            //pHashTable[index]->pLista = ListAppend(pHashTable[index]->pLista, pos);
            printf("\nErrore: La chiave %s e' gia' presente nella hashtable\n", Key);
            return;
        }
        if ( t->next == NULL )
        {
            t->next = htNewNode(Key, t1, t2, v, bInizializzato);
            //t = t->next;
            //t->next = NULL;
            return;
        }
        t = t->next;
    }
}

void htFree(HashTable* first)
{
    HashTable *n1 = first, *n2;
    while ( n1 != NULL )
    {
        n2 = n1->next;
        if ( n1->Key )
            free(n1->Key);
        if ( n1->Tipo1 == T_STRING )
        {
            if ( n1->Value.strVal )
                free(n1->Value.strVal);
        }
        free(n1);
        n1 = n2;
    }
}

void scopeInit(Scope *pScope)
{
    HashTable **pHT;
    int x;

    pScope->top = 0;

    pHT = (HashTable**)malloc(sizeof(HashTable*) * HT_SIZE);
    if ( pHT != NULL )
    {
        for ( x = 0; x < HT_SIZE; x++ )
        {
            pHT[x] = (HashTable*)malloc(sizeof(HashTable));
            if ( pHT[x] == NULL )
            {
                printf("Memoria non sufficiente.\n");
                return;
            }
            pHT[x] = NULL;
        }
    }
    else
    {
        printf("Memoria non sufficiente.\n");
        return;
    }

    pScope->stack[pScope->top] = pHT;

    for ( x = 1; x < SCOPE_SIZE; x++ )
        pScope->stack[x] = NULL;
}

void scopePush(Scope *pScope)
{
    HashTable **pHT;
    int x;

    pScope->top++;
    if ( pScope->top > SCOPE_SIZE - 1 )
    {
        printf("Stack scope pieno!\n");
        pScope->top = SCOPE_SIZE - 1;
        return;
    }

    pHT = (HashTable**)malloc(sizeof(HashTable*) * HT_SIZE);
    if ( pHT != NULL )
    {
        for ( x = 0; x < HT_SIZE; x++ )
        {
            pHT[x] = (HashTable*)malloc(sizeof(HashTable));
            if ( pHT[x] == NULL )
            {
                printf("Memoria non sufficiente.\n");
                return;
            }
            pHT[x] = NULL;
        }
    }
    else
    {
        printf("Memoria non sufficiente.\n");
        return;
    }

    pScope->stack[pScope->top] = pHT;
}

int scopePop(Scope *pScope)
{
    HashTable **pHT;
    int x;

    if ( pScope->top < 0 )
        return pScope->top;

    pHT = pScope->stack[pScope->top];
    for ( x = 0; x < HT_SIZE; x++)
        htFree(pHT[x]);
    free(pHT);
    pScope->stack[pScope->top] = NULL;
    pScope->top--;

    return pScope->top;
}

void scopeFree(Scope *pScope)
{
    while ( scopePop(pScope) >= 0 )
        ;
}

int scopeFind(Scope* pScope, char *Key, HashTable *pDati)
{
    HashTable **pHT;
    int x;

    for ( x = pScope->top; x >= 0; x-- )
    {
        pHT = pScope->stack[x];
        if ( htFind(pHT, Key, pDati) >= 0 )
        {
            return 1;
        }
    }

    return 0;
}

int scopeInsert(Scope *pScope, char *Key, enumTipo1 t1, enumTipo2 t2, Valore v, char bInizializzato)
{
    HashTable **pHT;
    HashTable Dati;

    pHT = pScope->stack[pScope->top];

    if ( htFind(pHT, Key, &Dati) >= 0 )
    {
        printf("Errore: la variabile '%s' e' gia' stata dichiarata nello scope %d\n", Key, pScope->top);
        return 0;
    }

    htInsert(pHT, Key, t1, t2, v, bInizializzato);

    return 1;
}

int scopeUpdateValue(Scope *pScope, char *Key, enumTipo1 t1, enumTipo2 t2, Valore v, char bInizializzato)
{
    HashTable **pHT;
    HashTable Dati;
    int x;
    int index;

    for ( x = pScope->top; x >= 0; x-- )
    {
        pHT = pScope->stack[x];

        index = htFind(pHT, Key, &Dati);
        if ( index >= 0 )
        {
            HashTable *pTable = pHT[index];
            while ( strcmp(pTable->Key, Key) != 0 )
                pTable = pTable->next;
            pTable->Value = v;
            pTable->bInizializzato = bInizializzato;
            return 1;
        }
    }

    printf("Errore: variabile '%s' non dichiarata\n", Key);
    return 0;
}
ast.h:
codice:
#ifndef AST_H
#define AST_H

#include "symtab.h"

typedef enum { typeCon, typeId, typeOpr } nodeEnum;

/* Costanti */
typedef struct
{
    Valore value;
} conNodeType;

/* identificatori */
typedef struct
{
    char *name;
    char *uniqueName;
    Valore value;
    char bInizializzato;
} idNodeType;

/* operatori */
typedef struct
{
    int oper;                   /* operatori */
    int nops;                   /* numero di operandi */
    struct nodeTypeTag *op[1];  /* operandi */
} oprNodeType;

typedef struct nodeTypeTag
{
    nodeEnum type;             
    enumTipo1 type1;
    enumTipo2 type2;

    union
    {
        conNodeType con;        /* costanti */
        idNodeType id;          /* identificatori */
        oprNodeType opr;        /* operatori */
    };
} nodeType;

nodeType *opr(int oper, int nops, ...);
nodeType *id(char *name, char *uniqueName, enumTipo1 t1, enumTipo2 t2, Valore value, char bInizializzato);
nodeType *con(enumTipo1 t1, Valore value);
void freeNode(nodeType *p);

#endif // AST_H
ast.c:
codice:
#include <stdio.h> 
#include <stdlib.h> 
#include <stdarg.h> 
#include <string.h> 
#include "ast.h" 
 
#define SIZEOF_NODETYPE ((char *)&p->con - (char *)p) 
 
extern void yyerror(char *s); 
 
nodeType *con(enumTipo1 t1, Valore value) 
{ 
    nodeType *p = NULL; 
    size_t nodeSize; 
 
    nodeSize = SIZEOF_NODETYPE + sizeof(conNodeType); 
    if ((p = malloc(nodeSize)) == NULL) 
        yyerror("out of memory"); 
 
    p->type = typeCon; 
    p->type1 = t1; 
    p->type2 = T_CONST; 
    p->con.value = value; 
 
    return p; 
} 
 
nodeType *id(char *name, char *uniqueName, enumTipo1 t1, enumTipo2 t2, Valore value, char bInizializzato) 
{ 
    nodeType *p = NULL; 
    size_t nodeSize; 
 
    nodeSize = SIZEOF_NODETYPE + sizeof(idNodeType); 
    if ((p = malloc(nodeSize)) == NULL) 
        yyerror("out of memory"); 
 
    p->type = typeId; 
    p->type1 = t1; 
    p->type2 = t2; 
    p->id.name = (char*)malloc(sizeof(char)*strlen(name)+1); 
    strcpy(p->id.name, name); 
    p->id.uniqueName = (char*)malloc(sizeof(char)*strlen(uniqueName)+1); 
    strcpy(p->id.uniqueName, uniqueName); 
    p->id.value = value; 
    p->id.bInizializzato = bInizializzato; 
 
    return p; 
} 
 
nodeType *opr(int oper, int nops, ...) 
{ 
    va_list ap; 
    nodeType *p = NULL; 
    size_t nodeSize; 
    int i; 
 
    nodeSize = SIZEOF_NODETYPE + sizeof(oprNodeType) + 
        (nops - 1) * sizeof(nodeType*); 
    if ((p = malloc(nodeSize)) == NULL) 
        yyerror("out of memory"); 
 
    p->type = typeOpr; 
    p->opr.oper = oper; 
    p->opr.nops = nops; 
    va_start(ap, nops); 
    for (i = 0; i < nops; i++) 
        p->opr.op[i] = va_arg(ap, nodeType*); 
    va_end(ap); 
    return p; 
} 
 
void freeNode(nodeType *p) { 
    int i; 
 
    if (!p) return; 
    if (p->type == typeOpr) { 
        for (i = 0; i < p->opr.nops; i++) 
            freeNode(p->opr.op[i]); 
    } 
    free (p); 
}