OTWO-1213 Works around lost encoding in Ruby/C binding layer
[ohcount] / src / parsers / modula2.rl
1 // modula2.rl, 
2 // derived from code written by Mitchell Foral. mitchell<att>caladbolg<dott>net
3
4
5 /************************* Required for every parser *************************/
6 #ifndef OHCOUNT_MODULA2_PARSER_H
7 #define OHCOUNT_MODULA2_PARSER_H
8
9 #include "../parser_macros.h"
10
11 // the name of the language
12 const char *MODULA2_LANG = LANG_MODULA2;
13
14 // the languages entities
15 const char *modula2_entities[] = {
16   "space", "comment", "string", "any"
17 };
18
19 // constants associated with the entities
20 enum {
21   MODULA2_SPACE = 0, MODULA2_COMMENT, MODULA2_STRING, MODULA2_ANY
22 };
23
24 /*****************************************************************************/
25
26 %%{
27   machine modula2;
28   write data;
29   include common "common.rl";
30
31   # Line counting machine
32
33   action modula2_ccallback {
34     switch(entity) {
35     case MODULA2_SPACE:
36       ls
37       break;
38     case MODULA2_ANY:
39       code
40       break;
41     case INTERNAL_NL:
42       std_internal_newline(MODULA2_LANG)
43       break;
44     case NEWLINE:
45       std_newline(MODULA2_LANG)
46     }
47   }
48
49
50   # Modula-2 comments
51
52   action modula2_comment_nc_res { nest_count = 0; }
53   action modula2_comment_nc_inc { nest_count++; }
54   action modula2_comment_nc_dec { nest_count--; }
55
56   modula2_comment =
57     '(*' >modula2_comment_nc_res @comment (
58       newline %{ entity = INTERNAL_NL; } %modula2_ccallback
59       |
60       ws
61       |
62       '(*' @modula2_comment_nc_inc @comment
63       |
64       '*)' @modula2_comment_nc_dec @comment
65       |
66       ^space @comment
67     )* :>> ('*)' when { nest_count == 0 }) @comment;
68
69
70   # Modula-2 string literals
71
72   modula2_singlequoted_string = '\'' @code [^\r\n\f"]* '\'';
73   modula2_doublequoted_string = '"' @code [^\r\n\f"]* '"';
74
75   modula2_string = modula2_singlequoted_string | modula2_doublequoted_string;
76
77
78   # Line counter
79
80   modula2_line := |*
81     spaces          ${ entity = MODULA2_SPACE; } => modula2_ccallback;
82     modula2_comment;
83     modula2_string;
84     newline         ${ entity = NEWLINE;       } => modula2_ccallback;
85     ^space          ${ entity = MODULA2_ANY;   } => modula2_ccallback;
86   *|;
87
88
89   # Entity machine
90
91   action modula2_ecallback {
92     callback(MODULA2_LANG, modula2_entities[entity], cint(ts), cint(te),
93              userdata);
94   }
95
96   modula2_comment_entity = '(*' >modula2_comment_nc_res (
97     '(*' @modula2_comment_nc_inc
98     |
99     '*)' @modula2_comment_nc_dec
100     |
101     any
102   )* :>> ('*)' when { nest_count == 0 });
103
104   modula2_string_entity = sq_str | dq_str;
105
106   modula2_entity := |*
107     space+                 ${ entity = MODULA2_SPACE;   } => modula2_ecallback;
108     modula2_comment_entity ${ entity = MODULA2_COMMENT; } => modula2_ecallback;
109     modula2_string_entity  ${ entity = MODULA2_STRING;  } => modula2_ecallback;
110     # TODO: detecting other entities may be useful to differentiate dialects
111     ^space;
112   *|;
113 }%%
114
115 /************************* Required for every parser *************************/
116
117 /* Parses a string buffer with Modula-2 code.
118  *
119  * @param *buffer The string to parse.
120  * @param length The length of the string to parse.
121  * @param count Integer flag specifying whether or not to count lines. If yes,
122  *   uses the Ragel machine optimized for counting. Otherwise uses the Ragel
123  *   machine optimized for returning entity positions.
124  * @param *callback Callback function. If count is set, callback is called for
125  *   every line of code, comment, or blank with 'lcode', 'lcomment', and
126  *   'lblank' respectively. Otherwise callback is called for each entity found.
127  */
128 void parse_modula2(char *buffer, int length, int count,
129                   void (*callback) (const char *lang, const char *entity, int s,
130                                     int e, void *udata),
131                   void *userdata
132   ) {
133   init
134
135   int nest_count = 0;
136
137   %% write init;
138   cs = (count) ? modula2_en_modula2_line : modula2_en_modula2_entity;
139   %% write exec;
140
141   // if no newline at EOF; callback contents of last line
142   if (count) { process_last_line(MODULA2_LANG) }
143 }
144
145 #endif
146
147 /*****************************************************************************/