Some instruction selection is now happening.
This commit is contained in:
parent
c8fcbe282a
commit
629e0ddfc6
|
@ -33,7 +33,11 @@ struct ir
|
||||||
const char* lvalue;
|
const char* lvalue;
|
||||||
struct basicblock* bvalue;
|
struct basicblock* bvalue;
|
||||||
} u;
|
} u;
|
||||||
|
|
||||||
|
void* state_label; /* used by the iburg instruction selector */
|
||||||
|
|
||||||
bool is_sequence : 1;
|
bool is_sequence : 1;
|
||||||
|
bool is_generated : 1;
|
||||||
};
|
};
|
||||||
|
|
||||||
extern const char* ir_names[];
|
extern const char* ir_names[];
|
||||||
|
|
|
@ -37,9 +37,10 @@ bool tracing(char k)
|
||||||
{
|
{
|
||||||
switch (k)
|
switch (k)
|
||||||
{
|
{
|
||||||
|
case 0: return true;
|
||||||
case 'E': return false;
|
case 'E': return false;
|
||||||
case '0': return false;
|
case '0': return false;
|
||||||
case '1': return true;
|
case '1': return false;
|
||||||
case '2': return true;
|
case '2': return true;
|
||||||
default: return true;
|
default: return true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -119,6 +119,7 @@ extern void tb_regvar(arith offset, int size, int type, int priority);
|
||||||
extern void pass_convert_stack_ops(struct procedure* proc);
|
extern void pass_convert_stack_ops(struct procedure* proc);
|
||||||
extern void pass_remove_dead_blocks(struct procedure* proc);
|
extern void pass_remove_dead_blocks(struct procedure* proc);
|
||||||
extern void pass_eliminate_trivial_blocks(struct procedure* proc);
|
extern void pass_eliminate_trivial_blocks(struct procedure* proc);
|
||||||
|
extern void pass_instruction_selector(struct procedure* proc);
|
||||||
|
|
||||||
extern void procedure_compile(struct procedure* proc);
|
extern void procedure_compile(struct procedure* proc);
|
||||||
|
|
||||||
|
|
|
@ -19,6 +19,7 @@ static void dumpCover(NODEPTR_TYPE p, int goalnt, int indent) {
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if 0
|
||||||
static NODEPTR_TYPE tree(int op, NODEPTR_TYPE l, NODEPTR_TYPE r) {
|
static NODEPTR_TYPE tree(int op, NODEPTR_TYPE l, NODEPTR_TYPE r) {
|
||||||
NODEPTR_TYPE p = malloc(sizeof *p);
|
NODEPTR_TYPE p = malloc(sizeof *p);
|
||||||
|
|
||||||
|
@ -48,4 +49,5 @@ int main(void) {
|
||||||
dumpCover(p, 1, 0);
|
dumpCover(p, 1, 0);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
|
@ -1,32 +1,20 @@
|
||||||
#include <stdio.h>
|
#include "mcg.h"
|
||||||
#include <assert.h>
|
#include "mcgg.h"
|
||||||
#include <stdlib.h>
|
|
||||||
#include <stdbool.h>
|
|
||||||
#include <limits.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
|
|
||||||
#define TRACE
|
|
||||||
|
|
||||||
#define STATE_TYPE void*
|
|
||||||
typedef struct tree {
|
|
||||||
int op;
|
|
||||||
struct tree *kids[2];
|
|
||||||
STATE_TYPE state_label;
|
|
||||||
} *NODEPTR_TYPE;
|
|
||||||
#define OP_LABEL(p) ((p)->op)
|
|
||||||
#define LEFT_CHILD(p) ((p)->kids[0])
|
|
||||||
#define RIGHT_CHILD(p) ((p)->kids[1])
|
|
||||||
#define STATE_LABEL(p) ((p)->state_label)
|
|
||||||
#define PANIC printf
|
#define PANIC printf
|
||||||
|
|
||||||
static void burm_trace(NODEPTR_TYPE p, int eruleno, int cost, int bestcost) {
|
static int OP_LABEL(struct ir* ir)
|
||||||
#ifdef TRACE
|
{
|
||||||
extern const char *burm_string[];
|
if (ir->is_generated)
|
||||||
|
return ir_to_esn(IR_REG, ir->size);
|
||||||
fprintf(stderr, "0x%p matched %s with cost %d vs. %d\n", p,
|
return ir_to_esn(ir->opcode, ir->size);
|
||||||
burm_string[eruleno], cost, bestcost);
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#define burm_assert(b, s) assert(b && s)
|
#define LEFT_CHILD(p) ((p)->left)
|
||||||
|
#define RIGHT_CHILD(p) ((p)->right)
|
||||||
|
|
||||||
|
#define burm_assert(b, s) assert(b)
|
||||||
|
|
||||||
|
extern void burm_panic_cannot_match(struct ir* ir);
|
||||||
|
|
||||||
|
|
87
mach/proto/mcg/pass_instsel.c
Normal file
87
mach/proto/mcg/pass_instsel.c
Normal file
|
@ -0,0 +1,87 @@
|
||||||
|
#include "mcg.h"
|
||||||
|
#include "mcgg.h"
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
static void dumpCover(NODEPTR_TYPE p, int goalnt, int indent) {
|
||||||
|
#ifdef TRACE
|
||||||
|
int eruleno = burm_rule(STATE_LABEL(p), goalnt);
|
||||||
|
const short *nts = burm_nts[eruleno];
|
||||||
|
NODEPTR_TYPE kids[10];
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; i < indent; i++)
|
||||||
|
fprintf(stderr, " ");
|
||||||
|
fprintf(stderr, "%s\n", burm_string[eruleno]);
|
||||||
|
burm_kids(p, eruleno, kids);
|
||||||
|
for (i = 0; nts[i]; i++)
|
||||||
|
{
|
||||||
|
if (kids[i])
|
||||||
|
dumpCover(kids[i], nts[i], indent + 1);
|
||||||
|
else
|
||||||
|
fprintf(stderr, "failed!\n");
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
void burm_trace(struct ir* p, int ruleno, int cost, int bestcost) {
|
||||||
|
tracef('I', "I: 0x%p matched %s with cost %d vs. %d\n", p,
|
||||||
|
burm_string[ruleno], cost, bestcost);
|
||||||
|
}
|
||||||
|
|
||||||
|
void burm_panic_cannot_match(struct ir* ir)
|
||||||
|
{
|
||||||
|
fprintf(stderr, "could not find any patterns to match:\n");
|
||||||
|
ir_print(0, ir);
|
||||||
|
fprintf(stderr, "aborting!\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void queue_instructions(struct ir* ir, int goal)
|
||||||
|
{
|
||||||
|
struct ir* children[10];
|
||||||
|
int ruleno = burm_rule(ir->state_label, goal);
|
||||||
|
const short* nts = burm_nts[ruleno];
|
||||||
|
int i;
|
||||||
|
|
||||||
|
burm_kids(ir, ruleno, children);
|
||||||
|
for (i=0; nts[i]; i++)
|
||||||
|
queue_instructions(children[i], nts[i]);
|
||||||
|
|
||||||
|
printf("selected insn %d: %s\n", ruleno, burm_string[ruleno]);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void select_instructions(struct basicblock* bb)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
tracef('I', "I: BLOCK: %s\n", bb->name);
|
||||||
|
|
||||||
|
for (i=0; i<bb->irs_count; i++)
|
||||||
|
{
|
||||||
|
int insnno;
|
||||||
|
struct ir* ir = bb->irs[i];
|
||||||
|
burm_label(ir);
|
||||||
|
|
||||||
|
insnno = burm_rule(ir->state_label, 1);
|
||||||
|
if (!insnno)
|
||||||
|
burm_panic_cannot_match(ir);
|
||||||
|
|
||||||
|
queue_instructions(ir, 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void pass_instruction_selector(struct procedure* proc)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i=0; i<proc->blocks_count; i++)
|
||||||
|
{
|
||||||
|
struct basicblock* bb = proc->blocks[i];
|
||||||
|
select_instructions(bb);
|
||||||
|
}
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* vim: set sw=4 ts=4 expandtab : */
|
||||||
|
|
|
@ -31,6 +31,8 @@ void procedure_compile(struct procedure* proc)
|
||||||
pass_convert_stack_ops(proc);
|
pass_convert_stack_ops(proc);
|
||||||
|
|
||||||
print_blocks('2', proc);
|
print_blocks('2', proc);
|
||||||
|
|
||||||
|
pass_instruction_selector(proc);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* vim: set sw=4 ts=4 expandtab : */
|
/* vim: set sw=4 ts=4 expandtab : */
|
||||||
|
|
|
@ -1,5 +1,33 @@
|
||||||
PATTERNS
|
PATTERNS
|
||||||
|
|
||||||
|
/* Special */
|
||||||
|
|
||||||
|
reg;
|
||||||
|
|
||||||
|
PAIR(BLOCK4, BLOCK4);
|
||||||
|
|
||||||
|
|
||||||
|
/* Miscellaneous special things */
|
||||||
|
|
||||||
|
PUSH4(in:reg)
|
||||||
|
emit "push %in"
|
||||||
|
cost 4;
|
||||||
|
|
||||||
|
reg = POP4
|
||||||
|
outs out:ANY
|
||||||
|
emit "pop %out"
|
||||||
|
cost 4;
|
||||||
|
|
||||||
|
RET
|
||||||
|
emit "ret"
|
||||||
|
cost 4;
|
||||||
|
|
||||||
|
SETRET4(in:reg)
|
||||||
|
emit "mov r0, %in"
|
||||||
|
cost 4;
|
||||||
|
|
||||||
|
/* Memory operations */
|
||||||
|
|
||||||
STORE4(addr:address, value:reg)
|
STORE4(addr:address, value:reg)
|
||||||
ins value:GPR
|
ins value:GPR
|
||||||
emit "str %value, %addr"
|
emit "str %value, %addr"
|
||||||
|
@ -7,9 +35,33 @@ PATTERNS
|
||||||
|
|
||||||
reg = LOAD4(addr:address)
|
reg = LOAD4(addr:address)
|
||||||
outs dest:ANY
|
outs dest:ANY
|
||||||
emit "ld %dest, %addr"
|
emit "ldr %dest, %addr"
|
||||||
cost 4;
|
cost 4;
|
||||||
|
|
||||||
|
reg = LOAD1(addr:address)
|
||||||
|
outs dest:ANY
|
||||||
|
emit "ldrb %dest, %addr"
|
||||||
|
cost 4;
|
||||||
|
|
||||||
|
reg = CIU14(LOAD1(addr:address))
|
||||||
|
outs dest:ANY
|
||||||
|
emit "ldrb %dest, %addr"
|
||||||
|
cost 4;
|
||||||
|
|
||||||
|
|
||||||
|
/* Locals */
|
||||||
|
|
||||||
|
reg = in:LOCAL4
|
||||||
|
outs out:GPR
|
||||||
|
emit "add %out, fp, #%in.ivalue"
|
||||||
|
cost 4;
|
||||||
|
|
||||||
|
address = in:LOCAL4
|
||||||
|
fragment "[fp, #%in.ivalue]";
|
||||||
|
|
||||||
|
|
||||||
|
/* Memory addressing modes */
|
||||||
|
|
||||||
address = ADD4(addr:reg, offset:CONST)
|
address = ADD4(addr:reg, offset:CONST)
|
||||||
ins addr:GPR
|
ins addr:GPR
|
||||||
fragment "[%addr, #%offset.ivalue]";
|
fragment "[%addr, #%offset.ivalue]";
|
||||||
|
@ -18,7 +70,47 @@ PATTERNS
|
||||||
ins addr:GPR
|
ins addr:GPR
|
||||||
fragment "[%addr]";
|
fragment "[%addr]";
|
||||||
|
|
||||||
reg;
|
|
||||||
|
/* Branches */
|
||||||
|
|
||||||
|
JUMP(addr:BLOCK4)
|
||||||
|
emit "b %addr.bvalue"
|
||||||
|
cost 4;
|
||||||
|
|
||||||
|
CJUMPEQ(value:tristate, PAIR(true:BLOCK4, false:BLOCK4))
|
||||||
|
emit "beq %trueblock.bvalue"
|
||||||
|
emit "bne %falseblock.bvalue"
|
||||||
|
cost 8;
|
||||||
|
|
||||||
|
|
||||||
|
/* Comparisons */
|
||||||
|
|
||||||
|
tristate = COMPARES4(val1:reg, val2:aluparam)
|
||||||
|
outs CC
|
||||||
|
emit "cmp %val1, %val2"
|
||||||
|
cost 4;
|
||||||
|
|
||||||
|
reg = tristate
|
||||||
|
emit "mov %out, #0"
|
||||||
|
emit "movlt %out, #-1"
|
||||||
|
emit "movgt %out, #1"
|
||||||
|
cost 12;
|
||||||
|
|
||||||
|
|
||||||
|
/* Conversions */
|
||||||
|
|
||||||
|
reg = CII14(CIU41(value:reg))
|
||||||
|
outs out:GPR
|
||||||
|
emit "sxtb %out, %value"
|
||||||
|
cost 4;
|
||||||
|
|
||||||
|
reg = CIU41(in:reg)
|
||||||
|
outs out:GPR
|
||||||
|
emit "and %out, %in, #0xff"
|
||||||
|
cost 4;
|
||||||
|
|
||||||
|
|
||||||
|
/* ALU operations */
|
||||||
|
|
||||||
reg = ADD4(left:reg, right:aluparam)
|
reg = ADD4(left:reg, right:aluparam)
|
||||||
ins left:GPR, right:GPR
|
ins left:GPR, right:GPR
|
||||||
|
@ -33,7 +125,6 @@ PATTERNS
|
||||||
cost 4;
|
cost 4;
|
||||||
|
|
||||||
aluparam = value:CONST4
|
aluparam = value:CONST4
|
||||||
when { return false; }
|
|
||||||
fragment "#%value.ivalue";
|
fragment "#%value.ivalue";
|
||||||
|
|
||||||
aluparam = reg;
|
aluparam = reg;
|
||||||
|
@ -45,7 +136,12 @@ PATTERNS
|
||||||
|
|
||||||
reg = value:LABEL4
|
reg = value:LABEL4
|
||||||
outs out:GPR
|
outs out:GPR
|
||||||
emit "adr %out, #value.lvalue"
|
emit "adr %out, %value.lvalue"
|
||||||
|
cost 4;
|
||||||
|
|
||||||
|
reg = value:BLOCK4
|
||||||
|
outs out:GPR
|
||||||
|
emit "adr %out, %value.bvalue"
|
||||||
cost 4;
|
cost 4;
|
||||||
|
|
||||||
reg = value:CONST4
|
reg = value:CONST4
|
||||||
|
|
|
@ -231,9 +231,9 @@ static void simple_branch2(int opcode, int size,
|
||||||
materialise_stack();
|
materialise_stack();
|
||||||
appendir(
|
appendir(
|
||||||
new_ir2(
|
new_ir2(
|
||||||
IR_CJUMP, 0,
|
irop, 0,
|
||||||
new_ir2(
|
new_ir2(
|
||||||
irop, size,
|
IR_COMPARES, size,
|
||||||
left, right
|
left, right
|
||||||
),
|
),
|
||||||
new_ir2(
|
new_ir2(
|
||||||
|
@ -260,13 +260,13 @@ static void insn_bvalue(int opcode, struct basicblock* leftbb, struct basicblock
|
||||||
{
|
{
|
||||||
switch (opcode)
|
switch (opcode)
|
||||||
{
|
{
|
||||||
case op_zeq: compare0_branch2(opcode, leftbb, rightbb, IR_IFEQ); break;
|
case op_zeq: compare0_branch2(opcode, leftbb, rightbb, IR_CJUMPEQ); break;
|
||||||
case op_zlt: compare0_branch2(opcode, leftbb, rightbb, IR_IFLT); break;
|
case op_zlt: compare0_branch2(opcode, leftbb, rightbb, IR_CJUMPLT); break;
|
||||||
case op_zle: compare0_branch2(opcode, leftbb, rightbb, IR_IFLE); break;
|
case op_zle: compare0_branch2(opcode, leftbb, rightbb, IR_CJUMPLE); break;
|
||||||
|
|
||||||
case op_zne: compare0_branch2(opcode, rightbb, leftbb, IR_IFEQ); break;
|
case op_zne: compare0_branch2(opcode, rightbb, leftbb, IR_CJUMPEQ); break;
|
||||||
case op_zge: compare0_branch2(opcode, rightbb, leftbb, IR_IFLT); break;
|
case op_zge: compare0_branch2(opcode, rightbb, leftbb, IR_CJUMPLT); break;
|
||||||
case op_zgt: compare0_branch2(opcode, rightbb, leftbb, IR_IFLE); break;
|
case op_zgt: compare0_branch2(opcode, rightbb, leftbb, IR_CJUMPLE); break;
|
||||||
|
|
||||||
case op_bra:
|
case op_bra:
|
||||||
{
|
{
|
||||||
|
|
|
@ -28,7 +28,8 @@ clibrary {
|
||||||
matching(filenamesof("+ircodes"), "%.c$")
|
matching(filenamesof("+ircodes"), "%.c$")
|
||||||
},
|
},
|
||||||
hdrs = {
|
hdrs = {
|
||||||
matching(filenamesof("+ircodes"), "%.h$")
|
matching(filenamesof("+ircodes"), "%.h$"),
|
||||||
|
"./mcgg.h"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -40,7 +41,7 @@ cprogram {
|
||||||
matching(filenamesof("+yacc"), "%.c$")
|
matching(filenamesof("+yacc"), "%.c$")
|
||||||
},
|
},
|
||||||
deps = {
|
deps = {
|
||||||
"./*.h",
|
"./iburg.h",
|
||||||
"+lib",
|
"+lib",
|
||||||
"+yacc"
|
"+yacc"
|
||||||
}
|
}
|
||||||
|
|
|
@ -419,7 +419,7 @@ static void print(char* fmt, ...)
|
||||||
|
|
||||||
void printlineno(void)
|
void printlineno(void)
|
||||||
{
|
{
|
||||||
print("#line %d\n", yylineno);
|
//print("#line %d\n", yylineno);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* reach - mark all non-terminals in tree t as reachable */
|
/* reach - mark all non-terminals in tree t as reachable */
|
||||||
|
@ -451,6 +451,9 @@ static void emitcase(Term p, int ntnumber)
|
||||||
{
|
{
|
||||||
Rule r;
|
Rule r;
|
||||||
|
|
||||||
|
if (!p->rules)
|
||||||
|
return;
|
||||||
|
|
||||||
print("%1case %d: /* %S */\n", p->esn, p);
|
print("%1case %d: /* %S */\n", p->esn, p);
|
||||||
switch (p->arity)
|
switch (p->arity)
|
||||||
{
|
{
|
||||||
|
@ -823,7 +826,8 @@ static void emitstate(Term terms, Nonterm start, int ntnumber)
|
||||||
for (p = terms; p; p = p->link)
|
for (p = terms; p; p = p->link)
|
||||||
emitcase(p, ntnumber);
|
emitcase(p, ntnumber);
|
||||||
print("%1default:\n"
|
print("%1default:\n"
|
||||||
"%2%Passert(0, PANIC(\"Bad operator %%d in %Pstate\\n\", op));\n%1}\n"
|
"%2%Ppanic_cannot_match(node);\n"
|
||||||
|
"%1}\n"
|
||||||
"%1return (STATE_TYPE)p;\n}\n\n");
|
"%1return (STATE_TYPE)p;\n}\n\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -86,15 +86,6 @@ extern int yylineno;
|
||||||
|
|
||||||
extern void printlineno(void);
|
extern void printlineno(void);
|
||||||
|
|
||||||
/* Excruciating macro which packs ir opcodes and sizes into an int for iburg's benefit.
|
#include "mcgg.h"
|
||||||
*
|
|
||||||
* Sizes are mapped as: 0=1, 1=1, 2=2, 4=3, 8=4.
|
|
||||||
*/
|
|
||||||
#define ir_to_esn(iropcode, size) \
|
|
||||||
((iropcode)*4 + \
|
|
||||||
(((size) == 4) ? 2 : \
|
|
||||||
((size) == 8) ? 3 : \
|
|
||||||
((size) == 0) ? 0 : \
|
|
||||||
(size-1)))
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -7,7 +7,7 @@ S CONST
|
||||||
S REG
|
S REG
|
||||||
S LABEL
|
S LABEL
|
||||||
S BLOCK
|
S BLOCK
|
||||||
S PAIR
|
V PAIR
|
||||||
S ANY
|
S ANY
|
||||||
S LOCAL
|
S LOCAL
|
||||||
S PHI
|
S PHI
|
||||||
|
@ -64,7 +64,9 @@ V CALL
|
||||||
|
|
||||||
# Flow control --- these never return
|
# Flow control --- these never return
|
||||||
V JUMP
|
V JUMP
|
||||||
V CJUMP
|
V CJUMPEQ
|
||||||
|
V CJUMPLT
|
||||||
|
V CJUMPLE
|
||||||
V RET
|
V RET
|
||||||
|
|
||||||
# Special
|
# Special
|
||||||
|
|
30
util/mcgg/mcgg.h
Normal file
30
util/mcgg/mcgg.h
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
#ifndef MCGG_H
|
||||||
|
#define MCGG_H
|
||||||
|
|
||||||
|
/* Excruciating macro which packs ir opcodes and sizes into an int for iburg's benefit.
|
||||||
|
*
|
||||||
|
* Sizes are mapped as: 0=1, 1=1, 2=2, 4=3, 8=4.
|
||||||
|
*/
|
||||||
|
#define ir_to_esn(iropcode, size) \
|
||||||
|
((iropcode)*4 + \
|
||||||
|
(((size) == 4) ? 2 : \
|
||||||
|
((size) == 8) ? 3 : \
|
||||||
|
((size) == 0) ? 0 : \
|
||||||
|
(size-1)))
|
||||||
|
|
||||||
|
|
||||||
|
#define STATE_TYPE void*
|
||||||
|
typedef struct ir* NODEPTR_TYPE;
|
||||||
|
|
||||||
|
#define STATE_LABEL(p) ((p)->state_label)
|
||||||
|
|
||||||
|
extern void* burm_label(struct ir* ir);
|
||||||
|
extern int burm_rule(void* state, int goalnt);
|
||||||
|
extern const char* burm_string[];
|
||||||
|
extern const short *burm_nts[];
|
||||||
|
extern struct ir** burm_kids(struct ir* p, int eruleno, struct ir* kids[]);
|
||||||
|
extern void burm_trace(struct ir* p, int ruleno, int cost, int bestcost);
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* vim: set sw=4 ts=4 expandtab : */
|
|
@ -22,7 +22,7 @@ static int braces = 0;
|
||||||
<ECHO>[^%\n]* fputs(yytext, outfp);
|
<ECHO>[^%\n]* fputs(yytext, outfp);
|
||||||
|
|
||||||
<INITIAL>"{" {
|
<INITIAL>"{" {
|
||||||
yylval.string = stringf("#line %d\n", yylineno);
|
yylval.string = ""; //stringf("#line %d\n", yylineno);
|
||||||
braces = 1;
|
braces = 1;
|
||||||
BEGIN(CSTRING);
|
BEGIN(CSTRING);
|
||||||
return CFRAGMENT;
|
return CFRAGMENT;
|
||||||
|
|
Loading…
Reference in a new issue