It would be better if I also remembered to add the files.
So here we go again.
I also added the generated .erl file for those that do not want to
install abnfc.

/Anders

On Thu, Oct 6, 2011 at 12:41 PM, Anders Nygren <[email protected]> wrote:
> Hi
> Just for fun I made a RFC4180 parser using the ABNF in the RFC.
>
> Compile rfc4180.abnf using abnfc
>
> abnfc -binary rfc4180.abnf
>
> And You get a working csv parser.
> There are some things in the textual description in the RFC that is
> not reflected
> in the abnf, e.g. if the file has a header row or not, and the
> generated parser does not
> check that all rows has the same number of fields.
>
> /Anders
>
> On Wed, Oct 5, 2011 at 12:15 PM, Anders Nygren <[email protected]> 
> wrote:
>> On Wed, Oct 5, 2011 at 12:09 PM, Eric Merritt <[email protected]> wrote:
>>> On 10/05/11 at 11:48am, Anders Nygren wrote:
>>>> Eric
>>>> In case You are not already aware of it, I would like to point You to
>>>> my ABNF parser
>>>> generator, abnfc, (most RFCs are specified using ABNF)
>>>
>>> I wasn't aware of it at all. Thats good to know. I probably will not
>>> go back and rewrite the existing stuff. However, I will absolutely
>>> keep it in mind for the future.
>>>
>>>> https://github.com/nygge/abnfc
>>>>
>>>> The documentation is nonexistent, but it was presented at EUC 2008
>>>>
>>>> http://www.erlang.org/euc/08/1500Nygren2.pdf
>>>>
>>>> There has been some changes after that, so contact me if You have any
>>>> questions/problems.
>>>>
>>>> In general I am not sure it is a good idea to put all RFC parsers in one 
>>>> erlang
>>>> application. Since after a while You may get a large number of unrelated
>>>> stuff.
>>>
>>> I am always on the fence about this. I am not a big fan of 1 erlang
>>> file OTP apps, though there is nothing intrinsically wrong with
>>> that. I try to group modules in some reasonable way. In this case, I
>>> think that the fact that this is a library application (ie static)
>>> implies that there is no system overhead in having all the RFCs
>>> there. Though as you say there maybe some conceptual overhead.
>>>
>>
>> Thinking a little more about this, it is not so bad, since with reltool
>> it is fairly simple to specify which modules to include from an application
>> when creating a release.
>>
>> /Anders
>>
>>>
>>>> But on the other hand many RFCs imports parts of other RFCs so I do
>>>> not have any good ideas on how to structure it.
>>>
>>> Right now its just going be structured by name. for example each RFC
>>> implementation will be named erfc_<rfc number>.erl. For example, 8120
>>> would be named erfc_8120.erl. etc.
>>>
>>>>
>>>> Maybe the best is just to make a big bag of parsers and let people pick 
>>>> the ones
>>>> they need.
>>>
>>> That is exactly the current plan. :)
>>>
>>> Thanks Anders, your input is always rock solid.
>>>>
>>>> /Anders
>>>>
>>>> On Wed, Oct 5, 2011 at 10:48 AM, Eric Merritt <[email protected]> 
>>>> wrote:
>>>> > Hello All,
>>>> >
>>>> > I have started an RFC parsing library in support of my latest
>>>> > endeavor. This seems like a target to put under erlware. I thought I
>>>> > would float the idea to the list.
>>>> >
>>>> > https://github.com/ericbmerritt/erfc_parsers
>>>> >
>>>> > I dont have a specific goal of implementing all RFCs but as I need
>>>> > them (RFC 821 should show up shortly) I will add them.
>>>> >
>>>> > What does everone think of putting them under erlware?
>>>> >
>>>> > Eric
>>>> >
>>>> > --
>>>> > You received this message because you are subscribed to the Google 
>>>> > Groups "erlware-dev" group.
>>>> > To post to this group, send email to [email protected].
>>>> > To unsubscribe from this group, send email to 
>>>> > [email protected].
>>>> > For more options, visit this group at 
>>>> > http://groups.google.com/group/erlware-dev?hl=en.
>>>> >
>>>> >
>>>>
>>>> --
>>>> You received this message because you are subscribed to the Google Groups 
>>>> "erlware-dev" group.
>>>> To post to this group, send email to [email protected].
>>>> To unsubscribe from this group, send email to 
>>>> [email protected].
>>>> For more options, visit this group at 
>>>> http://groups.google.com/group/erlware-dev?hl=en.
>>>>
>>>
>>> --
>>> You received this message because you are subscribed to the Google Groups 
>>> "erlware-dev" group.
>>> To post to this group, send email to [email protected].
>>> To unsubscribe from this group, send email to 
>>> [email protected].
>>> For more options, visit this group at 
>>> http://groups.google.com/group/erlware-dev?hl=en.
>>>
>>>
>>
>

