0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

ITパスポート・基本情報技術者試験の擬似言語をPythonに変換

Last updated at Posted at 2025-08-17

はじめに

ITパスポート・基本情報技術者試験の擬似言語をPythonに変換するプログラム(トランスコンパイラ)の紹介です。Python3.10で動作を確認しています。

Pythonに変換することで、Python用のデバッガが使えるようになるため、擬似言語の理解の助けになるのではないでしょうか。

使い方

ページ末尾のソースコードを「pesudo.py」という名前で保存したという前提で説明します。
そのまま実行した場合は、標準入力から擬似言語を読み込み、Pythonに変換して標準出力に出力します。

$ python3 pseudo.py
123を出力
Ctrl-D
print(123)

コマンドライン引数にファイル名を指定すると、そのファイルから擬似言語を読み込みます(test.txtの中身は「123を出力」)。

$ python3 pseudo.py test.txt
print(123)

「-o ファイル名」と指定すると、そのファイルにPythonコードが保存されます。

$ python3 pseudo.py test.txt -o test.py

「-e」を指定すると、Pythonコードに変換せず、その場で擬似言語を実行します。

$ python3 pseudo.py test.txt -e
123

注意

  • 不完全な仕様をもとに実装しているため、擬似言語として正しいコードなのに変換できない場合があります
  • エラーチェックが甘いので、擬似言語として正しくないコードを変換できてしまう場合があります

仕様

公開されている仕様との差分(独自に追加した仕様)のみ説明します。

基本型は「整数型」「実数型」「文字列型」「文字型」「論理型」の5種類です。
基本型の後ろに「の配列」をつけると一次元配列に、「配列の配列」もしくは「の二次元配列」をつけると二次元配列になります。

リテラル

「123」のように数字を並べたものは整数リテラル、「123.45」のように数字の間に小数点が入ると実数リテラルとなります。
「"ABC"」のようにダブルクォートで囲まれた文字列は文字列リテラルとなります。エスケープ機能がないため、ダブルクオートを含む文字列を作成する方法はありません。

手続きまたは関数の記法

手続き、関数の本体は、手続き・関数宣言後のインデントされた範囲とします。

○手続き名(型名1: 引数名1, 型名2: 引数名2, ...)
  処理1
  処理2
  ...
  処理n
○戻り値型名: 関数名(型名1: 引数名1, 型名2: 引数名2, ...)
  処理1
  処理2
  ...
  処理n

return

「return 値」と記述することで、指定した値を戻り値として関数を抜けます。

変数宣言

以下のように、コンマで区切って並べることで、同じ型の複数の変数をまとめて宣言することができます。また、変数宣言と同時に値を代入することもできます。

型名: 変数名1 ← 値1, 変数名2, ...

大域変数宣言

手続きまたは関数の外で宣言された変数を中から参照したい場合、その変数を大域変数として宣言する必要があります。大域変数として宣言するには、変数宣言の前に「大域:」と記述します。

大域: 型名: 変数名1 ← 値1, 変数名2, ...

for文の制御記述

以下の3種類が使用できます。

for (iを1から3まで1ずつ増やす)
for (iを3から1まで1ずつ減らす)
for (orderにordersの要素を順に代入する)

演算子と優先順位

演算子の種類 演算子 優先度
() . []
単項演算子 not + -
日本語演算 「~の要素数」など
乗除 mod × ÷「~÷~の商」「~÷~の余り」
加減 + -
論理シフト << >>
ビット論理積
ビット論理和
関係 ≠ ≦ ≧ < = >
日本語関係 「~が~以下」など
論理積 and
論理和 or

配列の特殊記法

以下のように記述すると、サイズが5で、全要素が-1で初期化された一次元配列を生成できます。

{5個の -1}

以下のように記述すると、サイズrow行col列で、全要素が「未定義の値」で初期化された二次元配列を生成できます。

{row行col列の 未定義の値}

日本語機能一覧

読めばわかる説明は省略します。

日本語処理

値を返さない手続き的な処理です。

処理 説明
(a)を出力
(a)と(b)をこの順にコンマ区切りで出力する 「コンマ区切り」を「空白区切り」に変更可
(a)の全ての要素 を先頭から順にコンマ区切りで出力する 「コンマ区切り」を「空白区切り」に変更可
(a)の末尾 に (b) を追加する 配列、文字列に使用可能
(a)と(b)の値を入れ替える
繰返し処理を終了する 他言語のbreak
(a)の値を(b)増やす

