Skip to content

Instantly share code, notes, and snippets.

@tacigar
Last active February 14, 2018 17:00
Show Gist options
  • Save tacigar/8d25407658ceb1a88f6d257ea60afe1b to your computer and use it in GitHub Desktop.
Save tacigar/8d25407658ceb1a88f6d257ea60afe1b to your computer and use it in GitHub Desktop.
y.output から文法情報のみを抽出
#include <cctype>
#include <iostream>
#include <fstream>
#include <string>
#include <regex>
#include <unordered_map>
auto main() -> int
{
while (true) {
std::string buffer;
std::getline(std::cin, buffer);
if (buffer.find("Grammar") != std::string::npos) {
break;
}
}
std::string current;
std::unordered_map<std::string, std::vector<std::string>> data;
while (true) {
std::string buffer;
std::getline(std::cin, buffer);
if (buffer == "") {
continue;
}
if (!std::isspace(buffer[0])) {
break;
}
std::smatch matches;
if (std::regex_search(buffer, matches, std::regex("^\\s*\\d+\\s*([$@\\w]+):\\s*(.*)"))) {
if (matches[1].str()[0] == '@') {
continue;
} else {
current = matches[1].str();
data[matches[1].str()].push_back(matches[2].str());
continue;
}
}
if (std::regex_search(buffer, matches, std::regex("^\\s*\\d+\\s*\\|\\s*(.*)"))) {
data[current].push_back(matches[1].str());
continue;
}
}
for (decltype(auto) entry: data) {
int indent = entry.first.size();
std::cout << entry.first << ": ";
for (int i = 0; i < entry.second.size(); ++i) {
std::string second = std::regex_replace(entry.second[i], std::regex("@\\d+"), "");
if (i == 0) {
std::cout << second << std::endl;
} else {
std::cout << std::string(indent, ' ') << "| " << second << std::endl;
}
}
}
return 0;
}
while true do
local buf = io.read()
if buf:find("Grammar") or buf:find("文法") then
break
end
end
local currentLabel
local data = {}
local order = {}
local maxindent = 0
while true do
local buf = io.read()
if buf == "" then
goto CONTINUE
elseif not buf:sub(1, 1):match("^%s") then
break
end
local label, member = buf:match("^%s*%d+%s*([$%w]+):%s*(.*)")
if label then
if label:len() > maxindent then
maxindent = label:len()
end
currentLabel = label
if not data[label] then
table.insert(order, label)
data[label] = {}
end
table.insert(data[label], member)
goto CONTINUE
end
member = buf:match("^%s*%d+%s*|%s*(.*)")
if member then
table.insert(data[currentLabel], member)
goto CONTINUE
end
::CONTINUE::
end
for _, label in ipairs(order) do
local members = data[label]
io.write(("%s"):format(label))
for i, member in ipairs(members) do
member = member:gsub("$@%d+ ", "")
member = member:gsub("@%d+ ", "")
if i == 1 then
io.write((" "):rep(maxindent - ("%s: "):format(label):len() + 2))
io.write((": %s\n"):format(member))
else
io.write((" "):rep(maxindent))
io.write(("| %s\n"):format(member))
end
end
end

Lua

使い方

cat y.output | lua yacc-grammar-extractor.lua

C++

コンパイル

g++ -o yacc-grammar-extractor yacc-grammar-extractor.cpp -std=c++1y

使い方


cat y.output | ./yacc-grammar-extractor

利用例

Lua 1.1 の YACC ファイル lua.stxy.output を以下コマンドで生成.

yacc -v lua.sty

生成された y.output から文法情報のみ抽出.

cat y.output | lua yacc-grammar-extractor.lua

以下のような出力が得られる.

exprlist: /* empty */
        | exprlist1
statlist: /* empty */
        | statlist stat sc
decinit: /* empty */
       | '=' exprlist1
ffieldlist1: ffield
           | ffieldlist1 ',' ffield
expr1: expr
var: NAME
   | var  '[' expr1 ']'
   | var  '.' NAME
function: FUNCTION NAME  '(' parlist ')'  block END
ffieldlist: /* empty */
          | ffieldlist1
lfieldlist1: expr1
           | lfieldlist1 ',' expr1
localdeclist: NAME
            | localdeclist ',' NAME
expr: '(' expr ')'
    | expr1 '=' expr1
    | expr1 '<' expr1
    | expr1 '>' expr1
    | expr1 NE expr1
    | expr1 LE expr1
    | expr1 GE expr1
    | expr1 '+' expr1
    | expr1 '-' expr1
    | expr1 '*' expr1
    | expr1 '/' expr1
    | expr1 CONC expr1
    | '+' expr1
    | '-' expr1
    | typeconstructor
    | '@' '(' dimension ')'
    | var
    | NUMBER
    | STRING
    | NIL
    | functioncall
    | NOT expr1
    | expr1 AND PrepJump  expr1
    | expr1 OR PrepJump  expr1
typeconstructor: '@'  objectname fieldlist
PrepJump: /* empty */
objectname: /* empty */
          | NAME
varlist1: var
        | varlist1 ',' var
$accept: functionlist $end
exprlist1: expr
         | exprlist1 ','  expr
block:  statlist  ret
parlist: /* empty */
       | parlist1
parlist1: NAME
        | parlist1 ',' NAME
stat1: IF expr1 THEN PrepJump block PrepJump elsepart END
     | WHILE  expr1 DO PrepJump block PrepJump END
     | REPEAT  block UNTIL expr1 PrepJump
     | varlist1 '=' exprlist1
     | functioncall
     | typeconstructor
     | LOCAL localdeclist decinit
dimension: /* empty */
         | expr1
ffield: NAME  '=' expr1
sc: /* empty */
  | ';'
stat:  stat1
functionvalue: var
ret: /* empty */
   |  RETURN exprlist sc
elsepart: /* empty */
        | ELSE block
        | ELSEIF expr1 THEN PrepJump block PrepJump elsepart
setdebug: DEBUG
functionlist: /* empty */
            | functionlist  stat sc
            | functionlist function
            | functionlist setdebug
functioncall: functionvalue  '(' exprlist ')'
lfieldlist: /* empty */
          | lfieldlist1
fieldlist: '{' ffieldlist '}'
         | '[' lfieldlist ']'
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment