Skip to content

Commit 0adc14a

Browse files
committed
Fix grammar for multiple entry points for compile mode
1 parent c2c5db0 commit 0adc14a

File tree

4 files changed

+173
-60
lines changed

4 files changed

+173
-60
lines changed

‎ast/ast.go‎

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
package ast
22

3+
// FIXME make base AstNode with position in
4+
// also keep a list of children in the parent node to simplify walking the tree?
5+
36
import (
47
"fmt"
58

‎parser/grammar.y‎

Lines changed: 50 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -12,21 +12,21 @@ import (
1212
%}
1313

1414
%union{
15-
strstring
16-
objpy.Object
17-
astast.Ast
18-
modast.Mod
19-
stmtast.Stmt
20-
stmts[]ast.Stmt
21-
stmts1[]ast.Stmt// nl_or_stmt accumulator
22-
stmts2[]ast.Stmt// small_stmts accumulator
23-
stmts3[]ast.Stmt// stmts accumulator
24-
posast.Pos// kept up to date by the lexer
15+
strstring
16+
objpy.Object
17+
astast.Ast
18+
modast.Mod
19+
stmtast.Stmt
20+
stmts[]ast.Stmt
21+
stmts1[]ast.Stmt// nl_or_stmt accumulator
22+
stmts2[]ast.Stmt// small_stmts accumulator
23+
stmts3[]ast.Stmt// stmts accumulator
24+
posast.Pos// kept up to date by the lexer
2525
}
2626

2727
%type<str>strings
2828
%type<ast>atom
29-
%type<mod>inputsfile_input
29+
%type<mod>inputsfile_inputsingle_inputeval_input
3030
%type<stmts>simple_stmtstmt
3131
%type<stmts1>nl_or_stmt
3232
%type<stmts2>small_stmts
@@ -101,6 +101,8 @@ import (
101101

102102
%token'('')''['']'':'','';''+''-''*''/''|''&''<''>''=''.''%''{''}''^''~''@'
103103

104+
%tokenSINGLE_INPUTFILE_INPUTEVAL_INPUT
105+
104106
// Note: Changing the grammar specified in this file will most likely
105107
// require corresponding changes in the parser module
106108
// (../Modules/parsermodule.c). If you can't make the changes to
@@ -119,18 +121,45 @@ import (
119121

120122
%%
121123

122-
// FIXME figure out how to tell the parser to start from a given node
123-
// inputs: single_input | file_input | eval_input
124-
// In the mean time just do file_input
125-
// inputs: single_input | file_input | eval_input
124+
// Start of grammar. This has 3 pseudo tokens which say which
125+
// direction through the rest of the grammar we take.
126126
inputs:
127-
file_input
127+
SINGLE_INPUTsingle_input
128+
{
129+
yylex.(*yyLex).mod = $2
130+
return0
131+
}
132+
|FILE_INPUTfile_input
133+
{
134+
yylex.(*yyLex).mod = $2
135+
return0
136+
}
137+
|EVAL_INPUTeval_input
128138
{
129-
yylex.(*yyLex).mod = $1
139+
yylex.(*yyLex).mod = $2
130140
return0
131141
}
132142

133-
single_input: NEWLINE|simple_stmt|compound_stmtNEWLINE
143+
single_input:
144+
NEWLINE
145+
{
146+
$$ = &ast.Interactive{ModBase: ast.ModBase{$<pos>$}}
147+
}
148+
|simple_stmt
149+
{
150+
$$ = &ast.Interactive{ModBase: ast.ModBase{$<pos>$}, Body: $1}
151+
}
152+
|compound_stmtNEWLINE
153+
{
154+
$$ = &ast.Interactive{ModBase: ast.ModBase{$<pos>$}, Body: []ast.Stmt{$1}}
155+
}
156+
157+
//file_input: (NEWLINE|stmt)* ENDMARKER
158+
file_input:
159+
nl_or_stmtENDMARKER
160+
{
161+
$$ = &ast.Module{ModBase: ast.ModBase{$<pos>$}, Body: $1}
162+
}
134163

135164
// (NEWLINE|stmt)*
136165
nl_or_stmt:
@@ -145,19 +174,15 @@ nl_or_stmt:
145174
$$ = append($$, $2...)
146175
}
147176

148-
//file_input: (NEWLINE|stmt)* ENDMARKER
149-
file_input:
150-
nl_or_stmtENDMARKER
177+
//eval_input: testlistNEWLINE* ENDMARKER
178+
eval_input:
179+
testlistnlsENDMARKER
151180
{
152-
$$ = &ast.Module{ModBase: ast.ModBase{$<pos>$}, Body: $1}
153181
}
154182

155183
// NEWLINE*
156184
nls: |nlsNEWLINE
157185

158-
//eval_input: testlistNEWLINE* ENDMARKER
159-
eval_input: testlistnlsENDMARKER
160-
161186
optional_arglist: |arglist
162187

163188
optional_arglist_call: |'('optional_arglist')'

‎parser/lexer.go‎

Lines changed: 50 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -46,15 +46,33 @@ type yyLex struct{
4646
parenthesisint// number of open ( )
4747
braceint// number of open{}
4848
mod ast.Mod// output
49+
startTokenint// initial token to output
4950
}
5051

51-
funcNewLex(r io.Reader) *yyLex{
52+
// Create a new lexer
53+
//
54+
// The mode argument specifies what kind of code must be compiled; it
55+
// can be 'exec' if source consists of a sequence of statements,
56+
// 'eval' if it consists of a single expression, or 'single' if it
57+
// consists of a single interactive statement
58+
funcNewLex(r io.Reader, modestring) (*yyLex, error){
5259
x:=&yyLex{
5360
reader: bufio.NewReader(r),
5461
indentStack: []int{0},
5562
state: readString,
5663
}
57-
returnx
64+
switchmode{
65+
case"exec":
66+
x.startToken=FILE_INPUT
67+
case"eval":
68+
x.startToken=EVAL_INPUT
69+
case"single":
70+
x.startToken=SINGLE_INPUT
71+
x.interactive=true
72+
default:
73+
returnnil, py.ExceptionNewf(py.ValueError, "compile mode must be 'exec', 'eval' or 'single'")
74+
}
75+
returnx, nil
5876
}
5977

6078
// Refill line
@@ -222,6 +240,9 @@ func init(){
222240
tokenToString[DEDENT] ="DEDENT"
223241
tokenToString[STRING] ="STRING"
224242
tokenToString[NUMBER] ="NUMBER"
243+
tokenToString[FILE_INPUT] ="FILE_INPUT"
244+
tokenToString[SINGLE_INPUT] ="SINGLE_INPUT"
245+
tokenToString[EVAL_INPUT] ="EVAL_INPUT"
225246
}
226247

227248
// True if there are any open brackets
@@ -309,6 +330,13 @@ func (x *yyLex) Lex(yylval *yySymType) (ret int){
309330
deferfunc(){fmt.Printf("LEX> %v\n", newLexToken(ret, yylval)) }()
310331
}
311332

333+
// Return initial token
334+
ifx.startToken!=eof{
335+
token:=x.startToken
336+
x.startToken=eof
337+
returntoken
338+
}
339+
312340
// FIXME keep x.pos up to date
313341
x.pos.Lineno=42
314342
x.pos.ColOffset=43
@@ -318,13 +346,14 @@ func (x *yyLex) Lex(yylval *yySymType) (ret int){
318346
// Read x.line
319347
x.refill()
320348
x.state++
321-
// an empty line while reading interactive input should return a NEWLINE
322-
ifx.interactive&& (x.line==""||x.line=="\n"){
349+
ifx.line==""&&x.eof{
350+
x.state=checkEof
351+
// an empty line while reading interactive input should return a NEWLINE
323352
// Don't output NEWLINE if brackets are open
324-
ifx.openBrackets(){
325-
continue
353+
ifx.interactive&&!x.openBrackets(){
354+
returnNEWLINE
326355
}
327-
returnNEWLINE
356+
continue
328357
}
329358
casereadIndent:
330359
// Read the initial indent and get rid of it
@@ -799,20 +828,26 @@ func SetDebug(level int){
799828
}
800829

801830
// Parse a file
802-
funcParse(in io.Reader) (ast.Mod, error){
803-
lex:=NewLex(in)
831+
funcParse(in io.Reader, modestring) (ast.Mod, error){
832+
lex, err:=NewLex(in, mode)
833+
iferr!=nil{
834+
returnnil, err
835+
}
804836
yyParse(lex)
805837
returnlex.mod, lex.ErrorReturn()
806838
}
807839

808840
// Parse a string
809-
funcParseString(instring) (ast.Ast, error){
810-
returnParse(bytes.NewBufferString(in))
841+
funcParseString(instring, modestring) (ast.Ast, error){
842+
returnParse(bytes.NewBufferString(in), mode)
811843
}
812844

813845
// Lex a file only, returning a sequence of tokens
814-
funcLex(in io.Reader) (ltsLexTokens, errerror){
815-
lex:=NewLex(in)
846+
funcLex(in io.Reader, modestring) (ltsLexTokens, errerror){
847+
lex, err:=NewLex(in, mode)
848+
iferr!=nil{
849+
returnnil, err
850+
}
816851
yylval:=yySymType{}
817852
for{
818853
ret:=lex.Lex(&yylval)
@@ -827,6 +862,6 @@ func Lex(in io.Reader) (lts LexTokens, err error){
827862
}
828863

829864
// Lex a string
830-
funcLexString(instring) (ltsLexTokens, errerror){
831-
returnLex(bytes.NewBufferString(in))
865+
funcLexString(instring, modestring) (ltsLexTokens, errerror){
866+
returnLex(bytes.NewBufferString(in), mode)
832867
}

0 commit comments

Comments
(0)