日本語比較

比較演算です(一部例外あり)。

処理 説明
(a) が (b) で割り切れる
(a) が (b) と等しい
(a) のいずれかの要素の値が (b) と等しい
(a) が (b) と等しくない
(a) が (b) より大きい
(a) が (b) より小さい
(a) が (b) 以上
(a) が (b) 以下
(a) が 未定義
(a) が 未定義ではない
(a) の要素の和 一次元、二次元両対応

日本語計算

値を返す関数的な処理です。

処理 説明
(a)の要素数
(a)の小数点以下を切り上げた値
(a)の小数点以下を切り捨てた値
(a)の正の平方根
(a)の整数部分
(a)の(b)乗
(a)の1文字だけから成る文字列 文字型から文字列型への変換
(a)の(b)文字目の文字
(a)の末尾から(b)文字目の文字
(a)を整数型に変換した値

ソースコード

#!/usr/bin/env python3
import re
import ast
import sys
import copy
import argparse
from dataclasses import dataclass
from collections import ChainMap

def parse(i):
    return ast.fix_missing_locations(program(peekable(i)))

class peekable:
    def __init__(self, it):
        self.it = it
        self.val = []
    def peek(self, pos = 0):
        while len(self.val) <= pos:
            self.val.append(next(self.it))
        return self.val[pos]
    def __next__(self):
        ret = self.peek()
        self.val.pop(0)
        return ret

global_variables = None
global_imports = None
global_environments = None

def program(s):
    global global_variables, global_imports, global_environments
    global_variables = set()
    global_imports = set()
    global_environments = ChainMap()
    stmts = []
    while not accept(s, 'EOF'):
        stmts += statement(s)
    if global_imports:
        stmts.insert(0, ast.Import([ast.alias(i) for i in global_imports]))
    return ast.Module(stmts, [])

def statement(s):
    global global_environments
    if accept(s, ''):
        global_environments = global_environments.new_child()
        if isinstance(s.peek(), Ident) and s.peek(1) == '(':
            rt = None
        else:
            rt, _ = japanese_inner(s), expect(s, ':')
        n, _ = expect_t(s, Ident), expect(s, '(')
        args = comma_separated(s, ')', arg_with_type)
        body = statements_until(s, 'ENDDEF')
        expect(s, 'ENDDEF')
        global_environments = global_environments.parents
        store_global = global_variables & set(collect_store(body))
        if store_global:
            body.insert(0, ast.Global([*store_global]))
        yield ast.FunctionDef(n.id, ast.arguments([], args, None, [], [], None, []), body, [], rt)
    elif accept(s, 'return'):
        yield ast.Return(None if s.peek() in ('elseif', 'else', 'endif') else bool_or(s))
    elif accept(s, 'if'):
        yield if_statement(s)
        expect(s, 'endif')
    elif accept(s, 'for'):
        _, i, _, it, _ = expect(s, '('), expect_t(s, Ident), expect_t(s, Japanese), bool_or(s), expect(s, ')')
        yield ast.For(ast.Name(i.id, ast.Store()), it, statements_until(s, 'endfor'), [])
        expect(s, 'endfor')
    elif accept(s, 'while'):
        _, c, _ = expect(s, '('), bool_or(s), expect(s, ')')
        yield ast.While(c, statements_until(s, 'endwhile'), [])
        expect(s, 'endwhile')
    elif accept(s, 'do'):
        body = statements_until(s, 'while')
        _, _, c, _ = expect(s, 'while'), expect(s, '('), bool_or(s), expect(s, ')')
        body.append(ast.If(ast.UnaryOp(ast.Not(), c), [ast.Break()], []))
        yield ast.While(ast.Constant(True), body, [])
    elif accept(s, '大域'):
        _, t, _ = expect(s, ':'), japanese_inner(s), expect(s, ':')
        while True:
            i = expect_t(s, Ident)
            global_variables.add(i.id)
            global_environments[i.id] = t
            e = bool_or(s) if accept(s, '') else None
            yield ast.AnnAssign(ast.Name(i.id, ast.Store()), copy.deepcopy(t), e, 1)
            if not accept(s, ','):
                break
    elif j := accept_t(s, Japanese):
        yield japanese_statement_commands[j.id]([])
    else:
        t = compare(s)
        if accept(s, ':'):
            while True:
                i = expect_t(s, Ident)
                global_environments[i.id] = t
                e = bool_or(s) if accept(s, '') else None
                yield ast.AnnAssign(ast.Name(i.id, ast.Store()), copy.deepcopy(t), e, 1)
                if not accept(s, ','):
                    break
        elif accept(s, ''):
            t.ctx = ast.Store()
            yield ast.Assign([t], bool_or(s))
        elif isinstance(s.peek(), Japanese):
            stack = [t]
            while True:
                if not (j := accept_t(s, Japanese)):
                    stack.append(compare(s))
                elif j.id in japanese_statement_commands:
                    yield japanese_statement_commands[j.id](stack)
                    break
                else:
                    stack.append(j)
        else:
            yield ast.Expr(t)