-- 
You received this message because you are subscribed to the Google Groups 
"erlware-dev" group.
To post to this group, send email to [email protected].
To unsubscribe from this group, send email to 
[email protected].
For more options, visit this group at 
http://groups.google.com/group/erlware-dev?hl=en.

Attachment: rfc4180.abnf
Description: Binary data

Attachment: rfc4180.hrl
Description: Binary data

%%% Do not modify this file, it is automatically generated by abnfc.
%%% All changes will be lost when it is regenerated.
%%% Generated by abnfc_gen on 2011-10-06 12:36:08

-module(rfc4180).

-export(['COMMA'/0, 'CR'/0, 'CRLF'/0, 'DDQUOTE'/0,
	 'DQUOTE'/0, 'LF'/0, 'TEXTDATA'/0, decode/2, escaped/0,
	 field/0, file/0, header/0, name/0, 'non-escaped'/0,
	 record/0]).

-include("rfc4180.hrl").

decode(file, Str) -> (file())(Str);
decode(header, Str) -> (header())(Str);
decode(record, Str) -> (record())(Str);
decode(name, Str) -> (name())(Str);
decode(field, Str) -> (field())(Str);
decode(escaped, Str) -> (escaped())(Str);
decode('non-escaped', Str) -> ('non-escaped'())(Str);
decode('COMMA', Str) -> ('COMMA'())(Str);
decode('CR', Str) -> ('CR'())(Str);
decode('DDQUOTE', Str) -> ('DDQUOTE'())(Str);
decode('DQUOTE', Str) -> ('DQUOTE'())(Str);
decode('LF', Str) -> ('LF'())(Str);
decode('CRLF', Str) -> ('CRLF'())(Str);
decode('TEXTDATA', Str) -> ('TEXTDATA'())(Str).

file() ->
    fun (T) ->
	    __P = '__seq'(['__repeat'(0, 1,
				      '__seq'([header(), 'CRLF'()])),
			   record(),
			   '__repeat'(0, infinity, '__seq'(['CRLF'(), record()])),
			   '__repeat'(0, 1, 'CRLF'())]),
	    case __P(T) of
	      {ok, [_YY1, _YY2, _YY3, _YY4] = _YY, _T1} ->
		  try #file{header = hd(hd(_YY1)),
			    records = [_YY2 | [Rec || [_, Rec] <- _YY3]]}
		  of
		    __Ret -> {ok, __Ret, _T1}
		  catch
		    fail -> fail
		  end;
	      fail -> fail
	    end
    end.

header() ->
    fun (T) ->
	    __P = '__seq'([name(),
			   '__repeat'(0, infinity, '__seq'(['COMMA'(), name()]))]),
	    case __P(T) of
	      {ok, [_YY1, _YY2] = _YY, _T1} ->
		  try #header{names =
				  [_YY1 | [Name || [_, Name] <- _YY2]]}
		  of
		    __Ret -> {ok, __Ret, _T1}
		  catch
		    fail -> fail
		  end;
	      fail -> fail
	    end
    end.

record() ->
    fun (T) ->
	    __P = '__seq'([field(),
			   '__repeat'(0, infinity,
				      '__seq'(['COMMA'(), field()]))]),
	    case __P(T) of
	      {ok, [_YY1, _YY2] = _YY, _T1} ->
		  try #record{fields =
				  [_YY1 | [Value || [_, Value] <- _YY2]]}
		  of
		    __Ret -> {ok, __Ret, _T1}
		  catch
		    fail -> fail
		  end;
	      fail -> fail
	    end
    end.

