Added XML Schema parser.
[ohcount] / ext / ohcount_native / ragel_parser.c
1 // ragel_parser.c written by Mitchell Foral. mitchell<att>caladbolg<dott>net.
2
3 #include "ruby.h"
4 #include "common.h"
5
6 // BEGIN parser includes
7 #include "c_parser.h"
8 #include "lua_parser.h"
9 #include "ruby_parser.h"
10 #include "css_parser.h"
11 #include "javascript_parser.h"
12 #include "html_parser.h"
13 #include "java_parser.h"
14 #include "objective_c_parser.h"
15 #include "visual_basic_parser.h"
16 #include "sql_parser.h"
17 #include "actionscript_parser.h"
18 #include "ada_parser.h"
19 #include "assembler_parser.h"
20 #include "autoconf_parser.h"
21 #include "automake_parser.h"
22 #include "awk_parser.h"
23 #include "bat_parser.h"
24 //#include "boo_parser.h"
25 #include "dcl_parser.h"
26 #include "dylan_parser.h"
27 #include "ebuild_parser.h"
28 #include "exheres_parser.h"
29 #include "lisp_parser.h"
30 #include "fortranfixed_parser.h"
31 #include "fortranfree_parser.h"
32 #include "haskell_parser.h"
33 #include "makefile_parser.h"
34 #include "matlab_parser.h"
35 #include "metafont_parser.h"
36 #include "metapost_parser.h"
37 #include "pascal_parser.h"
38 //#include "perl_parser.h"
39 #include "pike_parser.h"
40 //#include "python_parser.h"
41 #include "rexx_parser.h"
42 #include "scheme_parser.h"
43 #include "shell_parser.h"
44 #include "smalltalk_parser.h"
45 #include "tcl_parser.h"
46 #include "vhdl_parser.h"
47 //#include "vim_parser.h"
48 #include "xml_parser.h"
49 #include "xslt_parser.h"
50 #include "xmlschema_parser.h"
51 // END parser includes
52
53 ParseResult *pr;
54 char *parse_buffer;
55 int parse_buffer_len;
56
57 struct language {
58   char name[MAX_LANGUAGE_NAME];
59   void (*parser) (char*, int, int, void*);
60 };
61
62 struct language languages[] = {
63 // BEGIN languages
64   { "c", parse_c },
65   { "cpp", parse_cpp },
66   { "csharp", parse_csharp },
67   { "lua", parse_lua },
68   { "ruby", parse_ruby },
69   { "css", parse_css },
70   { "javascript", parse_javascript },
71   { "html", parse_html },
72   { "java", parse_java },
73   { "objective_c", parse_objective_c },
74   { "visualbasic", parse_visual_basic },
75   { "sql", parse_sql },
76   { "actionscript", parse_actionscript },
77   { "ada", parse_ada },
78   { "assembler", parse_assembler },
79   { "autoconf", parse_autoconf },
80   { "automake", parse_automake },
81   { "awk", parse_awk },
82   { "bat", parse_bat },
83   //{ "boo", parse_boo },
84   { "dcl", parse_dcl },
85   { "dylan", parse_dylan },
86   { "ebuild", parse_ebuild },
87   { "exheres", parse_exheres },
88   { "emacslisp", parse_emacslisp },
89   { "lisp", parse_lisp },
90   { "fortranfixed", parse_fortranfixed },
91   { "fortranfree", parse_fortranfree },
92   { "haskell", parse_haskell },
93   { "make", parse_makefile },
94   { "matlab", parse_matlab },
95   { "metafont", parse_metafont },
96   { "metapost", parse_metapost },
97   { "pascal", parse_pascal },
98   //{ "perl", parse_perl },
99   { "pike", parse_pike },
100   //{ "python", parse_python },
101   { "rexx", parse_rexx },
102   { "scheme", parse_scheme },
103   { "shell", parse_shell },
104   { "smalltalk", parse_smalltalk },
105   { "tcl", parse_tcl },
106   { "vala", parse_vala },
107   { "vhdl", parse_vhdl },
108   //{ "vim", parse_vim },
109   { "xml", parse_xml },
110   { "xslt", parse_xslt },
111   { "xmlschema", parse_xmlschema },
112 // END languages
113   { "", NULL }
114 };
115
116 /* Returns a language_breakdown for a given language name. */
117 LanguageBreakdown *get_language_breakdown(char *name) {
118         int i;
119         for (i = 0; i < pr->language_breakdown_count; i++)
120                 if (strcmp(pr->language_breakdowns[i].name, name) == 0)
121                         return &pr->language_breakdowns[i]; // found one
122
123         language_breakdown_initialize(
124     &pr->language_breakdowns[pr->language_breakdown_count],
125     name, parse_buffer_len); // create one
126         return &pr->language_breakdowns[pr->language_breakdown_count++];
127 }
128
129 /* Yields a line's language, semantic, and text to an optional Ruby block. */
130 void ragel_parse_yield_line(const char *lang, const char *entity, int s, int e) {
131         if (rb_block_given_p()) {
132         VALUE ary;
133                 ary = rb_ary_new2(2);
134                 rb_ary_store(ary, 0, ID2SYM(rb_intern(lang)));
135                 if (strcmp(entity, "lcode") == 0)
136       rb_ary_store(ary, 1, ID2SYM(rb_intern("code")));
137     else if (strcmp(entity, "lcomment") == 0)
138       rb_ary_store(ary, 1, ID2SYM(rb_intern("comment")));
139     else if (strcmp(entity, "lblank") == 0)
140       rb_ary_store(ary, 1, ID2SYM(rb_intern("blank")));
141     rb_ary_store(ary, 2, rb_str_new(parse_buffer + s, e - s));
142                 rb_yield(ary);
143         }
144 }
145
146 /* Callback function called for every entity in the source file discovered.
147  *
148  * Entities are defined in the parser and are things like comments, strings,
149  * keywords, etc.
150  * This callback yields for a Ruby block if necessary:
151  *   |language, semantic, line|
152  * @param *lang The language associated with the entity.
153  * @param *entity The entity discovered. There are 3 additional entities used
154  *   by Ohcount for counting: lcode, lcomment, and lblank for a line of code,
155  *   a whole line comment, or a blank line respectively.
156  * @param s The start position of the entity relative to the start of the
157  *   buffer.
158  * @param e The end position of the entity relative to the start of the buffer
159  *   (non-inclusive).
160  */
161 void ragel_parser_callback(const char *lang, const char *entity, int s, int e) {
162   LanguageBreakdown *lb = get_language_breakdown((char *) lang);
163   if (strcmp(entity, "lcode") == 0) {
164     language_breakdown_copy_code(lb, parse_buffer + s, parse_buffer + e);
165     ragel_parse_yield_line(lang, entity, s, e);
166   } else if (strcmp(entity, "lcomment") == 0) {
167     language_breakdown_copy_comment(lb, parse_buffer + s, parse_buffer + e);
168     ragel_parse_yield_line(lang, entity, s, e);
169   } else if (strcmp(entity, "lblank") == 0) {
170     lb->blank_count++;
171     ragel_parse_yield_line(lang, entity, s, e);
172   }
173 }
174
175 /* Tries to use an existing Ragel parser for the given language.
176  *
177  * @param *parse_result An allocated, empty ParseResult to hold parse results.
178  * @param *buffer A pointer to the buffer or character in the buffer to start
179  *   parsing at.
180  * @param buffer_len The length of the buffer to parse.
181  * @param *lang The language name associated with the buffer to parse.
182  * @return 1 if a Ragel parser is found, 0 otherwise.
183  */
184 int ragel_parser_parse(ParseResult *parse_result,
185                        char *buffer, int buffer_len, char *lang) {
186   pr = parse_result;
187   pr->language_breakdown_count = 0;
188   parse_buffer = buffer;
189   parse_buffer_len = buffer_len;
190   int i;
191   for (i = 0; strlen(languages[i].name) != 0; i++)
192     if (strcmp(languages[i].name, lang) == 0) {
193       languages[i].parser(buffer, buffer_len, 1, ragel_parser_callback);
194       printf("%s", lang);
195       return 1;
196     }
197   return 0;
198 }