diff --git a/rawstr4c/lib/CGenerator.rakumod b/rawstr4c/lib/CGenerator.rakumod index c57936c..aae7d70 100644 --- a/rawstr4c/lib/CGenerator.rakumod +++ b/rawstr4c/lib/CGenerator.rakumod @@ -13,7 +13,7 @@ unit module CGenerator; use ConfigParser; -class CharConverter { +class CStringConverter { method convert-char($char, $mode) { given $mode { @@ -41,7 +41,7 @@ class CharConverter { } } - method convert-content($content, $mode) { + method convert-string($content, $mode) { my $result = ""; for $content.comb -> $char { $result ~= self.convert-char($char, $mode); @@ -51,7 +51,7 @@ class CharConverter { } -class VariableNameGenerator { +class CVariableNameGenerator { method generate($global-config, $section-config, $title) { @@ -92,3 +92,170 @@ class VariableNameGenerator { return $postfix.as-string(); } } + + +#| 生成 .h 文件或/和 .c 文件,或存储到 @variables 中 +class CVariableGenerator { + has @.variables; + has $.c-header-filename; + + method new($c-header-filename = "rawstr4c.h") { + self.bless(:$c-header-filename, :variables([])); + } + + method add-variable($name, $content, $type) { + @.variables.push: { + name => $name, + content => $content, + type => $type + }; + } + + method generate-c-header-file($output-mode = 'global-variable') { + my $header = qq:to/EOF/; + #pragma once + + /** + * Generated by rawstr4c + * + * Date: {DateTime.now.Str} + */ + + EOF + + for @.variables -> $var { + given $var { + when 'global-variable' { + if $output-mode eq 'global-variable-only-header' { + $header ~= "char {$var}[] = \"{$var}\";\n"; + } else { + $header ~= "extern char {$var}[];\n"; + } + } + when 'macro' { + $header ~= "#define {$var.uc} \"{$var}\"\n"; + } + } + } + + return $header; + } + + method generate-c-source-file() { + my $source = qq:to/EOF/; + #include "{$.c-header-filename}" + + /** + * Generated by rawstr4c + * + * Date: {DateTime.now.Str} + */ + + EOF + + for @.variables -> $var { + if $var eq 'global-variable' { + $source ~= "char {$var}[] = \"{$var}\";\n"; + } + } + + return $source; + } + + method save-files($output-mode) { + $.c-header-filename.IO.spurt(self.generate-c-header-file($output-mode)); + say "Generated C header file: $.c-header-filename"; + + if $output-mode eq 'global-variable' { + my $has-globals = @.variables.grep({ $_ eq 'global-variable' }).elems > 0; + if $has-globals { + my $c-source-filename = $.c-header-filename.subst(/'.h'$/, '.c'); + $c-source-filename.IO.spurt(self.generate-c-source-file()); + say "Generated C source file: $c-source-filename"; + } + } + } +} + + +class Generator { + has $.cstring-converter; + has $.varname-generator; + has $.variable-generator; + + method new($output-file = 'rawstr4c.h') { + self.bless( + :cstring-converter(CStringConverter.new()), + :varname-generator(CVariableNameGenerator.new()), + :variable-generator(CVariableGenerator.new($output-file)) + ); + } + + method get-config-value($global-config, $section-config, $key, $default = '') { + return $section-config.exist($key) ?? + $section-config.get($key) !! + $global-config.get($key, $default); + } + + + method generate-for-section($global-config, $section) { + my $section-config = $section; + my $title = $section; + my $code = $section<raw-string>; + + return unless $code; + + say "=== Section: $title ==="; + + my $translate-mode = self.get-config-value( + $global-config, $section-config, 'translate', ':escape' + ).as-mode(); + + my $var-name = $.varname-generator.generate($global-config, $section-config, $title); + + my $output-mode = $global-config.get('output', ':terminal').as-mode(); + + say "Variable name: $var-name"; + say "Translation mode: $translate-mode"; + say "Output mode: $output-mode"; + + my $language = $section-config.get('language', 'None').as-string(); + say "Language: $language"; + say ''; + + my $c-string = $.cstring-converter.convert-string($code, $translate-mode); + + given $output-mode { + when 'terminal' { + say 'char ' ~ $var-name ~ '[] = "' ~ $c-string ~ '";'; + } + when 'global-variable' | 'global-variable-only-header' { + $.variable-generator.add-variable($var-name, $c-string, 'global-variable'); + } + when 'macro' { + $.variable-generator.add-variable($var-name, $c-string, 'macro'); + } + default { + die "Illegal output mode: $output-mode"; + } + } + say "\n"; + } + + + method generate-all($parser) { + my $global-config = $parser.global-config; + + # 这个 generate-for-section() 要么把变量输出到终端,要么累计到 @variabels 中 + for $parser.sections -> $section { + self.generate-for-section($global-config, $section); + } + + my $output-mode = $global-config.get('output', ':terminal').as-mode(); + + # 最后把累计到 @variables 的内容输出到文件 + if $output-mode ne 'terminal' { + $.variable-generator.save-files($output-mode); + } + } +}