def arg_with_type(s):
    t, _, a = japanese_inner(s), expect(s, ':'), expect_t(s, Ident)
    global_environments[a.id] = t
    return ast.arg(a.id, t)

def collect_store(exprs):
    for expr in exprs:
        for node in ast.walk(expr):
            if isinstance(node, ast.Name) and isinstance(getattr(node, 'ctx', None), ast.Store):
                yield node.id

def print_(stack):
    args = [s for s in stack if not isinstance(s, Japanese)]
    if Japanese('の全ての要素') in stack:
        args = [ast.Starred(a) for a in args]
    sep = [ast.keyword('sep', ast.Constant(','))] if Japanese('コンマ区切りで') in stack else []
    return ast.Expr(ast.Call(ast.Name('print'), args, sep))
def add_last(stack):
    e1, _, _, e2 = stack
    type_ = get_type(e1)
    if isinstance(type_, ast.Name) and type_.id == 'str':
        e1.ctx = ast.Store()
        return ast.AugAssign(e1, ast.Add(), e2)
    else:
        return ast.Expr(ast.Call(ast.Attribute(e1, 'append'), [e2], []))
def swap(stack):
    a, b = copy.deepcopy(stack[0]), copy.deepcopy(stack[2])
    a.ctx = ast.Store()
    b.ctx = ast.Store()
    return ast.Assign([ast.Tuple([a, b], ast.Store())], ast.Tuple([stack[2], stack[0]]))
def break_(_):
    return ast.Break()
def increment(stack):
    return ast.AugAssign(stack[0], ast.Add(), stack[2])

japanese_statement_commands = {
    '出力': print_,
    'を追加': add_last,
    'の値を入れ替え': swap,
    '繰返し処理を終了': break_,
    '増やす': increment,
}

def get_type(var):
    nest = 0
    while isinstance(var, ast.Subscript):
        var = var.value
        nest += 1
    if not isinstance(var, ast.Name) or var.id not in global_environments:
        return None
    type_ = global_environments[var.id]
    for _ in range(nest):
        if not isinstance(type_, ast.Subscript):
            return None
        type_ = type_.slice
    return type_

def if_statement(s):
    _, c, _ = expect(s, '('), bool_or(s), expect(s, ')')
    t = statements_until(s, 'elseif', 'else', 'endif')
    if accept(s, 'elseif'):
        e = [if_statement(s)]
    elif accept(s, 'else'):
        e = statements_until(s, 'endif')
    else:
        e = []
    return ast.If(c, t, e)

def statements_until(s, *ss):
    body = []
    while s.peek() not in ss:
        body += statement(s)
    return body

def bool_or(s):
    values = [bool_and(s)]
    while accept(s, 'or'):
        values.append(bool_and(s))
    if len(values) == 1:
        return values[0]
    else:
        return ast.BoolOp(ast.Or(), values)

def bool_and(s):
    values = [japanese_outer(s)]
    while accept(s, 'and'):
        values.append(japanese_outer(s))
    if len(values) == 1:
        return values[0]
    else:
        return ast.BoolOp(ast.And(), values)

def japanese_outer(s):
    e = compare(s)
    if not isinstance(s.peek(), Japanese):
        return e
    stack = [e]
    while True:
        if not (j := accept_t(s, Japanese)):
            stack.append(compare(s))
        elif j.id in japanese_outer_commands:
            return japanese_outer_commands[j.id](stack)
        else:
            stack.append(j)

def divisible(stack):
    e = stack.pop(0)
    mods = [ast.BinOp(copy.deepcopy(e), ast.Mod(), s) for s in stack if not isinstance(s, Japanese)]
    return ast.Compare(mods[0], [ast.Eq() for _ in range(len(mods))], mods[1:] + [ast.Constant(0)])
