Fixes recursion bug in disambiguate_in().
[ohcount] / src / parsers / modula3.rl
1 // modula3.rl, 
2 // derived from code written by Mitchell Foral. mitchell<att>caladbolg<dott>net
3
4
5 /************************* Required for every parser *************************/
6 #ifndef OHCOUNT_MODULA3_PARSER_H
7 #define OHCOUNT_MODULA3_PARSER_H
8
9 #include "../parser_macros.h"
10
11 // the name of the language
12 const char *MODULA3_LANG = LANG_MODULA3;
13
14 // the languages entities
15 const char *modula3_entities[] = {
16   "space", "comment", "string", "any"
17 };
18
19 // constants associated with the entities
20 enum {
21   MODULA3_SPACE = 0, MODULA3_COMMENT, MODULA3_STRING, MODULA3_ANY
22 };
23
24 /*****************************************************************************/
25
26 %%{
27   machine modula3;
28   write data;
29   include common "common.rl";
30
31   # Line counting machine
32
33   action modula3_ccallback {
34     switch(entity) {
35     case MODULA3_SPACE:
36       ls
37       break;
38     case MODULA3_ANY:
39       code
40       break;
41     case INTERNAL_NL:
42       std_internal_newline(MODULA3_LANG)
43       break;
44     case NEWLINE:
45       std_newline(MODULA3_LANG)
46     }
47   }
48
49
50   # Modula-3 comments
51
52   action modula3_comment_nc_res { nest_count = 0; }
53   action modula3_comment_nc_inc { nest_count++; }
54   action modula3_comment_nc_dec { nest_count--; }
55
56   modula3_comment =
57     '(*' >modula3_comment_nc_res @comment (
58       newline %{ entity = INTERNAL_NL; } %modula3_ccallback
59       |
60       ws
61       |
62       '(*' @modula3_comment_nc_inc @comment
63       |
64       '*)' @modula3_comment_nc_dec @comment
65       |
66       ^space @comment
67     )* :>> ('*)' when { nest_count == 0 }) @comment;
68
69
70   # Modula-3 string literals
71
72   modula3_singlequoted_string =
73     '\'' @code (
74       escaped_newline %{ entity = INTERNAL_NL; } %modula3_ccallback
75       |
76       ws
77       |
78       [^\t '\\] @code
79       |
80       '\\' nonnewline @code
81     )* '\'';
82   modula3_doublequoted_string =
83     '"' @code (
84       escaped_newline %{ entity = INTERNAL_NL; } %modula3_ccallback
85       |
86       ws
87       |
88       [^\t "\\] @code
89       |
90       '\\' nonnewline @code
91     )* '"';
92   modula3_string = modula3_singlequoted_string | modula3_doublequoted_string;
93
94
95   # Line counter
96
97   modula3_line := |*
98     spaces          ${ entity = MODULA3_SPACE; } => modula3_ccallback;
99     modula3_comment;
100     modula3_string;
101     newline         ${ entity = NEWLINE;       } => modula3_ccallback;
102     ^space          ${ entity = MODULA3_ANY;   } => modula3_ccallback;
103   *|;
104
105
106   # Entity machine
107
108   action modula3_ecallback {
109     callback(MODULA3_LANG, modula3_entities[entity], cint(ts), cint(te),
110              userdata);
111   }
112
113   modula3_comment_entity = '(*' >modula3_comment_nc_res (
114     '(*' @modula3_comment_nc_inc
115     |
116     '*)' @modula3_comment_nc_dec
117     |
118     any
119   )* :>> ('*)' when { nest_count == 0 });
120
121   modula3_string_entity = sq_str_with_escapes |
122                           dq_str_with_escapes;
123
124   modula3_entity := |*
125     space+                 ${ entity = MODULA3_SPACE;   } => modula3_ecallback;
126     modula3_comment_entity ${ entity = MODULA3_COMMENT; } => modula3_ecallback;
127     modula3_string_entity  ${ entity = MODULA3_STRING;  } => modula3_ecallback;
128     # TODO: detecting other entities may be useful to differentiate dialects
129     ^space;
130   *|;
131 }%%
132
133 /************************* Required for every parser *************************/
134
135 /* Parses a string buffer with Modula-3 code.
136  *
137  * @param *buffer The string to parse.
138  * @param length The length of the string to parse.
139  * @param count Integer flag specifying whether or not to count lines. If yes,
140  *   uses the Ragel machine optimized for counting. Otherwise uses the Ragel
141  *   machine optimized for returning entity positions.
142  * @param *callback Callback function. If count is set, callback is called for
143  *   every line of code, comment, or blank with 'lcode', 'lcomment', and
144  *   'lblank' respectively. Otherwise callback is called for each entity found.
145  */
146 void parse_modula3(char *buffer, int length, int count,
147                   void (*callback) (const char *lang, const char *entity, int s,
148                                     int e, void *udata),
149                   void *userdata
150   ) {
151   init
152
153   int nest_count = 0;
154
155   %% write init;
156   cs = (count) ? modula3_en_modula3_line : modula3_en_modula3_entity;
157   %% write exec;
158
159   // if no newline at EOF; callback contents of last line
160   if (count) { process_last_line(MODULA3_LANG) }
161 }
162
163 #endif
164
165 /*****************************************************************************/