[Haskell-beginners] Clearing Parsec error messages

Daniel Fischer daniel.is.fischer at web.de
Sat Jun 6 11:11:41 EDT 2009


Am Samstag 06 Juni 2009 14:26:14 schrieb Giuliano Vilela:
> On Sat, Jun 6, 2009 at 8:36 AM, Daniel Fischer <daniel.is.fischer at web.de>wrote:
> > Am Samstag 06 Juni 2009 02:05:13 schrieb Giuliano Vilela:
>
> Close, but not quite. I'm actually using the Parsec monad with my own state
> to build a symbol table during parsing (for a Pascal sub-language I
> mentioned earlier in this list). So the fail is deep in the "recursion
> chain", but it's something like what you mentioned above. It seemed to me
> that *fail* was the best way to report a error, like "undefined type
> identifier used".

Ah, I see.
You successfully parsed a list of syntactically correct declarations, then check if 
they're semantically correct (using only known types, in this case) and if that fails, you 
really don't want to know under which circumstances you could have parsed more 
declarations :)

>
> But thinking about it now, I see my solution probably isn't optimal. In
> some cases, I will report type errors even when there is bad syntax further
> in the source, which is not common behavior. You got any suggestions for my
> use case?

If you don't want a "die on first error" strategy, add a "list of encountered errors" 
component to your user state and log all encountered errors.

data ParsingState = PS
    { symTbl :: SymbolTable
    , typeTbl :: TypeTable
    , errs :: [SyntaxError]
    }

data SyntaxError
    = UnknownType SourcePos String
    | UnknownOperator SourcePos String
    | MissingSemicolon SourcePos
    | ...

parseType = do
    typeId <- Tk.identifier
    tTable <- typeT
    case mlookup typeId tTable of
      Nothing -> return (BadType typeId)
      Just typeV -> return (GoodType typeId typeV)

varDeclaration = do
    varIdL <- Tk.commaSep1 Tk.identifier
    Tk.symbol ":"
    pos <- getPosition
    tp <- parseType
    case tp of
      BadType typeName -> do 
            logError (UnknownType pos typeName)
            return (VarDecl varIdL typeName)
      GoodType typeName typeV -> do
            forM_ varIdL (\vi -> insert vi into symbol table)
            return (VarDecl varIdL typeName)

When inserting variables into the symbol table, you should check whether it's already 
there, you don't want to parse

var
x, y : integer;
z, x : boolean;

without error.

I don't know what you will finally want to parse, but you should think about local 
variables with the same name as one in an enclosing scope early.

Finally,

realProgram = do
    prog <- program
    errs <- errorList
    if null errs
      then return prog
      else failWithErrors errs


>
> The source code for the interpreter is here:
> http://code.google.com/p/hpascal/ (pretty immature, my group just started
> writing it) if you want to take a look. Important files are: Parsing.hs
> (the parser itself) and TypeChecker.hs (parsers that access the internal
> monad state and build the table).

Hope that helps,
Daniel



More information about the Beginners mailing list