def equals(stack):
    if len(stack) == 3 and isinstance(stack[1], Japanese) and stack[1].id == 'のいずれかの要素の値が':
        return ast.Compare(stack[2], [ast.In()], [stack[0]])
    else:
        return ast.Compare(stack[0], [ast.Eq() for _ in range(len(stack) - 1)], [s for s in stack[1:] if not isinstance(s, Japanese)])
def not_equals(stack):
    return ast.Compare(stack[0], [ast.NotEq()], [stack[2]])
def greater(stack):
    return ast.Compare(stack[0], [ast.Gt()], [stack[2]])
def less(stack):
    return ast.Compare(stack[0], [ast.Lt()], [stack[2]])
def greater_equal(stack):
    return ast.Compare(stack[0], [ast.GtE()], [stack[2]])
def less_equal(stack):
    return ast.Compare(stack[0], [ast.LtE()], [stack[2]])
def upto(stack):
    b, _, e, _, step = stack
    return ast.Call(ast.Name('range'), [b, ast.BinOp(e, ast.Add(), ast.Constant(1)), step], [])
def downto(stack):
    b, _, e, _, step = stack
    return ast.Call(ast.Name('range'), [b, ast.BinOp(e, ast.Sub(), ast.Constant(1)), ast.UnaryOp(ast.USub(), step)], [])
def is_not_none(stack):
    return ast.Compare(stack[0], [ast.IsNot()], [ast.Constant(None)])
def is_none(stack):
    return ast.Compare(stack[0], [ast.Is()], [ast.Constant(None)])
def sum_(stack):
    if len(stack) == 3:
        if stack[1].id == 'の列番号':
            return ast.Call(ast.Name('sum'),
                            [ast.GeneratorExp(ast.Subscript(ast.Name('i_'), ast.BinOp(stack[2], ast.Sub(), ast.Constant(1))),
                                              [ast.comprehension(ast.Name('i_', ast.Store()), stack[0], [], 0)])], [])
        else:
            return ast.Call(ast.Name('sum'), [ast.Subscript(stack[0], ast.BinOp(stack[2], ast.Sub(), ast.Constant(1)))], [])
    type_ = get_type(stack[0])
    if isinstance(type_, ast.Subscript) and isinstance(type_.slice, ast.Subscript):
        return ast.Call(ast.Name('sum'),
                        [ast.GeneratorExp(ast.Call(ast.Name('sum'), [ast.Name('i_')], []),
                                          [ast.comprehension(ast.Name('i_', ast.Store()), stack[0], [], 0)])], [])
    else:
        return ast.Call(ast.Name('sum'), [stack[0]], [])
def sort_uniq(stack):
    return ast.Call(ast.Name('sorted'),
                    [ast.Call(ast.Name('set'),
                              [ast.Call(ast.Name('sum'), [stack[0]], [ast.keyword('start', ast.List([]))])], [])], [])
def remove(stack):
    return ast.ListComp(ast.Name('i_'),
                        [ast.comprehension(ast.Name('i_', ast.Store()), stack[0],
                                           [ast.Compare(ast.Name('i_'), [ast.NotEq()], [stack[2]])], 0)])

japanese_outer_commands = {
    'で割り切れる': divisible,
    'と等しい': equals,
    'と等しくない': not_equals,
    'より大きい': greater,
    'より小さい': less,
    '以上': greater_equal,
    '以下': less_equal,
    'ずつ増やす': upto,
    'ずつ減らす': downto,
    '未定義ではない': is_not_none,
    '未定義': is_none,
    'の要素の和': sum_,
    '重複なく辞書順に格納した配列': sort_uniq,
    '要素を除いた配列': remove,
}

def compare(s):
    left = bit_or(s)
    os, cs = [], []
    while o := accept(s, '', '', '', '', '', ''):
        os.append({'': ast.Eq, '': ast.NotEq, '': ast.Lt, '': ast.LtE, '': ast.Gt, '': ast.GtE}[o]())
        cs.append(bit_or(s))
    if os:
        return ast.Compare(left, os, cs)
    else:
        return left

def bit_or(s):
    ret = bit_and(s)
    while accept(s, ''):
        ret = ast.BinOp(ret, ast.BitOr(), bit_and(s))
    return ret

