+1  A: 

For me this kind of problem would be just past the use-a-real-parsing-tool threshold. Here's a quick working example with Attoparsec:

import Control.Applicative
import Data.Attoparsec (maybeResult)
import Data.Attoparsec.Char8
import qualified Data.Attoparsec.Char8 as A (takeWhile)
import qualified Data.ByteString.Char8 as B
import Data.Maybe (fromMaybe)

data Entry = Entry String [String] [[String]] deriving (Show)

entry = Entry <$> table <*> cols <*> many1 vals
items = sepBy1 (A.takeWhile $ notInClass " \n") $ char ' '
table = string (B.pack "TABLE ") *> many1 (notChar '\n') <* endOfLine
cols = string (B.pack "COLUMNS ") *> (map B.unpack <$> items) <* endOfLine
vals = string (B.pack "VALUES ")  *> (map B.unpack <$> items) <* endOfLine

parseEntries :: B.ByteString -> Maybe [Entry]
parseEntries = maybeResult . flip feed B.empty . parse (sepBy1 entry skipSpace)

And a bit of machinery:

pretty :: Entry -> String
pretty (Entry t cs vs)
  = unwords $ ["TABLE", t, "COLUMNS"]
  ++ cs ++ concatMap ("VALUES" :) vs

layout :: B.ByteString -> Maybe String
layout = (unlines . map pretty <$>) . parseEntries

testLayout :: FilePath -> IO ()
testLayout f = putStr . fromMaybe [] =<< layout <$> B.readFile f

And given this input:

TABLE test
COLUMNS a b c
VALUES 1 2 3
VALUES 4 5 6

TABLE another
COLUMNS x y z q
VALUES 7 8 9 10
VALUES 1 2 3 4

We get the following:

*Main> testLayout "test.dat" 
TABLE test COLUMNS a b c VALUES 1 2 3 VALUES 4 5 6
TABLE another COLUMNS x y z q VALUES 7 8 9 10 VALUES 1 2 3 4

Which seems to be what you want?

Travis Brown
Which is exactly what I want! =) I was hoping to create this parser myself, but I realize it might take some more work than fiddling around with my elementary level. ^^
monkey C
A: 

This answer is literate Haskell, so you can copy-and-paste it into a file named table.lhs to get a working program.

Beginning with a few imports

> import Control.Arrow ((&&&))
> import Control.Monad (forM_)
> import Data.List (intercalate,isPrefixOf)
> import Data.Maybe (fromJust)

and say we represent a table with the following record:

> data Table = Table { tblName :: String
>                    , tblCols :: [String]
>                    , tblVals :: [String]
>                    }
>   deriving (Show)

That is, we record the table's name, the list of column names, and the list of column values.

Each table in the input starts on a line beginning with TABLE, so separate all lines in the input into chunks accordingly:

> tables :: [String] -> [Table]
> tables [] = []
> tables xs = next : tables ys
>   where next = mkTable (th:tt)
>         (th:rest) = dropWhile (not . isTable) xs
>         (tt,ys) = break isTable rest
>         isTable = ("TABLE" `isPrefixOf`)

Having chunked the input into tables, the name of a given table is the first word on the TABLE line. The column names are all words that appear on COLUMNS lines, and column values come from VALUES lines:

> mkTable :: [String] -> Table
> mkTable xs = Table name cols vals
>   where name = head $ fromJust $ lookup "TABLE" tagged
>         cols = grab "COLUMNS"
>         vals = grab "VALUES"
>         grab t = concatMap snd $ filter ((== t) . fst) tagged
>         tagged = map ((head &&& tail) . words)
>                $ filter (not . null) xs

Given a Table record, we print it by pasting the names, values, and SQL keywords together in the appropriate order on a single line:

> main :: IO ()
> main = do
>   input <- readFile "input"
>   forM_ (tables $ lines input) $
>     \t -> do putStrLn $ intercalate " " $
>                 "TABLE"   : (tblName t)  :
>                ("COLUMNS" : (tblCols t)) ++
>                ("VALUES"  : (tblVals t))

Given the unimaginative input of

TABLE name_of_table

COLUMNS first_column 2nd_column [..] n-th_column

VALUES 1st_value 2nd_value [...] n-th value

VALUES yet_another_value ... go on

TABLE name_of_table

COLUMNS first_column 2nd_column [..] n-th_column

VALUES 1st_value 2nd_value [...] n-th value

VALUES yet_another_value ... go on

the output is

$ runhaskell table.lhs
TABLE name_of_table COLUMNS first_column 2nd_column [..] n-th_column VALUES 1st_value 2nd_value [...] n-th value yet_another_value ... go on
TABLE name_of_table COLUMNS first_column 2nd_column [..] n-th_column VALUES 1st_value 2nd_value [...] n-th value yet_another_value ... go on
Greg Bacon