Question

I think I have researched very hard about my problem so here I am.

I have a "end of file unexpected" error at line 6 colunm 33.

I have already tried many solutions to resolve my problem.

Here is my code and the file I am trying to parse.

Here is the text I am trying to parse :

ifc.txt :

#9512= IFCBUILDINGSTOREY('3y21AUC9X4yAqzLGUny16E',#16,'Story',$,$,#9509,$,$,.ELEMENT.,6200.);
#9509= IFCLOCALPLACEMENT(#115,#9506);
#9506= IFCAXIS2PLACEMENT3D(#9502,#9498,#9494);
#9502= IFCCARTESIANPOINT((0.,0.,6200.));
#9498= IFCDIRECTION((0.,0.,1.));
#9494= IFCDIRECTION((1.,0.,0.));

Here is the code :

code.hs :

import Text.ParserCombinators.Parsec
main = do
  f <- readFile "ifc.txt"
  let m = (parse ifc "" f)
  print m

ifc :: Parser IfcModel
ifc = many ifcentry

ifcentry = do
  string "#"
  i <- idt
  string "= "
  name <- idt
  string "("
  prop <- idt
  string ")"
  string ";"
  string "\n"
  return (i,name,prop)

idt = many (letter <|> digit <|> char ','
   <|> char '$' <|> char ')' <|> char '\''
   <|> char '=' <|> char ';'  <|> char '\n'
   <|> char ' ' <|> char '(' <|> char '#'
   <|> char '.' <|> char '\r')

Thanks for your help, i should have checked a bit earlier my anwser because i worked on my own and i found asolution i will post it when i can (8hours left for a newbie like me who has less than 10 in reputation).

Thanks again.

Was it helpful?

Solution 3

Thanks for your help everyone, i should have checked a bit earlier my anwser because i worked on my own and finally found a solution :

import Text.ParserCombinators.Parsec

main = do
 f <- readFile "ifc.txt"
 let m = (parse ifc "" f)
 print m

type IfcIdt = String
type IfcName = String
type IfcProp = [String]
type IfcModel = [(IfcIdt,IfcName,IfcProp)]

ifc :: Parser IfcModel
ifc = many ifcentry

ifcentry = do
 string "#"
 i <- idtnumber
 string "= "
 name <- idtname
 opening
 prop <- ifcprop
 closing
 eol
 return (i,name,prop)

idtnumber = many digit
idtname = many (letter <|> digit)

ifcprop = sepBy prop (char ',')
prop = many (noneOf "=,();\n")
eol = string ";\n"
opening = try (string "((")
 <|> string "("
closing = try (string "))")
 <|> string ")"

OTHER TIPS

Solution: use sepBy instead of including the newline in ifcentry

Your ifcentry expects a newline at the end, and your input doesn't have one, which is why the EOF was unexpected.

Drop the string "\n" from ifcentry and instead define

ifc :: Parser IfcModel
ifc = ifcentry `sepBy` (char '\n')

Also, your idt parser is needlessly long. It would be clearer as

idt = many (letter <|> digit <|> oneOf ".,;' =#$()\n\r")

Clearer ifcentry

And while I'm at it, I'd write

ifcentry = do
  char '#'
  i <- idt
  string "= "
  name <- idt
  prop <- parens idt
  char ';'
  return (i,name,prop)

Because parens (which parses an open bracket, your idt content, then a close bracket) tidies it up and makes it clearer.

Less verbose main

I'd also write

main = fmap (parse ifc "") (readFile "ifc.txt") >>= print

certainly there's no need for

  let m = (parse ifc "" f)
  print m

because you may as well do

  print (parse ifc "" f)

In addtion to @enough rep to comment's answer

I would go much further and declare something in the line of

data IFCType = IFCBuildingStorey ....
             | IFCLocalPlacement ....
             | IFCAxis2Placement3D ....
             | IFCCartesianpoint Double Double Double
             | IFCDirection ....
             deriving Show

and

type ID = Integer
type IFCElement = (ID,IFCType)

where i will show the CartesianPoint as an example

ifctype :: Parser IFCType
ifctype = do string "IFC"
             buildingStorey
             <|> localPlacement
             <|> axis2Placement3D
             <|> cartesianpoint
             <|> direction

buildingStorey :: Parser IFCType
buildingStorey = do string "BUILDINGSTOREY"
                    return IFCBuildingStorey

localPlacement :: Parser IFCType
localPlacement = do string "LOCALPLACEMENT"
                    return IFCLocalPlacement

axis2Placement3D :: Parser IFCType
axis2Placement3D = do string "AXIS2PLACEMENT3D"
                      return IFCAxis2Placement3D

cartesianpoint :: Parser IFCType
cartesianpoint = do string "CARTESIANPOINT"
                    char '('
                    char '('
                    x <- double
                    char ','
                    y <- double
                    char ','
                    z <- double
                    char ')'
                    char ')'
                    return $ IFCCartesianpoint x y z

double :: Parser Double
double = do d <- many1 (digit <|> char '.')
            return $ read d

direction :: Parser IFCType
direction = do string "DIRECTION"
               return IFCDirection

this has the additional advantage that you have typed models.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top