def bit_and(s):
    ret = shift(s)
    while accept(s, ''):
        ret = ast.BinOp(ret, ast.BitAnd(), shift(s))
    return ret

def shift(s):
    ret = expression(s)
    while o := accept(s, '>>', '<<'):
        ret = ast.BinOp(ret, {'>>': ast.RShift, '<<': ast.LShift}[o](), expression(s))
    return ret

def expression(s):
    ret = term(s)
    while o := accept(s, '', ''):
        ret = ast.BinOp(ret, {'': ast.Add, '': ast.Sub}[o](), term(s))
    return ret

def term(s):
    ret = japanese_inner(s)
    while o := accept(s, 'mod', '×', '÷'):
        rhs = japanese_inner(s)
        if o == 'mod':
            ret = ast.BinOp(ret, ast.Mod(), rhs)
        elif o == '×':
            ret = ast.BinOp(ret, ast.Mult(), rhs)
        elif accept(s, 'の商'):
            ret = ast.BinOp(ret, ast.FloorDiv(), rhs)
        elif accept(s, 'の余り'):
            ret = ast.BinOp(ret, ast.Mod(), rhs)
        else:
            ret = ast.BinOp(ret, ast.Div(), rhs)
    return ret

def japanese_inner(s):
    stack = [unaryop(s)]
    if not (isinstance(s.peek(), Japanese) and s.peek().id in japanese_inner_tokens):
        return stack[0]
    while True:
        if not (j := accept_t(s, Japanese)):
            stack.append(unaryop(s))
        elif j.id in japanese_inner_commands:
            stack = [japanese_inner_commands[j.id](stack)]
            if not (isinstance(s.peek(), Japanese) and s.peek().id in japanese_inner_tokens):
                return stack[0]
        else:
            stack.append(j)

def array2d(stack):
    return ast.Subscript(ast.Name('list'), ast.Subscript(ast.Name('list'), stack[0]))
def array(stack):
    return ast.Subscript(ast.Name('list'), stack[0])
def length(stack):
    return ast.Call(ast.Name('len'), [stack[0]], [])
def length_col(stack):
    return ast.Call(ast.Name('len'), [ast.Subscript(stack[0], ast.Constant(0))], [])
def ceil(stack):
    global_imports.add('math')
    return ast.Call(ast.Attribute(ast.Name('math'), 'ceil'), [stack[0]], [])
def floor(stack):
    global_imports.add('math')
    return ast.Call(ast.Attribute(ast.Name('math'), 'floor'), [stack[0]], [])
def bit_type(_):
    return ast.Name('int')
def sqrt(stack):
    global_imports.add('math')
    return ast.Call(ast.Attribute(ast.Name('math'), 'sqrt'), [stack[0]], [])
def spow(stack):
    return ast.BinOp(stack[0], ast.Pow(), stack[2])
def const(stack):
    return stack[0]
def subscript(stack):
    if stack[1] == Japanese('の末尾から'):
        return ast.Subscript(stack[0], ast.UnaryOp(ast.USub(), stack[2]))
    else:
        return ast.Subscript(stack[0], ast.BinOp(stack[2], ast.Sub(), ast.Constant(1)))
def int_(stack):
    return ast.Call(ast.Name('int'), [stack[0]], [])

japanese_inner_commands = {
    'の二次元配列': array2d,
    'の配列': array,
    'の要素数': length,
    'の列数': length_col,
    'の小数点以下を切り上げた値': ceil,
    'の小数点以下を切り捨てた値': floor,
    'ビット型': bit_type,
    'の正の平方根': sqrt,
    '': spow,
    '文字だけから成る文字列': const,
    '文字目の文字': subscript,
    'を整数型に変換した値': int_,
}

japanese_inner_tokens = {'', 'の末尾から'}.union(japanese_inner_commands)

def unaryop(s):
    stack = []
    while o := accept(s, 'not', '', ''):
        stack.append({'not': ast.Not, '': ast.UAdd, '': ast.USub}[o]())
    ret = factor(s)
    while True:
        if accept(s, '.'):
            ret = ast.Attribute(ret, expect_t(s, Ident).id)
        elif accept(s, '('):
            ret = ast.Call(ret, comma_separated(s, ')', bool_or), [])
        elif accept(s, '['):
            for i in comma_separated(s, ']', bool_or):
                ret = ast.Subscript(ret, ast.BinOp(i, ast.Sub(), ast.Constant(1)))
        else:
            break
    for s in stack[::-1]:
        ret = ast.UnaryOp(s, ret)
    return ret

