Added C# 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 // END parser includes
26
27 ParseResult *pr;
28 char *parse_buffer;
29 int parse_buffer_len;
30
31 struct language {
32   char name[MAX_LANGUAGE_NAME];
33   void (*parser) (char*, int, int, void*);
34 };
35
36 struct language languages[] = {
37 // BEGIN languages
38   { "c", parse_c },
39   { "cpp", parse_cpp },
40   { "csharp", parse_csharp },
41   { "lua", parse_lua },
42   { "ruby", parse_ruby },
43   { "css", parse_css },
44   { "javascript", parse_javascript },
45   { "html", parse_html },
46   { "java", parse_java },
47   { "objective_c", parse_objective_c },
48   { "visualbasic", parse_visual_basic },
49   { "sql", parse_sql },
50   { "actionscript", parse_actionscript },
51   { "ada", parse_ada },
52   { "assembler", parse_assembler },
53   { "autoconf", parse_autoconf },
54   { "automake", parse_automake },
55   { "awk", parse_awk },
56   { "bat", parse_bat },
57   //{ "boo", parse_boo },
58 // END languages
59   { "", NULL }
60 };
61
62 /* Returns a language_breakdown for a given language name. */
63 LanguageBreakdown *get_language_breakdown(char *name) {
64         int i;
65         for (i = 0; i < pr->language_breakdown_count; i++)
66                 if (strcmp(pr->language_breakdowns[i].name, name) == 0)
67                         return &pr->language_breakdowns[i]; // found one
68
69         language_breakdown_initialize(
70     &pr->language_breakdowns[pr->language_breakdown_count],
71     name, parse_buffer_len); // create one
72         return &pr->language_breakdowns[pr->language_breakdown_count++];
73 }
74
75 /* Yields a line's language, semantic, and text to an optional Ruby block. */
76 void ragel_parse_yield_line(const char *lang, const char *entity, int s, int e) {
77         if (rb_block_given_p()) {
78         VALUE ary;
79                 ary = rb_ary_new2(2);
80                 rb_ary_store(ary, 0, ID2SYM(rb_intern(lang)));
81                 if (strcmp(entity, "lcode") == 0)
82       rb_ary_store(ary, 1, ID2SYM(rb_intern("code")));
83     else if (strcmp(entity, "lcomment") == 0)
84       rb_ary_store(ary, 1, ID2SYM(rb_intern("comment")));
85     else if (strcmp(entity, "lblank") == 0)
86       rb_ary_store(ary, 1, ID2SYM(rb_intern("blank")));
87     rb_ary_store(ary, 2, rb_str_new(parse_buffer + s, e - s));
88                 rb_yield(ary);
89         }
90 }
91
92 /* Callback function called for every entity in the source file discovered.
93  *
94  * Entities are defined in the parser and are things like comments, strings,
95  * keywords, etc.
96  * This callback yields for a Ruby block if necessary:
97  *   |language, semantic, line|
98  * @param *lang The language associated with the entity.
99  * @param *entity The entity discovered. There are 3 additional entities used
100  *   by Ohcount for counting: lcode, lcomment, and lblank for a line of code,
101  *   a whole line comment, or a blank line respectively.
102  * @param s The start position of the entity relative to the start of the
103  *   buffer.
104  * @param e The end position of the entity relative to the start of the buffer
105  *   (non-inclusive).
106  */
107 void ragel_parser_callback(const char *lang, const char *entity, int s, int e) {
108   LanguageBreakdown *lb = get_language_breakdown((char *) lang);
109   if (strcmp(entity, "lcode") == 0) {
110     language_breakdown_copy_code(lb, parse_buffer + s, parse_buffer + e);
111     ragel_parse_yield_line(lang, entity, s, e);
112   } else if (strcmp(entity, "lcomment") == 0) {
113     language_breakdown_copy_comment(lb, parse_buffer + s, parse_buffer + e);
114     ragel_parse_yield_line(lang, entity, s, e);
115   } else if (strcmp(entity, "lblank") == 0) {
116     lb->blank_count++;
117     ragel_parse_yield_line(lang, entity, s, e);
118   }
119 }
120
121 /* Tries to use an existing Ragel parser for the given language.
122  *
123  * @param *parse_result An allocated, empty ParseResult to hold parse results.
124  * @param *buffer A pointer to the buffer or character in the buffer to start
125  *   parsing at.
126  * @param buffer_len The length of the buffer to parse.
127  * @param *lang The language name associated with the buffer to parse.
128  * @return 1 if a Ragel parser is found, 0 otherwise.
129  */
130 int ragel_parser_parse(ParseResult *parse_result,
131                        char *buffer, int buffer_len, char *lang) {
132   pr = parse_result;
133   pr->language_breakdown_count = 0;
134   parse_buffer = buffer;
135   parse_buffer_len = buffer_len;
136   int i;
137   for (i = 0; strlen(languages[i].name) != 0; i++)
138     if (strcmp(languages[i].name, lang) == 0) {
139       languages[i].parser(buffer, buffer_len, 1, ragel_parser_callback);
140       printf("%s", lang);
141       return 1;
142     }
143   return 0;
144 }