name() -> fun (T) -> __P = field(), __P(T) end.

field() ->
    fun (T) ->
	    __P = '__alt'([escaped(), 'non-escaped'()]), __P(T)
    end.

escaped() ->
    fun (T) ->
	    __P = '__seq'(['DQUOTE'(),
			   '__repeat'(0, infinity,
				      '__alt'(['TEXTDATA'(), 'COMMA'(), 'CR'(), 'LF'(),
					       'DDQUOTE'()])),
			   'DQUOTE'()]),
	    case __P(T) of
	      {ok, [_YY1, _YY2, _YY3] = _YY, _T1} ->
		  try _YY2 of
		    __Ret -> {ok, __Ret, _T1}
		  catch
		    fail -> fail
		  end;
	      fail -> fail
	    end
    end.

'non-escaped'() ->
    fun (T) ->
	    __P = '__repeat'(0, infinity, 'TEXTDATA'()), __P(T)
    end.

'COMMA'() ->
    fun (T) ->
	    __P = fun (<<44, Tl/binary>>) -> {ok, 44, Tl};
		      (_) -> fail
		  end,
	    __P(T)
    end.

'CR'() ->
    fun (T) ->
	    __P = fun (<<13, Tl/binary>>) -> {ok, 13, Tl};
		      (_) -> fail
		  end,
	    __P(T)
    end.

'DDQUOTE'() ->
    fun (T) ->
	    __P = '__repeat'(2, 2, 'DQUOTE'()),
	    case __P(T) of
	      {ok, _YY, _T1} ->
		  try $" of
		    __Ret -> {ok, __Ret, _T1}
		  catch
		    fail -> fail
		  end;
	      fail -> fail
	    end
    end.

'DQUOTE'() ->
    fun (T) ->
	    __P = fun (<<34, Tl/binary>>) -> {ok, 34, Tl};
		      (_) -> fail
		  end,
	    __P(T)
    end.

'LF'() ->
    fun (T) ->
	    __P = fun (<<10, Tl/binary>>) -> {ok, 10, Tl};
		      (_) -> fail
		  end,
	    __P(T)
    end.

'CRLF'() ->
    fun (T) ->
	    __P = '__alt'(['__seq'(['CR'(), 'LF'()]), 'LF'()]),
	    __P(T)
    end.

'TEXTDATA'() ->
    fun (T) ->
	    __P = fun (<<C, Tl/binary>>)
			  when (C >= 32) and (C =< 33) ->
			  {ok, C, Tl};
		      (<<C, Tl/binary>>) when (C >= 35) and (C =< 43) ->
			  {ok, C, Tl};
		      (<<C, Tl/binary>>) when (C >= 45) and (C =< 126) ->
			  {ok, C, Tl};
		      (_) -> fail
		  end,
	    __P(T)
    end.

'__alt'([P | Ps]) ->
    fun (T) ->
	    case P(T) of
	      {ok, _R, _T1} = Res -> Res;
	      fail ->
		  case Ps of
		    [] -> fail;
		    _ -> ('__alt'(Ps))(T)
		  end
	    end
    end.

'__repeat'(Min, Max, P) -> '__repeat'(Min, Max, P, 0).

'__repeat'(Min, Max, P, Found) ->
    fun (T) ->
	    case P(T) of
	      {ok, R1, T1} when Max == Found + 1 -> {ok, [R1], T1};
	      {ok, R1, T1} ->
		  case ('__repeat'(Min, Max, P, Found + 1))(T1) of
		    {ok, R2, T2} -> {ok, [R1 | R2], T2};
		    fail when Found >= Min -> {ok, [R1], T1};
		    fail -> fail
		  end;
	      fail when Found >= Min -> {ok, [], T};
	      fail -> fail
	    end
    end.

'__seq'([P | Ps]) ->
    fun (T) ->
	    case P(T) of
	      {ok, R1, T1} ->
		  case ('__seq'(Ps))(T1) of
		    {ok, R2, T2} -> {ok, [R1 | R2], T2};
		    fail -> fail
		  end;
	      fail -> fail
	    end
    end;
'__seq'([]) -> fun (T) -> {ok, [], T} end.

Reply via email to