def comma_separated(s, end, func):
    if accept(s, end):
        return []
    ret = [func(s)]
    while accept(s, ','):
        ret.append(func(s))
    expect(s, end)
    return ret

def factor(s):
    if i := accept_t(s, Ident):
        return ast.Name(i.id)
    elif (n := accept_t(s, int)) is not None:
        return ast.Constant(n)
    elif (f := accept_t(s, float)) is not None:
        return ast.Constant(f)
    elif string := accept_t(s, String):
        return ast.Constant(string.val)
    elif accept(s, '('):
        ret, _ = bool_or(s), expect(s, ')')
        return ret
    elif accept(s, '{'):
        if accept(s, '}'):
            return ast.List([])
        elts = [bool_or(s)]
        if accept(s, '個の'):
            v, _ = bool_or(s), expect(s, '}')
            return ast.BinOp(ast.List([v]), ast.Mult(), elts[0])
        elif accept(s, ''):
            n, _, v, _ = bool_or(s), expect(s, '列の'), bool_or(s), expect(s, '}')
            return ast.ListComp(ast.BinOp(ast.List([v]), ast.Mult(), n),
                                [ast.comprehension(ast.Name('_', ast.Store()), ast.Call(ast.Name('range'), [elts[0]], []), [], 0)])
        while accept(s, ','):
            elts.append(bool_or(s))
        expect(s, '}')
        return ast.List(elts)
    elif accept(s, '未定義の値'):
        return ast.Constant(None)
    elif accept(s, 'true'):
        return ast.Constant(True)
    elif accept(s, 'false'):
        return ast.Constant(False)
    elif accept(s, ''):
        global_imports.add('math')
        return ast.Attribute(ast.Name('math'), 'inf')
    else:
        raise SyntaxError(s.peek())

def accept_t(s, t):
    if isinstance(s.peek(), t):
        return next(s)
    return None

def expect_t(s, t):
    if (a := accept_t(s, t)) is not None:
        return a
    raise SyntaxError(s.peek())

def accept(s, *ss):
    if s.peek() in ss:
        return next(s)
    return None

def expect(s, *ss):
    if a := accept(s, *ss):
        return a
    raise SyntaxError(s.peek())

def scan(text):
    space = re.compile(r'(?:\s|/\*.*?\*/|//[^\r\n]*)*', re.DOTALL)
    pattern = re.compile(r'''
        ((?:if|elseif|else|endif|while|endwhile|do|for|endfor|not|mod|and|or|true|false|return)\b|
            [][().{}+-×÷≠≦≧<=>∧∨∞○←,@&|=*/+-]|>[>=]?|<[<=]?|!=|:=?)|
        ([0-9]+(?:\.[0-9]*)?)|
        "([^"]*)"|
        ([\u3005\u4E00-\u9FCFぁ-んァ-ヶー\u2460-\u24FF\u2776-\u277F\u3251-\u32BF]+)|
        ((?:(?![\u3005\u4E00-\u9FCFぁ-んァ-ヶー\u2460-\u24FF\u2776-\u277F\u3251-\u32BF])\w)+)''', re.VERBOSE)
    re_japanese_tokens = re.compile('|'.join(f'({t})' for t, _ in japanese_tokens))
    pos, func_def = space.match(text).end(), False
    while pos < len(text):
        m = pattern.match(text, pos)
        if not m:
            raise SyntaxError(text[pos:pos+10])
        pos = m.end()
        if m[1]:
            v = convert_token[m[1]] if m[1] in convert_token else m[1]
            if v == '':
                func_def = True
            yield v
        elif m[2]:
            if '.' in m[2]:
                yield float(m[2])
            else:
                yield int(m[2])
        elif m[4]:
            for mm in re_japanese_tokens.finditer(m[4]):
                i = [p[1][1] for p in zip(mm.groups(), japanese_tokens) if p[0]][0]
                if i is ...:
                    yield Japanese(mm[0])
                elif i is not None:
                    yield i
        elif m[5]:
            i = m[5]
            if i in python_keywords:
                i += '_'
            yield Ident(i)
        else:
            yield String(m[3])
        m = space.match(text, pos)
        if func_def and m[0] and m[0][-1] in '\r\n':
            func_def = False
            yield 'ENDDEF'
        pos = m.end()
    if func_def:
        yield "ENDDEF"
    yield 'EOF'

@dataclass
class Ident:
    id: str

@dataclass
class String:
    val: str

@dataclass
class Japanese:
    id: str

convert_token = {
    '@': '',
    ':=': '',
    '+': '',
    '-': '',
    '*': '×',
    '/': '÷',
    '=': '',
    '!=': '',
    '<': '',
    '>': '',
    '<=': '',
    '>=': '',
    '&': '',
    '|': '',
}

japanese_tokens = (
    ('重複なく辞書順に格納した配列', ...),
    ('の小数点以下を切り上げた値', ...),
    ('の小数点以下を切り捨てた値', ...),
    ('文字だけから成る文字列', ...),
    ('のいずれかの要素の値が', ...),
    ('を整数型に変換した値', ...),
    ('の要素を順に代入する', None),
    ('に含まれる文字列を', ...),
    ('繰返し処理を終了', ...),
    ('を超えない範囲で', ...),
    ('要素を除いた配列', ...),
    ('の値を入れ替え', ...),
    ('未定義ではない', ...),
    ('の行から始まる', ...),
    ('要素番号の順に', Japanese('先頭から順に')),
    ('コンマ区切りで', ...),
    ('の複製から値が', ...),
    ('で割り切れる', ...),
    ('と等しくない', ...),
    ('の二次元配列', ...),
    ('の正の平方根', ...),
    ('文字目の文字', ...),
    ('の全ての要素', ...),
    ('の全要素の値', Japanese('の全ての要素')),
    ('空白区切りで', ...),
    ('先頭から順に', ...),
    ('ずつ増やす', ...),
    ('ずつ減らす', ...),
    ('より大きい', ...),
    ('より小さい', ...),
    ('未定義の値', '未定義の値'),
    ('の整数部分', Japanese('を整数型に変換した値')),
    ('から始めて', ...),
    ('番目の文字', Japanese('文字目の文字')),
    ('の末尾から', ...),
    ('の要素の和', ...),
    ('と等しい', ...),
    ('文字列型', Ident('str')),
    ('の要素数', ...),
    ('の文字数', Japanese('の要素数')),
    ('ビット型', ...),
    ('の戻り値', None),
    ('この順に', Japanese('先頭から順に')),
    ('の行番号', ...),
    ('の列番号', ...),
    ('文字型', Ident('str')),
    ('整数型', Ident('int')),
    ('実数型', Ident('float')),
    ('論理型', Ident('bool')),
    ('の余り', 'の余り'),
    ('の行数', Japanese('の要素数')),
    ('の列数', ...),
    ('の末尾', ...),
    ('の結果', None),
    ('未定義', ...),
    ('でない', Japanese('と等しくない')),
    ('の配列', ...),
    ('を追加', ...),
    ('増やす', ...),
    ('出力', ...),
    ('以上', ...),
    ('以下', ...),
    ('の商', 'の商'),
    ('の値', None),
    ('大域', '大域'),
    ('から', ...),
    ('まで', ...),
    ('配列', Japanese('の配列')),
    ('個の', '個の'),
    ('列の', '列の'),
    ('', ...),
    ('', ...),
    ('', ...),
    ('', ...),
    ('', ...),
    ('', ...),
    ('', ''),
)

python_keywords = {
    'False', 'await', 'else', 'import', 'pass',
    'None', 'break', 'except', 'in', 'raise',
    'True', 'class', 'finally', 'is', 'return',
    'and', 'continue', 'for', 'lambda', 'try',
    'as', 'def', 'from', 'nonlocal', 'while',
    'assert', 'del', 'global', 'not', 'with',
    'async', 'elif', 'if', 'or', 'yield',
}

argparser = argparse.ArgumentParser()
argparser.add_argument('infile', nargs='?', default=None)
argparser.add_argument('-o', '--outfile')
argparser.add_argument('-e', '--execute', action='store_true')
args = argparser.parse_args()
if args.infile:
    with open(args.infile) as f:
        text = f.read()
else:
    text = sys.stdin.read()
if args.execute:
    exec(ast.unparse(parse(scan(text))), globals={})
elif args.outfile:
    with open(args.outfile, 'w') as f:
        f.write(ast.unparse(parse(scan(text))))
else:
    print(ast.unparse(parse(scan(text))))
0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?